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.
30 #include "storage-external-dbus.h"
32 #define CHECK_STR(a) (a ? a : "")
34 #define STORAGE_EXT_GET_LIST "GetDeviceList"
36 #define STORAGE_EXT_OBJECT_ADDED "ObjectAdded"
37 #define STORAGE_EXT_OBJECT_REMOVED "ObjectRemoved"
38 #define STORAGE_EXT_DEVICE_CHANGED "DeviceChanged"
40 #define DBUS_REPLY_TIMEOUT (-1)
42 #define DEV_PREFIX "/dev/"
44 struct storage_ext_callback {
45 storage_ext_changed_cb func;
48 guint blockmanager_id;
51 static dd_list *changed_list;
53 static void storage_ext_release_internal(storage_ext_device *dev)
61 free(dev->fs_version);
63 free(dev->mount_point);
66 void storage_ext_release_device(storage_ext_device **dev)
70 storage_ext_release_internal(*dev);
75 void storage_ext_release_list(dd_list **list)
77 storage_ext_device *dev;
83 DD_LIST_FOREACH(*list, elem, dev) {
84 storage_ext_release_internal(dev);
92 static GDBusConnection *get_dbus_connection(void)
95 static GDBusConnection *conn;
100 #if !GLIB_CHECK_VERSION(2, 35, 0)
104 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
107 _E("fail to get dbus connection : %s", err->message);
110 _E("fail to get dbus connection");
116 static GVariant *dbus_method_call_sync(const gchar *dest, const gchar *path,
117 const gchar *iface, const gchar *method, GVariant *param)
119 GDBusConnection *conn;
123 if (!dest || !path || !iface || !method || !param)
126 conn = get_dbus_connection();
128 _E("fail to get dbus connection");
132 ret = g_dbus_connection_call_sync(conn,
133 dest, path, iface, method,
134 param, NULL, G_DBUS_CALL_FLAGS_NONE,
138 _E("dbus method sync call failed(%s)", err->message);
141 _E("g_dbus_connection_call_sync() failed");
148 int storage_ext_get_list(dd_list **list)
152 storage_ext_device *elem, info;
158 result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
159 STORAGE_EXT_PATH_MANAGER,
160 STORAGE_EXT_IFACE_MANAGER,
161 STORAGE_EXT_GET_LIST,
162 g_variant_new("(s)", "all"));
164 _E("Failed to get storage_ext device info");
168 g_variant_get(result, "(a(issssssisibii))", &iter);
170 while (g_variant_iter_loop(iter, "(issssssisibii)",
171 &info.type, &info.devnode, &info.syspath,
172 &info.fs_usage, &info.fs_type,
173 &info.fs_version, &info.fs_uuid,
174 &info.readonly, &info.mount_point,
175 &info.state, &info.primary,
176 &info.flags, &info.storage_id)) {
178 elem = (storage_ext_device *)malloc(sizeof(storage_ext_device));
180 _E("malloc() failed");
185 elem->type = info.type;
186 elem->readonly = info.readonly;
187 elem->state = info.state;
188 elem->primary = info.primary;
189 elem->devnode = strdup(CHECK_STR(info.devnode));
190 elem->syspath = strdup(CHECK_STR(info.syspath));
191 elem->fs_usage = strdup(CHECK_STR(info.fs_usage));
192 elem->fs_type = strdup(CHECK_STR(info.fs_type));
193 elem->fs_version = strdup(CHECK_STR(info.fs_version));
194 elem->fs_uuid = strdup(CHECK_STR(info.fs_uuid));
195 elem->mount_point = strdup(CHECK_STR(info.mount_point));
196 elem->flags = info.flags;
197 elem->storage_id = info.storage_id;
199 DD_LIST_APPEND(*list, elem);
202 ret = g_list_length(*list);
206 storage_ext_release_list(list);
207 g_variant_iter_free(iter);
208 g_variant_unref(result);
212 static char *get_devnode_from_path(char *path)
217 return path + strlen(STORAGE_EXT_PATH_DEVICES) + 1;
220 static void storage_ext_object_path_changed(enum storage_ext_state state,
221 GVariant *params, gpointer user_data)
223 storage_ext_device *dev = NULL;
225 struct storage_ext_callback *callback;
233 g_variant_get(params, "(s)", &path);
235 devnode = get_devnode_from_path(path);
239 dev = calloc(1, sizeof(storage_ext_device *));
243 dev->devnode = strdup(devnode);
244 if (dev->devnode == NULL) {
245 _E("strdup() failed");
249 DD_LIST_FOREACH(changed_list, elem, callback) {
252 ret = callback->func(dev, state, callback->data);
254 _E("Failed to call callback for devnode(%s, %d)", devnode, ret);
265 static void storage_ext_device_added(GVariant *params, gpointer user_data)
267 storage_ext_object_path_changed(STORAGE_EXT_ADDED, params, user_data);
270 static void storage_ext_device_removed(GVariant *params, gpointer user_data)
272 storage_ext_object_path_changed(STORAGE_EXT_REMOVED, params, user_data);
275 static void storage_ext_device_changed(GVariant *params, gpointer user_data)
277 storage_ext_device *dev;
279 struct storage_ext_callback *callback;
285 dev = calloc(1, sizeof(storage_ext_device));
289 g_variant_get(params, "(issssssisibii)",
304 DD_LIST_FOREACH(changed_list, elem, callback) {
307 ret = callback->func(dev, STORAGE_EXT_CHANGED, callback->data);
309 _E("Failed to call callback for devnode(%s, %d)", dev->devnode, ret);
312 storage_ext_release_device(&dev);
315 static void storage_ext_changed(GDBusConnection *conn,
323 size_t iface_len, signal_len;
325 if (!params || !sender || !path || !iface || !signal)
328 iface_len = strlen(iface) + 1;
329 signal_len = strlen(signal) + 1;
331 if (!strncmp(iface, STORAGE_EXT_IFACE_MANAGER, iface_len)) {
332 if (!strncmp(signal, STORAGE_EXT_OBJECT_ADDED, signal_len))
333 storage_ext_device_added(params, user_data);
334 else if (!strncmp(signal, STORAGE_EXT_OBJECT_REMOVED, signal_len))
335 storage_ext_device_removed(params, user_data);
339 if (!strncmp(iface, STORAGE_EXT_IFACE, iface_len) &&
340 !strncmp(signal, STORAGE_EXT_DEVICE_CHANGED, signal_len)) {
341 storage_ext_device_changed(params, user_data);
346 int storage_ext_register_device_change(storage_ext_changed_cb func, void *data)
348 GDBusConnection *conn;
349 guint block_id = NULL, blockmanager_id = NULL;
350 struct storage_ext_callback *callback;
356 DD_LIST_FOREACH(changed_list, elem, callback) {
357 if (callback->func != func)
359 if (callback->block_id == 0 || callback->blockmanager_id == 0)
365 callback = (struct storage_ext_callback *)malloc(sizeof(struct storage_ext_callback));
367 _E("malloc() failed");
371 conn = get_dbus_connection();
374 _E("Failed to get dbus connection");
378 block_id = g_dbus_connection_signal_subscribe(conn,
379 STORAGE_EXT_BUS_NAME,
381 STORAGE_EXT_DEVICE_CHANGED,
384 G_DBUS_SIGNAL_FLAGS_NONE,
390 _E("Failed to subscrive bus signal");
394 blockmanager_id = g_dbus_connection_signal_subscribe(conn,
395 STORAGE_EXT_BUS_NAME,
396 STORAGE_EXT_IFACE_MANAGER,
398 STORAGE_EXT_PATH_MANAGER,
400 G_DBUS_SIGNAL_FLAGS_NONE,
404 if (blockmanager_id == 0) {
406 _E("Failed to subscrive bus signal");
410 callback->func = func;
411 callback->data = data;
412 callback->block_id = block_id;
413 callback->blockmanager_id = blockmanager_id;
415 DD_LIST_APPEND(changed_list, callback);
420 void storage_ext_unregister_device_change(storage_ext_changed_cb func)
422 GDBusConnection *conn;
423 struct storage_ext_callback *callback;
429 conn = get_dbus_connection();
431 _E("fail to get dbus connection");
435 DD_LIST_FOREACH(changed_list, elem, callback) {
436 if (callback->func != func)
438 if (callback->block_id > 0)
439 g_dbus_connection_signal_unsubscribe(conn, callback->block_id);
440 if (callback->blockmanager_id > 0)
441 g_dbus_connection_signal_unsubscribe(conn, callback->blockmanager_id);
443 DD_LIST_REMOVE(changed_list, callback);
448 int storage_ext_get_device_info(int storage_id, storage_ext_device *info)
452 result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
453 STORAGE_EXT_PATH_MANAGER,
454 STORAGE_EXT_IFACE_MANAGER,
456 g_variant_new("(i)", storage_id));
458 _E("There is no storage with the storage id (%d)", storage_id);
462 g_variant_get(result, "(issssssisibii)",
463 &info->type, &info->devnode, &info->syspath,
464 &info->fs_usage, &info->fs_type,
465 &info->fs_version, &info->fs_uuid,
466 &info->readonly, &info->mount_point,
467 &info->state, &info->primary,
468 &info->flags, &info->storage_id);
470 g_variant_unref(result);