Use private dbus connection for synchronous calls.
[platform/core/system/libstorage.git] / src / storage-inhouse.c
index e589b14..ef71f98 100755 (executable)
  */
 
 
+#include <unistd.h>
+#include <sys/types.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <tzplatform_config.h>
+#include <blkid.h>
+#include <libsyscommon/libgdbus.h>
+#include <libsyscommon/common.h>
 
 #include "common.h"
-#include "list.h"
 #include "log.h"
 #include "storage-internal.h"
 #include "storage-external-dbus.h"
 
+#define FORMAT_TIMEOUT (120*1000)
+#define USER_PARTITION "user"
+#define CONTAINER_USER_PARTITION "contain-user"
+
 /*
-   Get compat path from origin Multi-user path
-   from TZ_USER_CONTENT/.. to /opt/usr/media/..
-   Input should be normalized path like /opt/usr/home/owner/media (TODO: internal normalization)
-
-   Why this API should be provided?
-   In multi-user environment, each user has own compat content direcotry.(/opt/usr/media)
-   However, although system daemon operates real path,
-            system daemon needs to provide compat path to App if the real path is converted.
-
-   Usage:
-       #include <storage-internal.h>
-
-       char dest[100];
-       if(storage_get_compat_internal_path(src, sizeof(dest), dest) < 0)
-               // cannot convert. use src path
-       else
-               // can convert. use dest path
+       Get compat path from origin Multi-user path
+       from TZ_USER_CONTENT/.. to /opt/usr/media/..
+       Input should be normalized path like /opt/usr/home/owner/media (TODO: internal normalization)
+
+       Why this API should be provided?
+       In multi-user environment, each user has own compat content direcotry.(/opt/usr/media)
+       However, although system daemon operates real path,
+               system daemon needs to provide compat path to App if the real path is converted.
+
+       Usage:
+               #include <storage-internal.h>
+
+               char dest[100];
+               if(storage_get_compat_internal_path(src, sizeof(dest), dest) < 0)
+                       // cannot convert. use src path
+               else
+                       // can convert. use dest path
  */
+//LCOV_EXCL_START Untested function
 API int storage_get_compat_internal_path(const char* origin, int len, char* compat)
 {
-       int r=-1;
+       int r = -1;
+       int str_len;
        const char* str;
 
+       if (!compat || !origin) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (getuid() <= USER_UID_START) {
+               //LCOV_EXCL_START System Error
+               _E("Only apps and user session daemons are allowed "
+                               "to use storage_get_compat_internal_path()");
+               return -1;
+               //LCOV_EXCL_STOP
+       }
+
        // this API works on place where compat path is bind-mounted
-       if(!is_compat_bind_mount()){
-               _E("no compat bind mount");
+       if (!is_compat_bind_mount()) {
+               //LCOV_EXCL_START System Error
+               _E("No compat bind mount");
                return -1;
+               //LCOV_EXCL_STOP
        }
 
-       str = tzplatform_getenv(TZ_USER_CONTENT);
-       if(strncmp(origin,str,strlen(str))!=0){
-               _E("failed to match TZ_USER_CONTENT");
+       str = tzplatform_uid_getenv(getuid(), TZ_USER_CONTENT);
+       str_len = strlen(str);
+       if (strncmp(origin, str, str_len) != 0) {
+               _E("Failed to match TZ_USER_CONTENT");
                return -1;
        }
 
-       r = snprintf(compat,len,"%s/%s",COMPAT_DIR,origin+strlen(str));
-       if(r < 0){
-               _E("failed to create new path");
+       r = snprintf(compat, len, "%s%s", COMPAT_DIR, origin + str_len);
+       if (r < 0) {
+               //LCOV_EXCL_START System Error
+               _E("Failed to create new path");
                return -1;
+               //LCOV_EXCL_STOP
        }
 
        return 0;
 }
+//LCOV_EXCL_STOP
 
 /*
-   Get Multi-user path from compat path
-   from /opt/usr/media/.. to TZ_USER_CONTENT/..
-   Input should be normalized path like /opt/usr/media (TODO: internal normalization)
-
-   Why this API should be provided?
-   In multi-user environment, each user has own compat content direcotry.(/opt/usr/media)
-   However, although some APIs send the compat path to system daemon,
-            system daemon should access real path.
-
-   Usage:
-       #include <storage-internal.h>
-
-       char dest[100];
-       if(storage_get_origin_internal_path(src, sizeof(dest), dest) < 0)
-               // cannot convert. use src path
-       else
-               // can convert. use dest path
+       Get Multi-user path from compat path
+       from /opt/usr/media/.. to TZ_USER_CONTENT/..
+       Input should be normalized path like /opt/usr/media (TODO: internal normalization)
+
+       Why this API should be provided?
+       In multi-user environment, each user has own compat content direcotry.(/opt/usr/media)
+       However, although some APIs send the compat path to system daemon,
+               system daemon should access real path.
+
+       Usage:
+               #include <storage-internal.h>
+
+               char dest[100];
+               if(storage_get_origin_internal_path(src, sizeof(dest), dest) < 0)
+                       // cannot convert. use src path
+               else
+                       // can convert. use dest path
 */
 API int storage_get_origin_internal_path(const char* compat, int len, char* origin)
 {
        int r;
+       int compat_len;
+
+       if (!compat || !origin) {
+               _E("Invalid parameter");
+               return -1;
+       }
+
+       if (getuid() <= USER_UID_START) {
+               //LCOV_EXCL_START System Error
+               _E("Only apps and user session daemons are allowed "
+                               "to use storage_get_origin_internal_path()");
+               return -1;
+               //LCOV_EXCL_STOP
+       }
 
        // this API works on place where compat path is bind-mounted
-       if(!is_compat_bind_mount()){
+       if (!is_compat_bind_mount()) {
+               //LCOV_EXCL_START System Error
                _E("no compat bind mount");
                return -1;
+               //LCOV_EXCL_STOP
        }
 
-       if(strncmp(compat,COMPAT_DIR,strlen(COMPAT_DIR))!=0){
+       compat_len = strlen(COMPAT_DIR);
+       if (strncmp(compat, COMPAT_DIR, compat_len) != 0) {
                _E("failed to match COMPAT_DIR");
                return -1;
        }
 
-       r = snprintf(origin,len,"%s/%s",tzplatform_getenv(TZ_USER_CONTENT),compat+strlen(COMPAT_DIR));
-       if(r < 0){
+       r = snprintf(origin, len, "%s%s", tzplatform_uid_getenv(getuid(), TZ_USER_CONTENT), compat + compat_len);
+       if (r < 0) {
+               //LCOV_EXCL_START System Error
                _E("failed to create new path");
                return -1;
+               //LCOV_EXCL_STOP
        }
 
        return 0;
@@ -117,40 +165,373 @@ API int storage_get_origin_internal_path(const char* compat, int len, char* orig
 
 API int storage_get_primary_sdcard(int *storage_id, char **path)
 {
-       GVariant *result;
-       storage_ext_device info;
+       GVariant *reply;
+       int ret, ret_dbus;
+       char *reply_mount_point = NULL;
+       int reply_id;
 
        if (!storage_id || !path)
                return STORAGE_ERROR_INVALID_PARAMETER;
 
-       result = dbus_method_call_sync(STORAGE_EXT_BUS_NAME,
+       if (!storage_ext_is_supported())
+               return STORAGE_ERROR_NOT_SUPPORTED;
+
+       dbus_handle_h dbus_handle = gdbus_get_connection(G_BUS_TYPE_SYSTEM, true);
+       if (dbus_handle == NULL) {
+               _E("Failed to get dbus connection");
+               return STORAGE_ERROR_OPERATION_FAILED;
+       }
+
+       ret_dbus = gdbus_priv_call_sync_with_reply(dbus_handle,
+                       STORAGE_EXT_BUS_NAME,
                        STORAGE_EXT_PATH_MANAGER,
                        STORAGE_EXT_IFACE_MANAGER,
                        "GetMmcPrimary",
-                       NULL);
-       if (!result) {
+                       NULL,
+                       &reply);
+
+       gdbus_free_connection(dbus_handle);
+
+       if (ret_dbus < 0) {
+               //LCOV_EXCL_START System Error
                _E("Failed to get primary sdcard partition"); //LCOV_EXCL_LINE
                return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
+               //LCOV_EXCL_STOP
+       }
+
+       if (!g_variant_get_safe(reply, "(issssssisibii)",
+                       NULL, NULL, NULL,
+                       NULL, NULL,
+                       NULL, NULL,
+                       NULL, &reply_mount_point,
+                       NULL, NULL,
+                       NULL, &reply_id)) {
+               g_variant_unref(reply);
+               return STORAGE_ERROR_OPERATION_FAILED;
+       }
+
+       g_variant_unref(reply);
+
+       if (reply_id < 0) {
+               ret = STORAGE_ERROR_NO_DEVICE;
+               goto out;
+       }
+
+       *path = strdup(reply_mount_point);
+       if (*path == NULL) {
+               ret = STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
+               goto out;
+       }
+
+       *storage_id = reply_id;
+
+       ret = STORAGE_ERROR_NONE;
+out:
+       g_free(reply_mount_point);
+
+       return ret;
+}
+
+API int storage_get_storage_level(const char *path, char **level)
+{
+       int ret_level;
+
+       if (!level || !path)
+               return STORAGE_ERROR_INVALID_PARAMETER;
+
+       ret_level = storage_ext_get_storage_level(path, level);
+       if (ret_level == -ENOMEM)
+               return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
+       else if (ret_level == -EINVAL)
+               return STORAGE_ERROR_INVALID_PARAMETER;
+       else if (ret_level < 0)
+               return STORAGE_ERROR_OPERATION_FAILED;
+
+       return STORAGE_ERROR_NONE;
+}
+
+//LCOV_EXCL_START Not called callback
+static void mount_mmc_cb(GVariant *var, void *user_data, GError *err)
+{
+       struct mmc_contents *mmc_data = (struct mmc_contents*)user_data;
+       int mmc_ret = -1;
+
+       _D("mount_mmc_cb called");
+
+       if (!var) {
+               _E("no message [%s]", err->message);
+               mmc_ret = -EBADMSG;
+               goto exit;
+       }
+
+       g_variant_get(var, "(i)", &mmc_ret);
+
+       _I("Mount State : %d", mmc_ret);
+
+exit:
+       if (var)
+               g_variant_unref(var);
+       (mmc_data->mmc_cb)(mmc_ret, mmc_data->user_data);
+}
+//LCOV_EXCL_STOP
+
+API int storage_request_mount_mmc(struct mmc_contents *mmc_data)
+{
+       void (*mount_cb)(GVariant *, void *, GError *) = NULL;
+       void *data = NULL;
+       char *path;
+       int ret_val;
+       int id;
+
+       if (mmc_data && mmc_data->mmc_cb) {
+               _I("Mount callback exists");
+               mount_cb = mount_mmc_cb;
+               data = mmc_data;
+       }
+
+       ret_val = storage_get_primary_sdcard(&id, &path);
+       if (ret_val != STORAGE_ERROR_NONE)
+               return ret_val;
+//LCOV_EXCL_START System Error
+       if (path)
+               free(path);
+//LCOV_EXCL_STOP
+
+       ret_val = gdbus_call_async_with_reply(STORAGE_EXT_BUS_NAME,
+                       STORAGE_EXT_PATH_MANAGER,
+                       STORAGE_EXT_IFACE_MANAGER,
+                       "Mount",
+                       g_variant_new("(is)", id, ""),
+                       mount_cb,
+                       -1,
+                       data);
+
+       _I("Mount Request %s", ret_val == 0 ? "Success" : "Failed");
+
+       if (ret_val == -ENOMEM)
+               return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
+       if (ret_val < 0)
+               return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
+
+       return STORAGE_ERROR_NONE;
+}
+
+//LCOV_EXCL_START Not called callback
+static void unmount_mmc_cb(GVariant *var, void *user_data, GError *err)
+{
+       struct mmc_contents *mmc_data = (struct mmc_contents*)user_data;
+       int mmc_ret;
+
+       _D("unmount_mmc_cb called");
+
+       if (!var) {
+               _E("no message [%s]", err->message);
+               mmc_ret = -EBADMSG;
+               goto exit;
+       }
+
+       g_variant_get(var, "(i)", &mmc_ret);
+
+       _I("Unmount State : %d", mmc_ret);
+
+exit:
+       if (var)
+               g_variant_unref(var);
+       (mmc_data->mmc_cb)(mmc_ret, mmc_data->user_data);
+}
+//LCOV_EXCL_STOP
+
+API int storage_request_unmount_mmc(struct mmc_contents *mmc_data, int option)
+{
+       void (*unmount_cb)(GVariant *, void *, GError *) = NULL;
+       void *data = NULL;
+       char *path;
+       int ret_val;
+       int id;
+
+       if (option < 0 || option > 1)
+               return STORAGE_ERROR_INVALID_PARAMETER;
+
+       if (mmc_data && mmc_data->mmc_cb) {
+               _I("Unmount callback exists");
+               unmount_cb = unmount_mmc_cb;
+               data = mmc_data;
+       }
+
+       ret_val = storage_get_primary_sdcard(&id, &path);
+       if (ret_val != STORAGE_ERROR_NONE)
+               return ret_val;
+//LCOV_EXCL_START System Error
+       if (path)
+               free(path);
+//LCOV_EXCL_STOP
+
+       ret_val = gdbus_call_async_with_reply(STORAGE_EXT_BUS_NAME,
+                       STORAGE_EXT_PATH_MANAGER,
+                       STORAGE_EXT_IFACE_MANAGER,
+                       "Unmount",
+                       g_variant_new("(ii)", id, option),
+                       unmount_cb,
+                       -1,
+                       data);
+
+       _I("Unmount Request %s", ret_val == 0 ? "Success" : "Failed");
+
+       if (ret_val == -ENOMEM)
+               return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
+       if (ret_val < 0)
+               return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
+
+       return STORAGE_ERROR_NONE;
+}
+
+//LCOV_EXCL_START Not called callback
+static void format_mmc_cb(GVariant *var, void *user_data, GError *err)
+{
+       struct mmc_contents *mmc_data = (struct mmc_contents*)user_data;
+       int mmc_ret;
+
+       _D("format_mmc_cb called");
+
+       if (!var) {
+               _E("no message [%s]", err->message);
+               mmc_ret = -EBADMSG;
+               goto exit;
+       }
+
+       g_variant_get(var, "(i)", &mmc_ret);
+
+       _I("Format State : %d", mmc_ret);
+
+exit:
+       if (var)
+               g_variant_unref(var);
+       (mmc_data->mmc_cb)(mmc_ret, mmc_data->user_data);
+}
+//LCOV_EXCL_STOP
+
+API int storage_request_format_mmc(struct mmc_contents *mmc_data)
+{
+       return storage_format_mmc(mmc_data, 1);
+}
+
+API int storage_format_mmc(struct mmc_contents *mmc_data, int option)
+{
+       void (*format_cb)(GVariant *, void *, GError *) = NULL;
+       void *data = NULL;
+       char *path;
+       int ret_val;
+       int id;
+
+       if (option < 0 || option > 1)
+               return STORAGE_ERROR_INVALID_PARAMETER;
+
+       if (mmc_data && mmc_data->mmc_cb) {
+               _I("Format callback exists");
+               format_cb = format_mmc_cb;
+               data = mmc_data;
+       }
+
+       ret_val = storage_get_primary_sdcard(&id, &path);
+       if (ret_val != STORAGE_ERROR_NONE)
+               return ret_val;
+//LCOV_EXCL_START System Error
+       if (path)
+               free(path);
+//LCOV_EXCL_STOP
+
+       ret_val = gdbus_call_async_with_reply(STORAGE_EXT_BUS_NAME,
+                       STORAGE_EXT_PATH_MANAGER,
+                       STORAGE_EXT_IFACE_MANAGER,
+                       "Format",
+                       g_variant_new("(ii)", id, option),
+                       format_cb,
+                       FORMAT_TIMEOUT,
+                       data);
+
+       _I("Format Request %s", ret_val == 0 ? "Success" : "Failed");
+
+       if (ret_val == -ENOMEM)
+               return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
+       if (ret_val < 0)
+               return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
+
+       return STORAGE_ERROR_NONE;
+}
+
+API int storage_is_mounted_opt_usr(storage_part_mount_e *mounted)
+{
+       blkid_cache cache = NULL;
+       blkid_dev_iterate iter;
+       blkid_dev dev;
+       int ret_val;
+       bool found = false;
+       char *user_label = libsys_is_container()? CONTAINER_USER_PARTITION: USER_PARTITION;
+
+       if (!mounted)
+               return STORAGE_ERROR_INVALID_PARAMETER;
+
+       _D("Find user partition label: %s", user_label);
+       ret_val = blkid_get_cache(&cache, NULL);
+       if (ret_val < 0) {
+               _E("Failed to get cache"); //LCOV_EXCL_LINE
+               *mounted = STORAGE_PART_ERROR; //LCOV_EXCL_LINE
+               return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
+       }
+
+       ret_val = blkid_probe_all(cache);
+       if (ret_val < 0) {
+               _E("Failed to probe all block devices"); //LCOV_EXCL_LINE
+               *mounted = STORAGE_PART_ERROR; //LCOV_EXCL_LINE
+               return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
        }
 
-       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);
+       iter = blkid_dev_iterate_begin(cache);
+       if (!iter) {
+               _E("Failed to get iterate"); //LCOV_EXCL_LINE
+               *mounted = STORAGE_PART_ERROR; //LCOV_EXCL_LINE
+               return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
+       }
+
+       ret_val = blkid_dev_set_search(iter, "LABEL", user_label);
+       if (blkid_dev_next(iter, &dev) == 0) {
+               dev = blkid_verify(cache, dev);
+               if (dev) {
+                       found = true;
+                       _D("Partition for user data is found(LABEL=%s)", user_label);
+               }
+       }
+       blkid_dev_iterate_end(iter);
 
-       g_variant_unref(result);
+       if (!found) {
+               iter = blkid_dev_iterate_begin(cache);
+               if (!iter) {
+                       _E("Failed to get iterate"); //LCOV_EXCL_LINE
+                       *mounted = STORAGE_PART_ERROR; //LCOV_EXCL_LINE
+                       return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
+               }
 
-       if (info.storage_id < 0)
-               return STORAGE_ERROR_NO_DEVICE;
+               ret_val = blkid_dev_set_search(iter, "PARTLABEL", user_label);
+               if (blkid_dev_next(iter, &dev) == 0) {
+                       dev = blkid_verify(cache, dev);
+                       if (dev) {
+                               found = true;
+                               _D("Partition for user data is found(PARTLABEL=%s)", user_label);
+                       }
+               }
+               blkid_dev_iterate_end(iter);
+       }
 
-       *path = strdup(info.mount_point);
-       if (*path == NULL)
-               return STORAGE_ERROR_OUT_OF_MEMORY;
+       blkid_put_cache(cache);
 
-       *storage_id = info.storage_id;
+       if (found) {
+               ret_val = mount_check(tzplatform_getenv(TZ_SYS_USER));
+               if (ret_val)
+                       *mounted = STORAGE_PART_MOUNTED;
+               else
+                       *mounted = STORAGE_PART_NOT_MOUNTED;
+       } else
+               *mounted = STORAGE_PART_NOT_SUPPORTED;
 
        return STORAGE_ERROR_NONE;
 }