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