Change TZ_SYS_HOME to TZ_SYS_USER
[platform/core/system/libstorage.git] / src / storage-external-dbus.c
1 /*
2  * libstorage
3  *
4  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <vconf.h>
23 #include <stdbool.h>
24 #include <errno.h>
25 #include <gio/gio.h>
26 #include <glib.h>
27 #include <assert.h>
28 #include <limits.h>
29 #include <sys/statvfs.h>
30
31 #include "log.h"
32 #include "storage-external-dbus.h"
33
34 #define CHECK_STR(a) (a ? a : "")
35
36 #define STORAGE_EXT_GET_LIST               "GetDeviceList"
37 #define STORAGE_EXT_GET_STATVFS            "GetStatvfs"
38 #define STORAGE_EXT_GET_STORAGE_LEVEL      "GetStorageLevel"
39
40 #define STORAGE_EXT_DEVICE_CHANGED         "DeviceChanged"
41 #define STORAGE_EXT_DEVICE_ADDED           "DeviceAdded"
42 #define STORAGE_EXT_DEVICE_REMOVED         "DeviceRemoved"
43 #define STORAGE_EXT_DEVICE_BLOCKED         "DeviceBlocked"
44
45 #define DBUS_REPLY_TIMEOUT (-1)
46
47 struct storage_ext_callback {
48         storage_ext_changed_cb func;
49         void *data;
50         guint block_id;
51 };
52
53 static dd_list *changed_list;
54
55 static void storage_ext_release_internal(storage_ext_device *dev)
56 {
57         if (!dev)
58                 return;
59         free(dev->devnode);
60         free(dev->syspath);
61         free(dev->fs_usage);
62         free(dev->fs_type);
63         free(dev->fs_version);
64         free(dev->fs_uuid);
65         free(dev->mount_point);
66 }
67
68 void storage_ext_release_device(storage_ext_device **dev)
69 {
70         if (!dev || !*dev)
71                 return;
72         storage_ext_release_internal(*dev);
73         free(*dev);
74         *dev = NULL;
75 }
76
77 void storage_ext_release_list(dd_list **list)
78 {
79         storage_ext_device *dev;
80         dd_list *elem;
81
82         if (*list == NULL)
83                 return;
84
85         DD_LIST_FOREACH(*list, elem, dev) {
86                 storage_ext_release_internal(dev);
87                 free(dev);
88         }
89
90         g_list_free(*list);
91         *list = NULL;
92 }
93
94 static GDBusConnection *get_dbus_connection(void)
95 {
96         GError *err = NULL;
97         static GDBusConnection *conn;
98
99         if (conn)
100                 return conn;
101
102 #if !GLIB_CHECK_VERSION(2, 35, 0)
103         g_type_init();
104 #endif
105
106         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
107         if (!conn) {
108 //LCOV_EXCL_START System Error
109                 if (err) {
110                         _E("fail to get dbus connection : %s", err->message);
111                         g_clear_error(&err);
112                 } else
113                         _E("fail to get dbus connection");
114                 return NULL;
115 //LCOV_EXCL_STOP
116         }
117         return conn;
118 }
119
120 GVariant *dbus_method_call_sync(const gchar *dest, const gchar *path,
121                                 const gchar *iface, const gchar *method, GVariant *param)
122 {
123         GDBusConnection *conn;
124         GError *err = NULL;
125         GVariant *ret;
126
127         if (!dest || !path || !iface || !method)
128                 return NULL;
129
130         conn = get_dbus_connection();
131         if (!conn) {
132                 _E("fail to get dbus connection"); //LCOV_EXCL_LINE
133                 return NULL;
134         }
135
136         ret = g_dbus_connection_call_sync(conn,
137                         dest, path, iface, method,
138                         param, NULL, G_DBUS_CALL_FLAGS_NONE,
139                         -1, NULL, &err);
140         if (!ret) {
141 //LCOV_EXCL_START System Error
142                 if (err) {
143                         _E("dbus method sync call failed(%s)", err->message);
144                         g_clear_error(&err);
145                 } else
146                         _E("g_dbus_connection_call_sync() failed");
147                 return NULL;
148 //LCOV_EXCL_STOP
149         }
150
151         return ret;
152 }
153
154 int storage_ext_get_list(dd_list **list)
155 {
156         GVariant *result;
157         GVariantIter *iter;
158         storage_ext_device *elem, info;
159         int ret;
160
161         if (!list)
162                 return -EINVAL;
163
164         result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
165                         STORAGE_EXT_PATH_MANAGER,
166                         STORAGE_EXT_IFACE_MANAGER,
167                         STORAGE_EXT_GET_LIST,
168                         g_variant_new("(s)", "all"));
169         if (!result) {
170                 _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
171                 return -EIO;
172         }
173
174         g_variant_get(result, "(a(issssssisibii))", &iter);
175
176         while (g_variant_iter_loop(iter, "(issssssisibii)",
177                                 &info.type, &info.devnode, &info.syspath,
178                                 &info.fs_usage, &info.fs_type,
179                                 &info.fs_version, &info.fs_uuid,
180                                 &info.readonly, &info.mount_point,
181                                 &info.state, &info.primary,
182                                 &info.flags, &info.storage_id)) {
183
184                 elem = (storage_ext_device *)malloc(sizeof(storage_ext_device));
185                 if (!elem) {
186                         _E("malloc() failed"); //LCOV_EXCL_LINE
187                         ret = -ENOMEM;
188                         goto out;
189                 }
190
191                 elem->type = info.type;
192                 elem->readonly = info.readonly;
193                 elem->state = info.state;
194                 elem->primary = info.primary;
195                 elem->devnode = strdup(CHECK_STR(info.devnode));
196                 elem->syspath = strdup(CHECK_STR(info.syspath));
197                 elem->fs_usage = strdup(CHECK_STR(info.fs_usage));
198                 elem->fs_type = strdup(CHECK_STR(info.fs_type));
199                 elem->fs_version = strdup(CHECK_STR(info.fs_version));
200                 elem->fs_uuid = strdup(CHECK_STR(info.fs_uuid));
201                 elem->mount_point = strdup(CHECK_STR(info.mount_point));
202                 elem->flags = info.flags;
203                 elem->storage_id = info.storage_id;
204
205                 DD_LIST_APPEND(*list, elem);
206         }
207
208         ret = g_list_length(*list);
209
210 out:
211         if (ret < 0)
212                 storage_ext_release_list(list); //LCOV_EXCL_LINE System Error
213         g_variant_iter_free(iter);
214         g_variant_unref(result);
215         return ret;
216 }
217
218 int storage_ext_get_statvfs(char *path, struct statvfs_32 *buf)
219 {
220         GVariant *result;
221         guint64 bsize, frsize, blocks, bfree, bavail, files, ffree, favail, fsid, flag, namemax;
222
223         assert(buf);
224
225         memset(buf, 0, sizeof(struct statvfs_32));
226
227         result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
228                         STORAGE_EXT_PATH_STORAGE,
229                         STORAGE_EXT_IFACE_STORAGE,
230                         STORAGE_EXT_GET_STATVFS,
231                         g_variant_new("(s)", path));
232         if (!result) {
233                 _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
234                 return -EIO;
235         }
236
237         g_variant_get(result, "(ttttttttttt)",
238                         &bsize, &frsize, &blocks,
239                         &bfree, &bavail, &files,
240                         &ffree, &favail, &fsid,
241                         &flag, &namemax);
242 //      %llu bsize, frsize, blocks, bfree, bavail, files, ffree, favail, fsid, flag, namemax
243
244         buf->f_bsize  = (unsigned long)bsize;
245         buf->f_frsize = (unsigned long)frsize;
246         buf->f_blocks = (unsigned long)blocks;
247         buf->f_bfree  = (unsigned long)bfree;
248         buf->f_bavail = (unsigned long)bavail;
249         buf->f_files  = (unsigned long)files;
250         buf->f_ffree  = (unsigned long)ffree;
251         buf->f_favail = (unsigned long)favail;
252         buf->f_fsid = (unsigned long)fsid;
253         buf->f_flag = (unsigned long)flag;
254         buf->f_namemax = (unsigned long)namemax;
255
256 //      %lu buf->f_bsize, buf->f_frsize, buf->f_blocks, buf->f_bfree, buf->f_bavail, buf->f_files, buf->f_ffree, buf->f_favail, buf->f_fsid, buf->f_flag, buf->f_namemax
257         return 0;
258 }
259
260 int storage_ext_get_statvfs_size64(char *path, struct statvfs *buf)
261 {
262         GVariant *result;
263
264         assert(buf);
265
266         memset(buf, 0, sizeof(struct statvfs));
267
268         result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
269                         STORAGE_EXT_PATH_STORAGE,
270                         STORAGE_EXT_IFACE_STORAGE,
271                         STORAGE_EXT_GET_STATVFS,
272                         g_variant_new("(s)", path));
273         if (!result) {
274                 _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
275                 return -EIO;
276         }
277
278         g_variant_get(result, "(ttttttttttt)",
279                         &(buf->f_bsize), &(buf->f_frsize), &(buf->f_blocks),
280                         &(buf->f_bfree), &(buf->f_bavail), &(buf->f_files),
281                         &(buf->f_ffree), &(buf->f_favail), &(buf->f_fsid),
282                         &(buf->f_flag), &(buf->f_namemax));
283
284 //      %lu buf->f_bsize, buf->f_frsize, buf->f_fsid, buf->f_flag, buf->f_namemax
285 //      %llu buf->f_blocks, buf->f_bfree, buf->f_bavail, buf->f_files, buf->f_ffree, buf->f_favail
286
287         return 0;
288 }
289
290 int storage_ext_get_storage_level(enum tzplatform_variable id, char **level)
291 {
292         GVariant *result;
293         char *tmp;
294
295         result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
296                         STORAGE_EXT_PATH_STORAGE,
297                         STORAGE_EXT_IFACE_STORAGE,
298                         STORAGE_EXT_GET_STORAGE_LEVEL,
299                         g_variant_new("(i)", id));
300         if (!result) {
301                 _E("Failed to get %d level", id);
302                 return -EIO;
303         }
304
305         g_variant_get(result, "(s)", &tmp);
306         *level = strdup(tmp);
307         if (*level == NULL)
308                 return -ENOMEM;
309
310         return 0;
311 }
312
313 //LCOV_EXCL_START Not called Callback
314 static void storage_ext_device_changed(GVariant *params, enum storage_ext_state state, gpointer user_data)
315 {
316         storage_ext_device *dev;
317         dd_list *elem;
318         struct storage_ext_callback *callback;
319         int ret;
320
321         if (!params)
322                 return;
323
324         dev = calloc(1, sizeof(storage_ext_device));
325         if (!dev)
326                 return;
327
328         g_variant_get(params, "(issssssisibii)",
329                         &dev->type,
330                         &dev->devnode,
331                         &dev->syspath,
332                         &dev->fs_usage,
333                         &dev->fs_type,
334                         &dev->fs_version,
335                         &dev->fs_uuid,
336                         &dev->readonly,
337                         &dev->mount_point,
338                         &dev->state,
339                         &dev->primary,
340                         &dev->flags,
341                         &dev->storage_id);
342
343         /* Callback is called when unmount is started(DeviceBlocked signal) */
344         if (state == STORAGE_EXT_CHANGED && dev->state == STORAGE_EXT_UNMOUNTED) {
345                 storage_ext_release_device(&dev);
346                 return;
347         }
348
349         DD_LIST_FOREACH(changed_list, elem, callback) {
350                 if (!callback->func)
351                         continue;
352                 ret = callback->func(dev, state, callback->data);
353                 if (ret < 0)
354                         _E("Failed to call callback for devnode(%s, %d)", dev->devnode, ret);
355         }
356
357         storage_ext_release_device(&dev);
358 }
359 //LCOV_EXCL_STOP
360
361 //LCOV_EXCL_START Not called Callback
362 static void storage_ext_changed(GDBusConnection *conn,
363                 const gchar *sender,
364                 const gchar *path,
365                 const gchar *iface,
366                 const gchar *signal,
367                 GVariant *params,
368                 gpointer user_data)
369 {
370         size_t iface_len, signal_len;
371         enum storage_ext_state state;
372
373         if (!params || !sender || !path || !iface || !signal)
374                 return;
375
376         iface_len = strlen(iface) + 1;
377         signal_len = strlen(signal) + 1;
378
379         if (strncmp(iface, STORAGE_EXT_IFACE_MANAGER, iface_len))
380                 return;
381
382         if (!strncmp(signal, STORAGE_EXT_DEVICE_CHANGED, signal_len))
383                 state = STORAGE_EXT_CHANGED;
384
385         else if (!strncmp(signal, STORAGE_EXT_DEVICE_ADDED, signal_len))
386                 state = STORAGE_EXT_ADDED;
387
388         else if (!strncmp(signal, STORAGE_EXT_DEVICE_REMOVED, signal_len))
389                 state = STORAGE_EXT_REMOVED;
390
391         else if (!strncmp(signal, STORAGE_EXT_DEVICE_BLOCKED, signal_len))
392                 state = STORAGE_EXT_BLOCKED;
393
394         else
395                 return;
396
397         storage_ext_device_changed(params, state, user_data);
398 }
399 //LCOV_EXCL_STOP
400
401 int storage_ext_register_device_change(storage_ext_changed_cb func, void *data)
402 {
403         GDBusConnection *conn;
404         guint block_id = 0;
405         struct storage_ext_callback *callback;
406         dd_list *elem;
407
408         if (!func)
409                 return -EINVAL;
410
411         DD_LIST_FOREACH(changed_list, elem, callback) {
412                 if (callback->func != func)
413                         continue;
414                 if (callback->block_id == 0)
415                         continue;
416
417                 return -EEXIST;
418         }
419
420         callback = (struct storage_ext_callback *)malloc(sizeof(struct storage_ext_callback));
421         if (!callback) {
422                 //LCOV_EXCL_START System Error
423                 _E("malloc() failed");
424                 return -ENOMEM;
425                 //LCOV_EXCL_STOP
426         }
427
428         conn = get_dbus_connection();
429         if (!conn) {
430                 //LCOV_EXCL_START System Error
431                 free(callback);
432                 _E("Failed to get dbus connection");
433                 return -EPERM;
434                 //LCOV_EXCL_STOP
435         }
436
437         block_id = g_dbus_connection_signal_subscribe(conn,
438                         NULL,
439                         STORAGE_EXT_IFACE_MANAGER,
440                         NULL,
441                         NULL,
442                         NULL,
443                         G_DBUS_SIGNAL_FLAGS_NONE,
444                         storage_ext_changed,
445                         NULL,
446                         NULL);
447         if (block_id == 0) {
448                 //LCOV_EXCL_START System Error
449                 free(callback);
450                 _E("Failed to subscrive bus signal");
451                 return -EPERM;
452                 //LCOV_EXCL_STOP
453         }
454
455         callback->func = func;
456         callback->data = data;
457         callback->block_id = block_id;
458
459         DD_LIST_APPEND(changed_list, callback);
460
461         return 0;
462 }
463
464 void storage_ext_unregister_device_change(storage_ext_changed_cb func)
465 {
466         GDBusConnection *conn;
467         struct storage_ext_callback *callback;
468         dd_list *elem;
469         dd_list *elem_n;
470
471         if (!func)
472                 return;
473
474         conn = get_dbus_connection();
475         if (!conn) {
476 //LCOV_EXCL_START System Error
477                 _E("fail to get dbus connection");
478                 return;
479 //LCOV_EXCL_STOP
480         }
481
482         DD_LIST_FOREACH_SAFE(changed_list, elem, elem_n, callback) {
483                 if (callback->func != func)
484                         continue;
485                 if (callback->block_id > 0)
486                         g_dbus_connection_signal_unsubscribe(conn, callback->block_id);
487
488                 DD_LIST_REMOVE(changed_list, callback);
489                 free(callback);
490         }
491 }
492
493 int storage_ext_get_device_info(int storage_id, storage_ext_device *info)
494 {
495         GVariant *result;
496
497         result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
498                         STORAGE_EXT_PATH_MANAGER,
499                         STORAGE_EXT_IFACE_MANAGER,
500                         "GetDeviceInfo",
501                         g_variant_new("(i)", storage_id));
502         if (!result) {
503                 _E("There is no storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
504                 return -ENODEV;
505         }
506
507         if (g_variant_check_format_string(result, "(issssssisibii)", true)) {
508                 g_variant_get(result, "(issssssisibii)",
509                                 &info->type, &info->devnode, &info->syspath,
510                                 &info->fs_usage, &info->fs_type,
511                                 &info->fs_version, &info->fs_uuid,
512                                 &info->readonly, &info->mount_point,
513                                 &info->state, &info->primary,
514                                 &info->flags, &info->storage_id);
515         } else {
516                 _E("No storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
517                 return -ENODEV;
518         }
519
520         if (info->storage_id < 0) {
521                 _E("No storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
522                 return -ENODEV;
523         }
524
525         g_variant_unref(result);
526
527         return 0;
528 }