BLOCK_DEV_REMOVE,
};
+enum private_operation_state {
+ REQ_NORMAL,
+ REQ_PRIVATE,
+ REQ_PRIVATE_FORMAT,
+};
+
struct operation_queue {
enum block_dev_operation op;
DBusMessage *msg;
dd_list *op_queue;
int thread_id; /* Current thread ID */
bool removed; /* True when device is physically removed but operation is not precessed yet */
+ enum private_operation_state on_private_op;
+ bool mount_point_updated;
+ pid_t private_pid;
};
struct format_data {
const char *fs_type,
const char *fs_version,
const char *fs_uuid_enc,
- const char *readonly)
+ const char *readonly,
+ bool mount_point_updated)
{
if (!data)
return -EINVAL;
/* generate_mount_path function should be invoked
* after fs_uuid_enc is updated */
- free(data->mount_point);
- data->mount_point = generate_mount_path(data);
+ if (!mount_point_updated) {
+ free(data->mount_point);
+ data->mount_point = generate_mount_path(data);
+ }
data->readonly = false;
if (readonly)
bdev->data = data;
bdev->thread_id = -1;
bdev->removed = false;
+ bdev->on_private_op = REQ_NORMAL;
+ bdev->private_pid = 0;
+ bdev->mount_point_updated = false;
return bdev;
}
broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
/* Broadcast outside with Block iface */
- signal_device_changed(pdata.bdev, pdata.op);
+ if (pdata.bdev->on_private_op == REQ_NORMAL)
+ signal_device_changed(pdata.bdev, pdata.op);
+ else if (pdata.bdev->on_private_op == REQ_PRIVATE) {
+ if (pdata.op == BLOCK_DEV_UNMOUNT) {
+ pdata.bdev->on_private_op = REQ_NORMAL;
+ _D("Private operation state: %d", pdata.bdev->on_private_op);
+ }
+ } else {
+ if (pdata.op == BLOCK_DEV_MOUNT) {
+ pdata.bdev->on_private_op = REQ_PRIVATE;
+ _D("Private operation state: %d", pdata.bdev->on_private_op);
+ }
+ }
if (pdata.op == BLOCK_DEV_REMOVE) {
thread_id = pdata.bdev->thread_id;
return true;
}
-static int retrieve_udev_device(struct block_data *data)
+static int retrieve_udev_device(struct block_data *data, bool mount_point_updated)
{
struct udev *udev;
struct udev_device *dev;
udev_device_get_property_value(dev, "ID_FS_TYPE"),
udev_device_get_property_value(dev, "ID_FS_VERSION"),
udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
- udev_device_get_sysattr_value(dev, "ro"));
+ udev_device_get_sysattr_value(dev, "ro"),
+ mount_point_updated);
if (r < 0)
_E("fail to update block data for %s", data->devnode);
/* If the mount path already exists, the path cannot be used */
if (mount_point &&
- access(mount_point, F_OK) != 0)
+ access(mount_point, F_OK) != 0) {
data->mount_point = strdup(mount_point);
- else
+ bdev->mount_point_updated = true;
+ } else {
data->mount_point = generate_mount_path(data);
+ bdev->mount_point_updated = false;
+ }
return 0;
}
}
static int block_format(struct block_data *data,
- const char *fs_type)
+ const char *fs_type, bool mount_point_updated)
{
const struct block_fs_ops *fs;
dd_list *elem;
/* need to update the partition data.
* It can be changed in doing format. */
- retrieve_udev_device(data);
+ retrieve_udev_device(data, mount_point_updated);
out:
return r;
}
}
- r = block_format(data, fs_type);
+ r = block_format(data, fs_type, bdev->mount_point_updated);
if (r < 0)
_E("fail to format %s device : %d", data->devnode, r);
if (!bdev)
return -EINVAL;
+
_D("Add operation (%s, %s)",
get_operation_char(operation, name, sizeof(name)),
bdev->data->devnode);
BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
bdev->removed = true;
+ if (bdev->on_private_op) {
+ bdev->on_private_op = REQ_NORMAL;
+ _D("Private operation state: %d", bdev->on_private_op);
+ }
+
ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
if (ret < 0) {
_E("Failed to add operation (unmount %s)", devnode);
}
static DBusMessage *request_mount_block(E_DBus_Object *obj,
- DBusMessage *msg)
+ DBusMessage *msg, bool onprivate)
{
struct block_device *bdev;
char *mount_point;
DBUS_TYPE_INVALID);
if (!ret)
goto out;
+
bdev = find_block_device_by_id(id);
if (!bdev) {
_E("Failed to find (%d) in the device list", id);
ret = -ENOENT;
goto out;
}
+ if (bdev->on_private_op != REQ_NORMAL) {
+ ret = -EPERM;
+ goto out;
+ }
if (bdev->data->state == BLOCK_MOUNT) {
_I("%s is already mounted", bdev->data->devnode);
goto out;
}
+ if (onprivate) {
+ bdev->on_private_op = REQ_PRIVATE;
+ bdev->private_pid = get_edbus_sender_pid(msg);
+ _D("Private operation state: %d", bdev->on_private_op);
+ } else {
+ if (bdev->on_private_op != REQ_NORMAL) {
+ _E("Failed to process mount operation");
+ ret = -EPERM;
+ goto out;
+ }
+ }
+
/* if requester want to use a specific mount point */
if (mount_point && strncmp(mount_point, "", 1) != 0) {
ret = change_mount_point(bdev, mount_point);
return make_reply_message(msg, ret);
}
-static DBusMessage *request_unmount_block(E_DBus_Object *obj,
+static DBusMessage *request_public_mount_block(E_DBus_Object *obj,
DBusMessage *msg)
{
+ return request_mount_block(obj, msg, false);
+}
+
+static DBusMessage *request_private_mount_block(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ return request_mount_block(obj, msg, true);
+}
+
+static DBusMessage *request_unmount_block(E_DBus_Object *obj,
+ DBusMessage *msg, bool onprivate)
+{
struct block_device *bdev;
+ pid_t pid;
long option;
int id;
int ret = -EBADMSG;
DBUS_TYPE_INVALID);
if (!ret)
goto out;
+
bdev = find_block_device_by_id(id);
if (!bdev) {
_E("Failed to find (%d) in the device list", id);
goto out;
}
+ if (onprivate) {
+ pid = get_edbus_sender_pid(msg);
+ if (bdev->on_private_op == REQ_NORMAL || (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid)) {
+ _E("Failed to process private unmount operation");
+ ret = -EPERM;
+ goto out;
+ }
+ } else {
+ if (bdev->on_private_op != REQ_NORMAL) {
+ _E("Failed to process unmount operation");
+ ret = -EPERM;
+ goto out;
+ }
+ }
+
ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, msg, (void *)option);
if (ret < 0) {
_E("Failed to add operation (unmount %s)", bdev->data->devnode);
return make_reply_message(msg, ret);
}
+static DBusMessage *request_public_unmount_block(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ return request_unmount_block(obj, msg, false);
+}
+
+static DBusMessage *request_private_unmount_block(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ return request_unmount_block(obj, msg, true);
+}
+
static DBusMessage *request_format_block(E_DBus_Object *obj,
DBusMessage *msg)
{
struct block_device *bdev;
struct format_data *fdata;
+ pid_t pid;
int id;
int option;
int ret = -EBADMSG;
DBUS_TYPE_INVALID);
if (!ret)
goto out;
+
bdev = find_block_device_by_id(id);
if (!bdev) {
_E("Failed to find (%d) in the device list", id);
goto out;
}
+ pid = get_edbus_sender_pid(msg);
+ if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
+ _E("Failed to format on private state");
+ ret = -EPERM;
+ goto out;
+ }
fdata = get_format_data(NULL, option);
if (!fdata) {
goto out;
}
- prev_state = bdev->data->state;
+ prev_state = bdev->data->state;
if (prev_state == BLOCK_MOUNT) {
+ if (bdev->on_private_op == REQ_PRIVATE) {
+ bdev->on_private_op = REQ_PRIVATE_FORMAT;
+ _D("Private operation state: %d", bdev->on_private_op);
+ }
ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
if (ret < 0) {
_E("Failed to add operation (unmount %s)", bdev->data->devnode);
{ "ShowDeviceList", NULL, NULL, request_show_device_list },
{ "GetDeviceList" , "s", "a(issssssisibii)", request_get_device_list },
{ "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
- { "Mount", "is", "i", request_mount_block },
- { "Unmount", "ii", "i", request_unmount_block },
+ { "Mount", "is", "i", request_public_mount_block },
+ { "Unmount", "ii", "i", request_public_unmount_block },
{ "Format", "ii", "i", request_format_block },
{ "GetDeviceInfo", "i", "(issssssisibii)", request_get_device_info },
{ "GetMmcPrimary" , NULL, "(issssssisibii)" , request_get_mmc_primary },
+ { "PrivateMount", "is", "i", request_private_mount_block },
+ { "PrivateUnmount", "ii", "i", request_private_unmount_block },
};
static int load_config(struct parse_result *result, void *user_data)