Fix documentation for storage_get_internal_memory_size and storage_get_external_memor...
[platform/core/system/libstorage.git] / src / storage-external-dbus.c
index e4f4c49..5d45189 100755 (executable)
 #include <errno.h>
 #include <gio/gio.h>
 #include <glib.h>
+#include <assert.h>
 #include <limits.h>
+#include <sys/statvfs.h>
+#include <tzplatform_config.h>
 
 #include "log.h"
 #include "storage-external-dbus.h"
 
 #define CHECK_STR(a) (a ? a : "")
 
-#define STORAGE_EXT_GET_LIST       "GetDeviceList"
+#define STORAGE_EXT_GET_LIST               "GetDeviceList"
+#define STORAGE_EXT_GET_STATVFS            "GetStatvfs"
+#define STORAGE_EXT_GET_STORAGE_LEVEL      "GetStorageLevel"
 
-#define STORAGE_EXT_OBJECT_ADDED   "ObjectAdded"
-#define STORAGE_EXT_OBJECT_REMOVED "ObjectRemoved"
-#define STORAGE_EXT_DEVICE_CHANGED "DeviceChanged"
+#define STORAGE_EXT_DEVICE_CHANGED         "DeviceChanged"
+#define STORAGE_EXT_DEVICE_ADDED           "DeviceAdded"
+#define STORAGE_EXT_DEVICE_REMOVED         "DeviceRemoved"
+#define STORAGE_EXT_DEVICE_BLOCKED         "DeviceBlocked"
 
 #define DBUS_REPLY_TIMEOUT (-1)
 
-#define DEV_PREFIX           "/dev/"
-
 struct storage_ext_callback {
        storage_ext_changed_cb func;
        void *data;
        guint block_id;
-       guint blockmanager_id;
 };
 
+typedef struct {
+        dbus_pending_cb func;
+        void *data;
+} pending_call_data;
+
 static dd_list *changed_list;
 
 static void storage_ext_release_internal(storage_ext_device *dev)
@@ -103,29 +111,104 @@ static GDBusConnection *get_dbus_connection(void)
 
        conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
        if (!conn) {
+//LCOV_EXCL_START System Error
                if (err) {
                        _E("fail to get dbus connection : %s", err->message);
                        g_clear_error(&err);
                } else
                        _E("fail to get dbus connection");
                return NULL;
+//LCOV_EXCL_STOP
        }
        return conn;
 }
 
-static GVariant *dbus_method_call_sync(const gchar *dest, const gchar *path,
+static void _cb_pending(GDBusConnection *conn,
+                       GAsyncResult *res,
+                       gpointer user_data)
+{
+       GVariant *reply = NULL;
+       GError *err = NULL;
+       pending_call_data *data = (pending_call_data *)user_data;
+
+       reply = g_dbus_connection_call_finish(conn, res, &err);
+       if (!reply || err) {
+               if (!err)
+                       g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED,
+                               "Error during g_dbus_connection_call");
+
+               if (data && data->func)
+                       data->func(NULL, data->data, err);
+               goto out;
+       }
+
+       if (data && data->func)
+               data->func(reply, data->data, err);
+out:
+       if (err)
+               g_error_free(err);
+       if (data)
+               free(data);
+}
+
+int dbus_method_async_with_reply_var(const char *dest, const char *path,
+               const char *iface, const char *method, GVariant *param,
+               dbus_pending_cb cb, int timeout, void *data)
+{
+       GDBusConnection *conn;
+       pending_call_data *pdata = NULL;
+       int ret = 0;
+
+       if (!dest || !path || !iface || !method)
+               return -EINVAL;
+
+       if (timeout < -1) {
+               _E("wrong timeout %d", timeout);
+               return -EINVAL;
+       }
+
+       conn = get_dbus_connection();
+       if (!conn) {
+               _E("fail to get dbus connection"); //LCOV_EXCL_LINE
+               return -1;
+       }
+
+       if (cb) {
+               pdata = (pending_call_data*)malloc(sizeof(pending_call_data));
+               if (!pdata) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               pdata->func = cb;
+               pdata->data = data;
+       }
+
+       g_dbus_connection_call(conn, dest, path, iface, method,
+                       param, NULL, G_DBUS_CALL_FLAGS_NONE, timeout, NULL,
+                       (GAsyncReadyCallback)_cb_pending,
+                       pdata);
+
+       return ret;
+err:
+       if (param)
+               g_variant_unref(param);
+       return ret;
+}
+
+GVariant *dbus_method_call_sync(const gchar *dest, const gchar *path,
                                const gchar *iface, const gchar *method, GVariant *param)
 {
        GDBusConnection *conn;
        GError *err = NULL;
        GVariant *ret;
 
-       if (!dest || !path || !iface || !method || !param)
+       if (!dest || !path || !iface || !method)
                return NULL;
 
        conn = get_dbus_connection();
        if (!conn) {
-               _E("fail to get dbus connection");
+               _E("fail to get dbus connection"); //LCOV_EXCL_LINE
                return NULL;
        }
 
@@ -134,12 +217,14 @@ static GVariant *dbus_method_call_sync(const gchar *dest, const gchar *path,
                        param, NULL, G_DBUS_CALL_FLAGS_NONE,
                        -1, NULL, &err);
        if (!ret) {
+//LCOV_EXCL_START System Error
                if (err) {
                        _E("dbus method sync call failed(%s)", err->message);
                        g_clear_error(&err);
                } else
                        _E("g_dbus_connection_call_sync() failed");
                return NULL;
+//LCOV_EXCL_STOP
        }
 
        return ret;
@@ -161,7 +246,7 @@ int storage_ext_get_list(dd_list **list)
                        STORAGE_EXT_GET_LIST,
                        g_variant_new("(s)", "all"));
        if (!result) {
-               _E("Failed to get storage_ext device info");
+               _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
                return -EIO;
        }
 
@@ -177,7 +262,7 @@ int storage_ext_get_list(dd_list **list)
 
                elem = (storage_ext_device *)malloc(sizeof(storage_ext_device));
                if (!elem) {
-                       _E("malloc() failed");
+                       _E("malloc() failed"); //LCOV_EXCL_LINE
                        ret = -ENOMEM;
                        goto out;
                }
@@ -203,76 +288,121 @@ int storage_ext_get_list(dd_list **list)
 
 out:
        if (ret < 0)
-               storage_ext_release_list(list);
+               storage_ext_release_list(list); //LCOV_EXCL_LINE System Error
        g_variant_iter_free(iter);
        g_variant_unref(result);
        return ret;
 }
 
-static char *get_devnode_from_path(char *path)
+int storage_ext_get_statvfs(char *path, struct statvfs_32 *buf)
 {
-       if (!path)
-               return NULL;
-       /* 1 means '/' */
-       return path + strlen(STORAGE_EXT_PATH_DEVICES) + 1;
+       GVariant *result;
+       guint64 bsize, frsize, blocks, bfree, bavail, files, ffree, favail, fsid, flag, namemax;
+
+       assert(buf);
+
+       memset(buf, 0, sizeof(struct statvfs_32));
+
+       result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
+                       STORAGE_EXT_PATH_STORAGE,
+                       STORAGE_EXT_IFACE_STORAGE,
+                       STORAGE_EXT_GET_STATVFS,
+                       g_variant_new("(s)", path));
+       if (!result) {
+               _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
+               return -EIO;
+       }
+
+       g_variant_get(result, "(ttttttttttt)",
+                       &bsize, &frsize, &blocks,
+                       &bfree, &bavail, &files,
+                       &ffree, &favail, &fsid,
+                       &flag, &namemax);
+//     %llu bsize, frsize, blocks, bfree, bavail, files, ffree, favail, fsid, flag, namemax
+
+       buf->f_bsize  = (unsigned long)bsize;
+       buf->f_frsize = (unsigned long)frsize;
+       buf->f_blocks = (unsigned long)blocks;
+       buf->f_bfree  = (unsigned long)bfree;
+       buf->f_bavail = (unsigned long)bavail;
+       buf->f_files  = (unsigned long)files;
+       buf->f_ffree  = (unsigned long)ffree;
+       buf->f_favail = (unsigned long)favail;
+       buf->f_fsid = (unsigned long)fsid;
+       buf->f_flag = (unsigned long)flag;
+       buf->f_namemax = (unsigned long)namemax;
+
+//     %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
+       return 0;
 }
 
-static void storage_ext_object_path_changed(enum storage_ext_state state,
-               GVariant *params, gpointer user_data)
+int storage_ext_get_statvfs_size64(char *path, struct statvfs *buf)
 {
-       storage_ext_device *dev = NULL;
-       dd_list *elem;
-       struct storage_ext_callback *callback;
-       char *path = NULL;
-       char *devnode;
-       int ret;
+       GVariant *result;
 
-       if (!params)
-               return;
+       assert(buf);
 
-       g_variant_get(params, "(s)", &path);
+       memset(buf, 0, sizeof(struct statvfs));
 
-       devnode = get_devnode_from_path(path);
-       if (!devnode)
-               goto out;
+       result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
+                       STORAGE_EXT_PATH_STORAGE,
+                       STORAGE_EXT_IFACE_STORAGE,
+                       STORAGE_EXT_GET_STATVFS,
+                       g_variant_new("(s)", path));
+       if (!result) {
+               _E("Failed to get storage_ext device info"); //LCOV_EXCL_LINE
+               return -EIO;
+       }
 
-       dev = calloc(1, sizeof(storage_ext_device *));
-       if (!dev)
-               goto out;
+       g_variant_get(result, "(ttttttttttt)",
+                       &(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));
 
-       dev->devnode = strdup(devnode);
-       if (dev->devnode == NULL) {
-               _E("strdup() failed");
-               goto out;
-       }
+//     %lu buf->f_bsize, buf->f_frsize, buf->f_fsid, buf->f_flag, buf->f_namemax
+//     %llu buf->f_blocks, buf->f_bfree, buf->f_bavail, buf->f_files, buf->f_ffree, buf->f_favail
 
-       DD_LIST_FOREACH(changed_list, elem, callback) {
-               if (!callback->func)
-                       continue;
-               ret = callback->func(dev, state, callback->data);
-               if (ret < 0)
-                       _E("Failed to call callback for devnode(%s, %d)", devnode, ret);
+       return 0;
+}
+
+int storage_ext_get_storage_level(const char *path, char **level)
+{
+       GVariant *result;
+       char *tmp;
+       enum tzplatform_variable id;
+
+       if (!strcmp(path, tzplatform_getenv(TZ_SYS_USER)))
+               id = TZ_SYS_USER;
+       else if (!strcmp(path, tzplatform_getenv(TZ_SYS_TMP)))
+               id = TZ_SYS_TMP;
+       else if (!strcmp(path, tzplatform_getenv(TZ_SYS_OPT)))
+               id = TZ_SYS_OPT;
+       else {
+               _E("Invalid path");
+               return -EINVAL;
        }
 
-out:
-       if (dev) {
-               free(dev->devnode);
-               free(dev);
+       result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
+                       STORAGE_EXT_PATH_STORAGE,
+                       STORAGE_EXT_IFACE_STORAGE,
+                       STORAGE_EXT_GET_STORAGE_LEVEL,
+                       g_variant_new("(i)", id));
+       if (!result) {
+               _E("Failed to get %d level", id);
+               return -EIO;
        }
-       free(path);
-}
 
-static void storage_ext_device_added(GVariant *params, gpointer user_data)
-{
-       storage_ext_object_path_changed(STORAGE_EXT_ADDED, params, user_data);
-}
+       g_variant_get(result, "(s)", &tmp);
+       *level = strdup(tmp);
+       if (*level == NULL)
+               return -ENOMEM;
 
-static void storage_ext_device_removed(GVariant *params, gpointer user_data)
-{
-       storage_ext_object_path_changed(STORAGE_EXT_REMOVED, params, user_data);
+       return 0;
 }
 
-static void storage_ext_device_changed(GVariant *params, gpointer user_data)
+//LCOV_EXCL_START Not called Callback
+static void storage_ext_device_changed(GVariant *params, enum storage_ext_state state, gpointer user_data)
 {
        storage_ext_device *dev;
        dd_list *elem;
@@ -301,17 +431,25 @@ static void storage_ext_device_changed(GVariant *params, gpointer user_data)
                        &dev->flags,
                        &dev->storage_id);
 
+       /* Callback is called when unmount is started(DeviceBlocked signal) */
+       if (state == STORAGE_EXT_CHANGED && dev->state == STORAGE_EXT_UNMOUNTED) {
+               storage_ext_release_device(&dev);
+               return;
+       }
+
        DD_LIST_FOREACH(changed_list, elem, callback) {
                if (!callback->func)
                        continue;
-               ret = callback->func(dev, STORAGE_EXT_CHANGED, callback->data);
+               ret = callback->func(dev, state, callback->data);
                if (ret < 0)
                        _E("Failed to call callback for devnode(%s, %d)", dev->devnode, ret);
        }
 
        storage_ext_release_device(&dev);
 }
+//LCOV_EXCL_STOP
 
+//LCOV_EXCL_START Not called Callback
 static void storage_ext_changed(GDBusConnection *conn,
                const gchar *sender,
                const gchar *path,
@@ -321,6 +459,7 @@ static void storage_ext_changed(GDBusConnection *conn,
                gpointer user_data)
 {
        size_t iface_len, signal_len;
+       enum storage_ext_state state;
 
        if (!params || !sender || !path || !iface || !signal)
                return;
@@ -328,25 +467,32 @@ static void storage_ext_changed(GDBusConnection *conn,
        iface_len = strlen(iface) + 1;
        signal_len = strlen(signal) + 1;
 
-       if (!strncmp(iface, STORAGE_EXT_IFACE_MANAGER, iface_len)) {
-               if (!strncmp(signal, STORAGE_EXT_OBJECT_ADDED, signal_len))
-                       storage_ext_device_added(params, user_data);
-               else if (!strncmp(signal, STORAGE_EXT_OBJECT_REMOVED, signal_len))
-                       storage_ext_device_removed(params, user_data);
+       if (strncmp(iface, STORAGE_EXT_IFACE_MANAGER, iface_len))
                return;
-       }
 
-       if (!strncmp(iface, STORAGE_EXT_IFACE, iface_len) &&
-               !strncmp(signal, STORAGE_EXT_DEVICE_CHANGED, signal_len)) {
-               storage_ext_device_changed(params, user_data);
+       if (!strncmp(signal, STORAGE_EXT_DEVICE_CHANGED, signal_len))
+               state = STORAGE_EXT_CHANGED;
+
+       else if (!strncmp(signal, STORAGE_EXT_DEVICE_ADDED, signal_len))
+               state = STORAGE_EXT_ADDED;
+
+       else if (!strncmp(signal, STORAGE_EXT_DEVICE_REMOVED, signal_len))
+               state = STORAGE_EXT_REMOVED;
+
+       else if (!strncmp(signal, STORAGE_EXT_DEVICE_BLOCKED, signal_len))
+               state = STORAGE_EXT_BLOCKED;
+
+       else
                return;
-       }
+
+       storage_ext_device_changed(params, state, user_data);
 }
+//LCOV_EXCL_STOP
 
 int storage_ext_register_device_change(storage_ext_changed_cb func, void *data)
 {
        GDBusConnection *conn;
-       guint block_id = NULL, blockmanager_id = NULL;
+       guint block_id = 0;
        struct storage_ext_callback *callback;
        dd_list *elem;
 
@@ -356,7 +502,7 @@ int storage_ext_register_device_change(storage_ext_changed_cb func, void *data)
        DD_LIST_FOREACH(changed_list, elem, callback) {
                if (callback->func != func)
                        continue;
-               if (callback->block_id == 0 || callback->blockmanager_id == 0)
+               if (callback->block_id == 0)
                        continue;
 
                return -EEXIST;
@@ -364,53 +510,42 @@ int storage_ext_register_device_change(storage_ext_changed_cb func, void *data)
 
        callback = (struct storage_ext_callback *)malloc(sizeof(struct storage_ext_callback));
        if (!callback) {
+               //LCOV_EXCL_START System Error
                _E("malloc() failed");
                return -ENOMEM;
+               //LCOV_EXCL_STOP
        }
 
        conn = get_dbus_connection();
        if (!conn) {
+               //LCOV_EXCL_START System Error
                free(callback);
                _E("Failed to get dbus connection");
                return -EPERM;
+               //LCOV_EXCL_STOP
        }
 
        block_id = g_dbus_connection_signal_subscribe(conn,
-                       STORAGE_EXT_BUS_NAME,
-                       STORAGE_EXT_IFACE,
-                       STORAGE_EXT_DEVICE_CHANGED,
-                       NULL,
                        NULL,
-                       G_DBUS_SIGNAL_FLAGS_NONE,
-                       storage_ext_changed,
-                       NULL,
-                       NULL);
-       if (block_id == 0) {
-               free(callback);
-               _E("Failed to subscrive bus signal");
-               return -EPERM;
-       }
-
-       blockmanager_id = g_dbus_connection_signal_subscribe(conn,
-                       STORAGE_EXT_BUS_NAME,
                        STORAGE_EXT_IFACE_MANAGER,
                        NULL,
-                       STORAGE_EXT_PATH_MANAGER,
+                       NULL,
                        NULL,
                        G_DBUS_SIGNAL_FLAGS_NONE,
                        storage_ext_changed,
                        NULL,
                        NULL);
-       if (blockmanager_id == 0) {
+       if (block_id == 0) {
+               //LCOV_EXCL_START System Error
                free(callback);
                _E("Failed to subscrive bus signal");
                return -EPERM;
+               //LCOV_EXCL_STOP
        }
 
        callback->func = func;
        callback->data = data;
        callback->block_id = block_id;
-       callback->blockmanager_id = blockmanager_id;
 
        DD_LIST_APPEND(changed_list, callback);
 
@@ -422,23 +557,24 @@ void storage_ext_unregister_device_change(storage_ext_changed_cb func)
        GDBusConnection *conn;
        struct storage_ext_callback *callback;
        dd_list *elem;
+       dd_list *elem_n;
 
        if (!func)
                return;
 
        conn = get_dbus_connection();
        if (!conn) {
+//LCOV_EXCL_START System Error
                _E("fail to get dbus connection");
                return;
+//LCOV_EXCL_STOP
        }
 
-       DD_LIST_FOREACH(changed_list, elem, callback) {
+       DD_LIST_FOREACH_SAFE(changed_list, elem, elem_n, callback) {
                if (callback->func != func)
                        continue;
                if (callback->block_id > 0)
                        g_dbus_connection_signal_unsubscribe(conn, callback->block_id);
-               if (callback->blockmanager_id > 0)
-                       g_dbus_connection_signal_unsubscribe(conn, callback->blockmanager_id);
 
                DD_LIST_REMOVE(changed_list, callback);
                free(callback);
@@ -452,20 +588,30 @@ int storage_ext_get_device_info(int storage_id, storage_ext_device *info)
        result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
                        STORAGE_EXT_PATH_MANAGER,
                        STORAGE_EXT_IFACE_MANAGER,
-                       "GetDeviceInfoByID",
+                       "GetDeviceInfo",
                        g_variant_new("(i)", storage_id));
        if (!result) {
-               _E("There is no storage with the storage id (%d)", storage_id);
+               _E("There is no storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
                return -ENODEV;
        }
 
-       g_variant_get(result, "(issssssisibii)",
-                       &info->type, &info->devnode, &info->syspath,
-                       &info->fs_usage, &info->fs_type,
-                       &info->fs_version, &info->fs_uuid,
-                       &info->readonly, &info->mount_point,
-                       &info->state, &info->primary,
-                       &info->flags, &info->storage_id);
+       if (g_variant_check_format_string(result, "(issssssisibii)", true)) {
+               g_variant_get(result, "(issssssisibii)",
+                               &info->type, &info->devnode, &info->syspath,
+                               &info->fs_usage, &info->fs_type,
+                               &info->fs_version, &info->fs_uuid,
+                               &info->readonly, &info->mount_point,
+                               &info->state, &info->primary,
+                               &info->flags, &info->storage_id);
+       } else {
+               _E("No storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
+               return -ENODEV;
+       }
+
+       if (info->storage_id < 0) {
+               _E("No storage with the storage id (%d)", storage_id); //LCOV_EXCL_LINE
+               return -ENODEV;
+       }
 
        g_variant_unref(result);