Increase line coverage using LCOV_EXCL
[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 <assert.h>
27 #include <limits.h>
28 #include <glib.h>
29 #include <sys/statvfs.h>
30 #include <tzplatform_config.h>
31 #include <libsyscommon/libgdbus.h>
32 #include <libsyscommon/list.h>
33
34 #include "log.h"
35 #include "storage-external-dbus.h"
36
37 #define CHECK_STR(a) (a ? a : "")
38
39 #define STORAGE_EXT_GET_LIST               "GetDeviceList"
40 #define STORAGE_EXT_GET_STATVFS            "GetStatvfs"
41 #define STORAGE_EXT_GET_STORAGE_LEVEL      "GetStorageLevel"
42
43 #define STORAGE_EXT_DEVICE_CHANGED         "DeviceChanged"
44 #define STORAGE_EXT_DEVICE_ADDED           "DeviceAdded"
45 #define STORAGE_EXT_DEVICE_REMOVED         "DeviceRemoved"
46 #define STORAGE_EXT_DEVICE_BLOCKED         "DeviceBlocked"
47
48 #define DBUS_REPLY_TIMEOUT (-1)
49
50 #define GET_DBUS_CONN_OR_EXIT() \
51         ({ \
52                 dbus_handle_h dbus_handle = gdbus_get_connection(G_BUS_TYPE_SYSTEM, true); \
53                 if (dbus_handle == NULL) { \
54                         _E("Failed to get dbus connection"); \
55                         return -EIO; \
56                 } \
57                 dbus_handle; \
58         })
59
60
61 struct storage_ext_callback {
62         storage_ext_changed_cb func;
63         void *data;
64         guint block_id;
65 };
66
67 static GList *changed_list;
68
69 static void storage_ext_release_internal(storage_ext_device *dev)
70 {
71         if (!dev)
72                 return;
73         free(dev->devnode);
74         free(dev->syspath);
75         free(dev->fs_usage);
76         free(dev->fs_type);
77         free(dev->fs_version);
78         free(dev->fs_uuid);
79         free(dev->mount_point);
80 }
81
82 void storage_ext_release_device(storage_ext_device **dev)
83 {
84         if (!dev || !*dev)
85                 return;
86         storage_ext_release_internal(*dev);
87         free(*dev);
88         *dev = NULL;
89 }
90
91 void storage_ext_release_list(GList **list)
92 {
93         storage_ext_device *dev;
94         GList *elem;
95
96         if (*list == NULL)
97                 return;
98
99         SYS_G_LIST_FOREACH(*list, elem, dev) {
100                 storage_ext_release_internal(dev);
101                 free(dev);
102         }
103
104         g_list_free(*list);
105         *list = NULL;
106 }
107
108 int storage_ext_get_list(GList **list)
109 {
110         GVariant *reply;
111         GVariantIter *iter;
112         storage_ext_device *elem, info;
113         int ret, ret_dbus;
114
115         if (!list)
116                 return -EINVAL;
117
118         dbus_handle_h dbus_handle = GET_DBUS_CONN_OR_EXIT();
119
120         ret_dbus = gdbus_priv_call_sync_with_reply(dbus_handle,
121                         STORAGE_EXT_BUS_NAME,
122                         STORAGE_EXT_PATH_MANAGER,
123                         STORAGE_EXT_IFACE_MANAGER,
124                         STORAGE_EXT_GET_LIST,
125                         g_variant_new("(s)", "all"),
126                         &reply);
127
128         gdbus_free_connection(dbus_handle);
129
130         if (ret_dbus < 0) {
131                 _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
132                 return -EIO; //LCOV_EXCL_LINE
133         }
134
135         if (!g_variant_get_safe(reply, "(a(issssssisibii))", &iter)) {
136                 //LCOV_EXCL_START Dbus type error
137                 _E("Failed to get params from gvariant.");
138                 g_variant_unref(reply);
139                 return -EIO;
140                 //LCOV_EXCL_STOP
141         }
142
143         while (g_variant_iter_loop(iter, "(issssssisibii)",
144                                 &info.type, &info.devnode, &info.syspath,
145                                 &info.fs_usage, &info.fs_type,
146                                 &info.fs_version, &info.fs_uuid,
147                                 &info.readonly, &info.mount_point,
148                                 &info.state, &info.primary,
149                                 &info.flags, &info.storage_id)) {
150
151                 elem = (storage_ext_device *)malloc(sizeof(storage_ext_device));
152                 if (!elem) {
153                         //LCOV_EXCL_START System error
154                         _E("malloc() failed");
155                         ret = -ENOMEM;
156                         goto out;
157                         //LCOV_EXCL_STOP
158                 }
159
160                 elem->type = info.type;
161                 elem->readonly = info.readonly;
162                 elem->state = info.state;
163                 elem->primary = info.primary;
164                 elem->devnode = strdup(CHECK_STR(info.devnode));
165                 elem->syspath = strdup(CHECK_STR(info.syspath));
166                 elem->fs_usage = strdup(CHECK_STR(info.fs_usage));
167                 elem->fs_type = strdup(CHECK_STR(info.fs_type));
168                 elem->fs_version = strdup(CHECK_STR(info.fs_version));
169                 elem->fs_uuid = strdup(CHECK_STR(info.fs_uuid));
170                 elem->mount_point = strdup(CHECK_STR(info.mount_point));
171                 elem->flags = info.flags;
172                 elem->storage_id = info.storage_id;
173
174                 SYS_G_LIST_APPEND(*list, elem);
175         }
176
177         ret = SYS_G_LIST_LENGTH(*list);
178
179 out:
180         if (ret < 0)
181                 storage_ext_release_list(list); //LCOV_EXCL_LINE System Error
182         g_variant_iter_free(iter);
183         g_variant_unref(reply);
184         return ret;
185 }
186
187 int storage_ext_get_statvfs(char *path, struct statvfs_32 *buf)
188 {
189         GVariant *reply;
190         int ret_dbus;
191         guint64 bsize, frsize, blocks, bfree, bavail, files, ffree, favail, fsid, flag, namemax;
192
193         assert(buf);
194
195         memset(buf, 0, sizeof(struct statvfs_32));
196
197         dbus_handle_h dbus_handle = GET_DBUS_CONN_OR_EXIT();
198
199         ret_dbus = gdbus_priv_call_sync_with_reply(dbus_handle,
200                         STORAGE_EXT_BUS_NAME,
201                         STORAGE_EXT_PATH_STORAGE,
202                         STORAGE_EXT_IFACE_STORAGE,
203                         STORAGE_EXT_GET_STATVFS,
204                         g_variant_new("(s)", path),
205                         &reply);
206
207         gdbus_free_connection(dbus_handle);
208
209         if (ret_dbus < 0) {
210                 _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
211                 return -EIO; //LCOV_EXCL_LINE
212         }
213
214         if (!g_variant_get_safe(reply, "(ttttttttttt)",
215                         &bsize, &frsize, &blocks,
216                         &bfree, &bavail, &files,
217                         &ffree, &favail, &fsid,
218                         &flag, &namemax)) {
219                 _E("Failed to get params from gvariant.");
220                 g_variant_unref(reply);
221                 return -EIO;
222         }
223 //      %llu bsize, frsize, blocks, bfree, bavail, files, ffree, favail, fsid, flag, namemax
224
225         buf->f_bsize  = (unsigned long)bsize;
226         buf->f_frsize = (unsigned long)frsize;
227         buf->f_blocks = (unsigned long)blocks;
228         buf->f_bfree  = (unsigned long)bfree;
229         buf->f_bavail = (unsigned long)bavail;
230         buf->f_files  = (unsigned long)files;
231         buf->f_ffree  = (unsigned long)ffree;
232         buf->f_favail = (unsigned long)favail;
233         buf->f_fsid = (unsigned long)fsid;
234         buf->f_flag = (unsigned long)flag;
235         buf->f_namemax = (unsigned long)namemax;
236
237 //      %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
238         return 0;
239 }
240
241 int storage_ext_get_statvfs_size64(char *path, struct statvfs *buf)
242 {
243         GVariant *reply;
244         int ret_dbus;
245
246         assert(buf);
247
248         memset(buf, 0, sizeof(struct statvfs));
249
250         dbus_handle_h dbus_handle = GET_DBUS_CONN_OR_EXIT();
251
252         ret_dbus = gdbus_priv_call_sync_with_reply(dbus_handle,
253                         STORAGE_EXT_BUS_NAME,
254                         STORAGE_EXT_PATH_STORAGE,
255                         STORAGE_EXT_IFACE_STORAGE,
256                         STORAGE_EXT_GET_STATVFS,
257                         g_variant_new("(s)", path),
258                         &reply);
259
260         gdbus_free_connection(dbus_handle);
261
262         if (ret_dbus < 0) {
263                 _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
264                 return -EIO; //LCOV_EXCL_LINE
265         }
266
267         if (!g_variant_get_safe(reply, "(ttttttttttt)",
268                         &(buf->f_bsize), &(buf->f_frsize), &(buf->f_blocks),
269                         &(buf->f_bfree), &(buf->f_bavail), &(buf->f_files),
270                         &(buf->f_ffree), &(buf->f_favail), &(buf->f_fsid),
271                         &(buf->f_flag), &(buf->f_namemax))) {
272                 //LCOV_EXCL_START Dbus type error
273                 _E("Failed to get params from gvariant.");
274                 g_variant_unref(reply);
275                 return -EIO;
276                 //LCOV_EXCL_STOP
277         }
278
279 //      %lu buf->f_bsize, buf->f_frsize, buf->f_fsid, buf->f_flag, buf->f_namemax
280 //      %llu buf->f_blocks, buf->f_bfree, buf->f_bavail, buf->f_files, buf->f_ffree, buf->f_favail
281
282         return 0;
283 }
284
285 int storage_ext_get_storage_level(const char *path, char **level)
286 {
287         GVariant *reply;
288         int ret_dbus;
289         char *reply_val;
290         enum tzplatform_variable id;
291
292         if (!strcmp(path, tzplatform_getenv(TZ_SYS_USER)))
293                 id = TZ_SYS_USER;
294         else if (!strcmp(path, tzplatform_getenv(TZ_SYS_TMP)))
295                 id = TZ_SYS_TMP;
296         else if (!strcmp(path, tzplatform_getenv(TZ_SYS_OPT)))
297                 id = TZ_SYS_OPT;
298         else {
299                 _E("Invalid path");
300                 return -EINVAL;
301         }
302
303         dbus_handle_h dbus_handle = GET_DBUS_CONN_OR_EXIT();
304
305         ret_dbus = gdbus_priv_call_sync_with_reply(
306                         dbus_handle,
307                         STORAGE_EXT_BUS_NAME,
308                         STORAGE_EXT_PATH_STORAGE,
309                         STORAGE_EXT_IFACE_STORAGE,
310                         STORAGE_EXT_GET_STORAGE_LEVEL,
311                         g_variant_new("(i)", id),
312                         &reply);
313
314         gdbus_free_connection(dbus_handle);
315
316         if (ret_dbus < 0) {
317                 //LCOV_EXCL_START Dbus error
318                 _E("Failed to get %d level", id);
319                 return -EIO;
320                 //LCOV_EXCL_STOP
321         }
322
323         if (!g_variant_get_safe(reply, "(s)", &reply_val)) {
324                 //LCOV_EXCL_START Dbus type error
325                 _E("Failed to get params from gvariant.");
326                 g_variant_unref(reply);
327                 return -EIO;
328                 //LCOV_EXCL_STOP
329         }
330
331         *level = strdup(reply_val);
332         g_free(reply_val);
333         g_variant_unref(reply);
334
335         if (*level == NULL)
336                 return -ENOMEM; //LCOV_EXCL_LINE
337
338         return 0;
339 }
340
341 //LCOV_EXCL_START Not called Callback
342 static void storage_ext_device_changed(GVariant *params, enum storage_ext_state state, gpointer user_data)
343 {
344         storage_ext_device *dev;
345         GList *elem;
346         struct storage_ext_callback *callback;
347         int ret_val;
348
349         if (!params)
350                 return;
351
352         dev = calloc(1, sizeof(storage_ext_device));
353         if (!dev)
354                 return;
355
356         if (!g_variant_get_safe(params, "(issssssisibii)",
357                         &dev->type,
358                         &dev->devnode,
359                         &dev->syspath,
360                         &dev->fs_usage,
361                         &dev->fs_type,
362                         &dev->fs_version,
363                         &dev->fs_uuid,
364                         &dev->readonly,
365                         &dev->mount_point,
366                         &dev->state,
367                         &dev->primary,
368                         &dev->flags,
369                         &dev->storage_id))
370                 return;
371
372         /* Callback is called when unmount is started(DeviceBlocked signal) */
373         if (state == STORAGE_EXT_CHANGED && dev->state == STORAGE_EXT_UNMOUNTED) {
374                 storage_ext_release_device(&dev);
375                 return;
376         }
377
378         SYS_G_LIST_FOREACH(changed_list, elem, callback) {
379                 if (!callback->func)
380                         continue;
381                 ret_val = callback->func(dev, state, callback->data);
382                 if (ret_val < 0)
383                         _E("Failed to call callback for devnode(%s, %d)", dev->devnode, ret_val);
384         }
385
386         storage_ext_release_device(&dev);
387 }
388 //LCOV_EXCL_STOP
389
390 //LCOV_EXCL_START Not called Callback
391 static void storage_ext_changed(GDBusConnection *conn,
392                 const gchar *sender,
393                 const gchar *path,
394                 const gchar *iface,
395                 const gchar *signal,
396                 GVariant *params,
397                 gpointer user_data)
398 {
399         size_t iface_len, signal_len;
400         enum storage_ext_state state;
401
402         if (!params || !sender || !path || !iface || !signal)
403                 return;
404
405         iface_len = strlen(iface) + 1;
406         signal_len = strlen(signal) + 1;
407
408         if (strncmp(iface, STORAGE_EXT_IFACE_MANAGER, iface_len))
409                 return;
410
411         if (!strncmp(signal, STORAGE_EXT_DEVICE_CHANGED, signal_len))
412                 state = STORAGE_EXT_CHANGED;
413
414         else if (!strncmp(signal, STORAGE_EXT_DEVICE_ADDED, signal_len))
415                 state = STORAGE_EXT_ADDED;
416
417         else if (!strncmp(signal, STORAGE_EXT_DEVICE_REMOVED, signal_len))
418                 state = STORAGE_EXT_REMOVED;
419
420         else if (!strncmp(signal, STORAGE_EXT_DEVICE_BLOCKED, signal_len))
421                 state = STORAGE_EXT_BLOCKED;
422
423         else
424                 return;
425
426         storage_ext_device_changed(params, state, user_data);
427 }
428 //LCOV_EXCL_STOP
429
430 int storage_ext_register_device_change(storage_ext_changed_cb func, void *data)
431 {
432         guint block_id = 0;
433         struct storage_ext_callback *callback;
434         GList *elem;
435
436         if (!func)
437                 return -EINVAL;
438
439         SYS_G_LIST_FOREACH(changed_list, elem, callback) {
440                 if (callback->func != func)
441                         continue;
442                 if (callback->block_id == 0)
443                         continue;
444
445                 return -EEXIST;
446         }
447
448         callback = (struct storage_ext_callback *)malloc(sizeof(struct storage_ext_callback));
449         if (!callback) {
450                 //LCOV_EXCL_START System Error
451                 _E("malloc() failed");
452                 return -ENOMEM;
453                 //LCOV_EXCL_STOP
454         }
455
456         block_id = gdbus_signal_subscribe(NULL, NULL,
457                         STORAGE_EXT_IFACE_MANAGER,
458                         NULL,
459                         storage_ext_changed,
460                         NULL,
461                         NULL);
462         if (block_id == 0) {
463                 //LCOV_EXCL_START System Error
464                 free(callback);
465                 _E("Failed to subscrive bus signal");
466                 return -EPERM;
467                 //LCOV_EXCL_STOP
468         }
469
470         callback->func = func;
471         callback->data = data;
472         callback->block_id = block_id;
473
474         SYS_G_LIST_APPEND(changed_list, callback);
475
476         return 0;
477 }
478
479 void storage_ext_unregister_device_change(storage_ext_changed_cb func)
480 {
481         struct storage_ext_callback *callback;
482         GList *elem;
483         GList *elem_n;
484
485         if (!func)
486                 return;
487
488         SYS_G_LIST_FOREACH_SAFE(changed_list, elem, elem_n, callback) {
489                 if (callback->func != func)
490                         continue;
491                 if (callback->block_id > 0)
492                         gdbus_signal_unsubscribe(NULL, callback->block_id);
493
494                 SYS_G_LIST_REMOVE(changed_list, callback);
495                 free(callback);
496         }
497 }
498
499 int storage_ext_get_device_info(int storage_id, storage_ext_device *info)
500 {
501         GVariant *reply;
502         int ret_dbus;
503
504         dbus_handle_h dbus_handle = GET_DBUS_CONN_OR_EXIT();
505
506         ret_dbus = gdbus_priv_call_sync_with_reply(dbus_handle,
507                         STORAGE_EXT_BUS_NAME,
508                         STORAGE_EXT_PATH_MANAGER,
509                         STORAGE_EXT_IFACE_MANAGER,
510                         "GetDeviceInfo",
511                         g_variant_new("(i)", storage_id),
512                         &reply);
513
514         gdbus_free_connection(dbus_handle);
515
516         if (ret_dbus < 0) {
517                 _E("There is no storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
518                 return -ENODEV; //LCOV_EXCL_LINE
519         }
520
521         if (!g_variant_get_safe(reply, "(issssssisibii)",
522                                 &info->type, &info->devnode, &info->syspath,
523                                 &info->fs_usage, &info->fs_type,
524                                 &info->fs_version, &info->fs_uuid,
525                                 &info->readonly, &info->mount_point,
526                                 &info->state, &info->primary,
527                                 &info->flags, &info->storage_id)) {
528                 //LCOV_EXCL_START Dbus error
529                 _E("No storage with the storage id (%d)", storage_id);
530                 ret_dbus = -ENODEV;
531                 goto out;
532                 //LCOV_EXCL_STOP
533         }
534
535         if (info->storage_id < 0) {
536                 //LCOV_EXCL_START Dbus error
537                 _E("No storage with the storage id (%d)", storage_id);
538                 ret_dbus = -ENODEV;
539                 goto out;
540                 //LCOV_EXCL_STOP
541         }
542
543 out:
544         g_variant_unref(reply);
545         return 0;
546 }