*/
+#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;
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()) {
+ //LCOV_EXCL_START System Error
_E("No compat bind mount");
return -1;
+ //LCOV_EXCL_STOP
}
- str = tzplatform_getenv(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 + str_len);
+ 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)
{
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()) {
+ //LCOV_EXCL_START System Error
_E("no compat bind mount");
return -1;
+ //LCOV_EXCL_STOP
}
compat_len = strlen(COMPAT_DIR);
return -1;
}
- r = snprintf(origin, len, "%s/%s", tzplatform_getenv(TZ_USER_CONTENT), compat + compat_len);
+ 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;
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;
}