4 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
29 #include <sys/statvfs.h>
30 #include <tzplatform_config.h>
33 #include "storage-external-dbus.h"
35 #define CHECK_STR(a) (a ? a : "")
37 #define STORAGE_EXT_GET_LIST "GetDeviceList"
38 #define STORAGE_EXT_GET_STATVFS "GetStatvfs"
39 #define STORAGE_EXT_GET_STORAGE_LEVEL "GetStorageLevel"
41 #define STORAGE_EXT_DEVICE_CHANGED "DeviceChanged"
42 #define STORAGE_EXT_DEVICE_ADDED "DeviceAdded"
43 #define STORAGE_EXT_DEVICE_REMOVED "DeviceRemoved"
44 #define STORAGE_EXT_DEVICE_BLOCKED "DeviceBlocked"
46 #define DBUS_REPLY_TIMEOUT (-1)
48 struct storage_ext_callback {
49 storage_ext_changed_cb func;
59 static dd_list *changed_list;
61 static void storage_ext_release_internal(storage_ext_device *dev)
69 free(dev->fs_version);
71 free(dev->mount_point);
74 void storage_ext_release_device(storage_ext_device **dev)
78 storage_ext_release_internal(*dev);
83 void storage_ext_release_list(dd_list **list)
85 storage_ext_device *dev;
91 DD_LIST_FOREACH(*list, elem, dev) {
92 storage_ext_release_internal(dev);
100 static GDBusConnection *get_dbus_connection(void)
103 static GDBusConnection *conn;
108 #if !GLIB_CHECK_VERSION(2, 35, 0)
112 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
114 //LCOV_EXCL_START System Error
116 _E("fail to get dbus connection : %s", err->message);
119 _E("fail to get dbus connection");
126 static void _cb_pending(GDBusConnection *conn,
130 GVariant *reply = NULL;
132 pending_call_data *data = (pending_call_data *)user_data;
134 reply = g_dbus_connection_call_finish(conn, res, &err);
137 g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED,
138 "Error during g_dbus_connection_call");
140 if (data && data->func)
141 data->func(NULL, data->data, err);
145 if (data && data->func)
146 data->func(reply, data->data, err);
154 int dbus_method_async_with_reply_var(const char *dest, const char *path,
155 const char *iface, const char *method, GVariant *param,
156 dbus_pending_cb cb, int timeout, void *data)
158 GDBusConnection *conn;
159 pending_call_data *pdata = NULL;
162 if (!dest || !path || !iface || !method)
166 _E("wrong timeout %d", timeout);
170 conn = get_dbus_connection();
172 _E("fail to get dbus connection"); //LCOV_EXCL_LINE
177 pdata = (pending_call_data*)malloc(sizeof(pending_call_data));
187 g_dbus_connection_call(conn, dest, path, iface, method,
188 param, NULL, G_DBUS_CALL_FLAGS_NONE, timeout, NULL,
189 (GAsyncReadyCallback)_cb_pending,
195 g_variant_unref(param);
199 GVariant *dbus_method_call_sync(const gchar *dest, const gchar *path,
200 const gchar *iface, const gchar *method, GVariant *param)
202 GDBusConnection *conn;
206 if (!dest || !path || !iface || !method)
209 conn = get_dbus_connection();
211 _E("fail to get dbus connection"); //LCOV_EXCL_LINE
215 ret = g_dbus_connection_call_sync(conn,
216 dest, path, iface, method,
217 param, NULL, G_DBUS_CALL_FLAGS_NONE,
220 //LCOV_EXCL_START System Error
222 _E("dbus method sync call failed(%s)", err->message);
225 _E("g_dbus_connection_call_sync() failed");
233 int storage_ext_get_list(dd_list **list)
237 storage_ext_device *elem, info;
243 result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
244 STORAGE_EXT_PATH_MANAGER,
245 STORAGE_EXT_IFACE_MANAGER,
246 STORAGE_EXT_GET_LIST,
247 g_variant_new("(s)", "all"));
249 _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
253 g_variant_get(result, "(a(issssssisibii))", &iter);
255 while (g_variant_iter_loop(iter, "(issssssisibii)",
256 &info.type, &info.devnode, &info.syspath,
257 &info.fs_usage, &info.fs_type,
258 &info.fs_version, &info.fs_uuid,
259 &info.readonly, &info.mount_point,
260 &info.state, &info.primary,
261 &info.flags, &info.storage_id)) {
263 elem = (storage_ext_device *)malloc(sizeof(storage_ext_device));
265 _E("malloc() failed"); //LCOV_EXCL_LINE
270 elem->type = info.type;
271 elem->readonly = info.readonly;
272 elem->state = info.state;
273 elem->primary = info.primary;
274 elem->devnode = strdup(CHECK_STR(info.devnode));
275 elem->syspath = strdup(CHECK_STR(info.syspath));
276 elem->fs_usage = strdup(CHECK_STR(info.fs_usage));
277 elem->fs_type = strdup(CHECK_STR(info.fs_type));
278 elem->fs_version = strdup(CHECK_STR(info.fs_version));
279 elem->fs_uuid = strdup(CHECK_STR(info.fs_uuid));
280 elem->mount_point = strdup(CHECK_STR(info.mount_point));
281 elem->flags = info.flags;
282 elem->storage_id = info.storage_id;
284 DD_LIST_APPEND(*list, elem);
287 ret = g_list_length(*list);
291 storage_ext_release_list(list); //LCOV_EXCL_LINE System Error
292 g_variant_iter_free(iter);
293 g_variant_unref(result);
297 int storage_ext_get_statvfs(char *path, struct statvfs_32 *buf)
300 guint64 bsize, frsize, blocks, bfree, bavail, files, ffree, favail, fsid, flag, namemax;
304 memset(buf, 0, sizeof(struct statvfs_32));
306 result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
307 STORAGE_EXT_PATH_STORAGE,
308 STORAGE_EXT_IFACE_STORAGE,
309 STORAGE_EXT_GET_STATVFS,
310 g_variant_new("(s)", path));
312 _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
316 g_variant_get(result, "(ttttttttttt)",
317 &bsize, &frsize, &blocks,
318 &bfree, &bavail, &files,
319 &ffree, &favail, &fsid,
321 // %llu bsize, frsize, blocks, bfree, bavail, files, ffree, favail, fsid, flag, namemax
323 buf->f_bsize = (unsigned long)bsize;
324 buf->f_frsize = (unsigned long)frsize;
325 buf->f_blocks = (unsigned long)blocks;
326 buf->f_bfree = (unsigned long)bfree;
327 buf->f_bavail = (unsigned long)bavail;
328 buf->f_files = (unsigned long)files;
329 buf->f_ffree = (unsigned long)ffree;
330 buf->f_favail = (unsigned long)favail;
331 buf->f_fsid = (unsigned long)fsid;
332 buf->f_flag = (unsigned long)flag;
333 buf->f_namemax = (unsigned long)namemax;
335 // %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
339 int storage_ext_get_statvfs_size64(char *path, struct statvfs *buf)
345 memset(buf, 0, sizeof(struct statvfs));
347 result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
348 STORAGE_EXT_PATH_STORAGE,
349 STORAGE_EXT_IFACE_STORAGE,
350 STORAGE_EXT_GET_STATVFS,
351 g_variant_new("(s)", path));
353 _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
357 g_variant_get(result, "(ttttttttttt)",
358 &(buf->f_bsize), &(buf->f_frsize), &(buf->f_blocks),
359 &(buf->f_bfree), &(buf->f_bavail), &(buf->f_files),
360 &(buf->f_ffree), &(buf->f_favail), &(buf->f_fsid),
361 &(buf->f_flag), &(buf->f_namemax));
363 // %lu buf->f_bsize, buf->f_frsize, buf->f_fsid, buf->f_flag, buf->f_namemax
364 // %llu buf->f_blocks, buf->f_bfree, buf->f_bavail, buf->f_files, buf->f_ffree, buf->f_favail
369 int storage_ext_get_storage_level(const char *path, char **level)
373 enum tzplatform_variable id;
375 if (!strcmp(path, tzplatform_getenv(TZ_SYS_USER)))
377 else if (!strcmp(path, tzplatform_getenv(TZ_SYS_TMP)))
379 else if (!strcmp(path, tzplatform_getenv(TZ_SYS_OPT)))
386 result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
387 STORAGE_EXT_PATH_STORAGE,
388 STORAGE_EXT_IFACE_STORAGE,
389 STORAGE_EXT_GET_STORAGE_LEVEL,
390 g_variant_new("(i)", id));
392 _E("Failed to get %d level", id);
396 g_variant_get(result, "(s)", &tmp);
397 *level = strdup(tmp);
406 //LCOV_EXCL_START Not called Callback
407 static void storage_ext_device_changed(GVariant *params, enum storage_ext_state state, gpointer user_data)
409 storage_ext_device *dev;
411 struct storage_ext_callback *callback;
417 dev = calloc(1, sizeof(storage_ext_device));
421 g_variant_get(params, "(issssssisibii)",
436 /* Callback is called when unmount is started(DeviceBlocked signal) */
437 if (state == STORAGE_EXT_CHANGED && dev->state == STORAGE_EXT_UNMOUNTED) {
438 storage_ext_release_device(&dev);
442 DD_LIST_FOREACH(changed_list, elem, callback) {
445 ret = callback->func(dev, state, callback->data);
447 _E("Failed to call callback for devnode(%s, %d)", dev->devnode, ret);
450 storage_ext_release_device(&dev);
454 //LCOV_EXCL_START Not called Callback
455 static void storage_ext_changed(GDBusConnection *conn,
463 size_t iface_len, signal_len;
464 enum storage_ext_state state;
466 if (!params || !sender || !path || !iface || !signal)
469 iface_len = strlen(iface) + 1;
470 signal_len = strlen(signal) + 1;
472 if (strncmp(iface, STORAGE_EXT_IFACE_MANAGER, iface_len))
475 if (!strncmp(signal, STORAGE_EXT_DEVICE_CHANGED, signal_len))
476 state = STORAGE_EXT_CHANGED;
478 else if (!strncmp(signal, STORAGE_EXT_DEVICE_ADDED, signal_len))
479 state = STORAGE_EXT_ADDED;
481 else if (!strncmp(signal, STORAGE_EXT_DEVICE_REMOVED, signal_len))
482 state = STORAGE_EXT_REMOVED;
484 else if (!strncmp(signal, STORAGE_EXT_DEVICE_BLOCKED, signal_len))
485 state = STORAGE_EXT_BLOCKED;
490 storage_ext_device_changed(params, state, user_data);
494 int storage_ext_register_device_change(storage_ext_changed_cb func, void *data)
496 GDBusConnection *conn;
498 struct storage_ext_callback *callback;
504 DD_LIST_FOREACH(changed_list, elem, callback) {
505 if (callback->func != func)
507 if (callback->block_id == 0)
513 callback = (struct storage_ext_callback *)malloc(sizeof(struct storage_ext_callback));
515 //LCOV_EXCL_START System Error
516 _E("malloc() failed");
521 conn = get_dbus_connection();
523 //LCOV_EXCL_START System Error
525 _E("Failed to get dbus connection");
530 block_id = g_dbus_connection_signal_subscribe(conn,
532 STORAGE_EXT_IFACE_MANAGER,
536 G_DBUS_SIGNAL_FLAGS_NONE,
541 //LCOV_EXCL_START System Error
543 _E("Failed to subscrive bus signal");
548 callback->func = func;
549 callback->data = data;
550 callback->block_id = block_id;
552 DD_LIST_APPEND(changed_list, callback);
557 void storage_ext_unregister_device_change(storage_ext_changed_cb func)
559 GDBusConnection *conn;
560 struct storage_ext_callback *callback;
567 conn = get_dbus_connection();
569 //LCOV_EXCL_START System Error
570 _E("fail to get dbus connection");
575 DD_LIST_FOREACH_SAFE(changed_list, elem, elem_n, callback) {
576 if (callback->func != func)
578 if (callback->block_id > 0)
579 g_dbus_connection_signal_unsubscribe(conn, callback->block_id);
581 DD_LIST_REMOVE(changed_list, callback);
586 int storage_ext_get_device_info(int storage_id, storage_ext_device *info)
590 result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
591 STORAGE_EXT_PATH_MANAGER,
592 STORAGE_EXT_IFACE_MANAGER,
594 g_variant_new("(i)", storage_id));
596 _E("There is no storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
600 if (g_variant_check_format_string(result, "(issssssisibii)", true)) {
601 g_variant_get(result, "(issssssisibii)",
602 &info->type, &info->devnode, &info->syspath,
603 &info->fs_usage, &info->fs_type,
604 &info->fs_version, &info->fs_uuid,
605 &info->readonly, &info->mount_point,
606 &info->state, &info->primary,
607 &info->flags, &info->storage_id);
609 _E("No storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
613 if (info->storage_id < 0) {
614 _E("No storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
618 g_variant_unref(result);