4 * Copyright (c) 2012 - 2015 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.
27 #include <sys/mount.h>
28 #include <sys/statvfs.h>
32 #include <sys/statfs.h>
39 #include <tzplatform_config.h>
40 #include <app2ext_interface.h>
42 #include <blkid/blkid.h>
45 #include <glib/gstdio.h>
47 #include <libsyscommon/dbus-system.h>
50 #include "config-parser.h"
51 #include "module-intf.h"
55 #include "fd_handler.h"
58 #include "storaged_common.h"
61 * TODO Assume root device is always mmcblk0*.
63 #define MMC_PATH "*/mmcblk[0-9]*"
64 #define MMC_PARTITION_PATH "mmcblk[0-9]p[0-9]"
65 /* Emulator send devlink for sdcard as \*\/sdcard\/\* */
66 #define MMC_LINK_PATH "*/sdcard/*"
67 #define SCSI_PATH "*/sd[a-z]*"
68 #define SCSI_PARTITION_PATH "sd[a-z][0-9]"
69 #define SCSI_PARTITION_LENGTH 9
70 #define EXTENDEDSD_NODE_PATH "/dev/mapper/extendedsd"
72 #define FILESYSTEM_NAME "filesystem"
74 #define DEV_PREFIX "/dev/"
77 #define UNMOUNT_RETRY 5
78 #define TIMEOUT_MAKE_OBJECT 500 /* milliseconds */
80 #define SIGNAL_POWEROFF_STATE "ChangeState"
81 #define METHOD_ADD_POWEROFF_WAIT "AddPowerOffWait"
82 #define METHOD_REMOVE_POWEROFF_WAIT "RemovePowerOffWait"
84 #define BLOCK_DEVICE_ADDED "DeviceAdded"
85 #define BLOCK_DEVICE_REMOVED "DeviceRemoved"
86 #define BLOCK_DEVICE_BLOCKED "DeviceBlocked"
87 #define BLOCK_DEVICE_CHANGED "DeviceChanged"
89 #define BLOCK_TYPE_MMC "mmc"
90 #define BLOCK_TYPE_SCSI "scsi"
91 #define BLOCK_TYPE_ALL "all"
93 #define BLOCK_MMC_NODE_PREFIX "SDCard"
94 #define BLOCK_SCSI_NODE_PREFIX "USBDrive"
96 #define BLOCK_CONF_FILE "/etc/storaged/block.conf"
98 #define EXTERNAL_STORAGE_PATH "/run/storaged/external-storage"
99 #define EXTENDED_INTERNAL_PATH "/run/storaged/extended-internal-sd"
102 #define EXTENDEDSD_MOUNT_PATH "/opt/extendedsd"
104 #define VFAT_NAME "vfat"
105 #define EXFAT_NAME "exfat"
106 #define EXT4_NAME "ext4"
107 #define LUKS_NAME "crypto_LUKS"
108 #define EXTENDEDSD_NAME "extendedsd"
110 /* Minimum value of block id */
111 #define BLOCK_ID_MIN 10
112 /* For 2.4 Backward Compatibility */
113 #define EXT_PRIMARY_SD_FIXID 1
115 /* Maximum number of thread */
118 #define SPEEDCHECK_SIZE 16
119 #define SPEEDCHECK_CRITERION 4 /* MB/s */
121 #define PKGDIR_BUS_NAME "org.tizen.pkgdir_tool"
122 #define PKGDIR_PATH "/org/tizen/pkgdir_tool"
123 #define PKGDIR_INTERFACE "org.tizen.pkgdir_tool"
125 #define POPUP_KEY_CONTENT "_SYSPOPUP_CONTENT_"
126 #define VIEWTYPE_KEY "viewtype"
127 #define DEVPATH_KEY "dev_path"
128 #define MAPPING_NODE_KEY "mapping_node"
129 #define INSERT_SD_CARD "INSERT_SD_CARD"
131 #define MMC_POPUP_NOTI "SDcardNoti"
132 #define MMC_INSERTED "inserted"
133 #define MMC_REMOVED "removed"
135 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
137 #define FILE_NAME_LEN_MAX 255
139 enum block_dev_operation {
148 enum private_operation_state {
154 struct operation_queue {
155 enum block_dev_operation op;
156 GDBusMethodInvocation *invocation;
161 struct block_device {
162 struct block_data *data;
164 int thread_id; /* Current thread ID */
165 bool removed; /* True when device is physically removed but operation is not precessed yet */
166 enum private_operation_state on_private_op;
167 bool mount_point_updated;
172 struct block_device *bdev;
174 enum unmount_operation option;
178 enum block_dev_operation op;
179 struct block_device *bdev;
183 static struct block_conf {
185 bool extendedinternal;
186 } block_conf[BLOCK_EXTENDEDSD_DEV + 1];
188 static struct manage_thread {
189 dd_list *th_node_list; /* List of devnode which thread dealt with. Only main thread access */
190 dd_list *block_dev_list; /* Use thread mutex */
192 pthread_mutex_t mutex;
194 int num_dev; /* Number of devices which thread holds. Only main thread access */
195 int op_len; /* Number of operation of thread. Use thread mutex */
196 int thread_id; /* Never changed */
198 } th_manager[THREAD_MAX];
200 char mmc_default_path[][FILE_NAME_LEN_MAX + 1] = {
207 #define DIR_NUM ((int)(sizeof(mmc_default_path)/sizeof(mmc_default_path[0])))
209 static dd_list *fs_head;
210 static dd_list *block_ops_list;
213 static fd_handler_h phandler;
214 static bool block_control = false;
215 static bool block_boot = false;
216 static pthread_mutex_t pipe_mutex = PTHREAD_MUTEX_INITIALIZER;
217 static bool add_poweroff_wait = false;
219 /* Assume there is only one physical internal storage */
220 static int dev_internal = -1;
221 static char dev_internal_scsi = '\0';
222 static char dev_internal_emul = '\0';
224 static int block_start(void *data);
225 static int block_stop(void *data);
227 static int add_operation(struct block_device *bdev,
228 enum block_dev_operation operation,
229 GDBusMethodInvocation *invocation, void *data);
230 static void remove_operation(struct block_device *bdev);
231 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
232 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
233 static int change_mount_point(struct block_device *bdev, const char *mount_point);
234 static void terminate_threads(void);
236 #define nullstr(x) (x ? x : "")
237 static GVariant *block_data_to_gvariant(struct block_data *data, int flags);
239 #define block_send_dbus_reply(invocation, result) if (invocation) {g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", result)); }
241 static void uevent_block_handler(struct udev_device *dev);
242 static struct uevent_handler uh = {
243 .subsystem = BLOCK_SUBSYSTEM,
244 .uevent_func = uevent_block_handler,
247 static void __CONSTRUCTOR__ smack_check(void)
252 fp = fopen("/proc/filesystems", "r");
256 while (fgets(buf, sizeof(buf), fp) != NULL) {
257 if (strstr(buf, "smackfs")) {
266 void add_fs(const struct block_fs_ops *fs)
268 DD_LIST_APPEND(fs_head, (void *)fs);
271 void remove_fs(const struct block_fs_ops *fs)
273 DD_LIST_REMOVE(fs_head, (void *)fs);
276 const struct block_fs_ops *find_fs(enum block_fs_type type)
278 struct block_fs_ops *fs;
281 DD_LIST_FOREACH(fs_head, elem, fs) {
282 if (fs->type == type)
288 void add_block_dev(const struct block_dev_ops *ops)
290 DD_LIST_APPEND(block_ops_list, (void *)ops);
293 void remove_block_dev(const struct block_dev_ops *ops)
295 DD_LIST_REMOVE(block_ops_list, (void *)ops);
298 static void broadcast_block_info(enum block_dev_operation op,
299 struct block_data *data, int result)
301 struct block_dev_ops *ops;
304 if (data->primary != true)
307 DD_LIST_FOREACH(block_ops_list, elem, ops) {
308 int data_block_type = (data->block_type == BLOCK_EXTENDEDSD_DEV)
309 ? BLOCK_MMC_DEV : data->block_type;
311 if (ops->block_type != data_block_type)
313 // TODO What happend on extended internal storage case?
314 if (op == BLOCK_DEV_MOUNT) {
315 ops->mounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
316 } else if (op == BLOCK_DEV_UNMOUNT) {
317 ops->unmounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
318 } else if (op == BLOCK_DEV_FORMAT) {
319 ops->formatted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
320 } else if (op == BLOCK_DEV_INSERT)
322 else if (op == BLOCK_DEV_REMOVE)
327 // Called by MainThread - Insert
328 static int block_get_new_id(void)
330 static int id = BLOCK_ID_MIN;
331 struct block_device *bdev;
336 for (i = 0 ; i < INT_MAX ; i++) {
338 for (j = 0; j < THREAD_MAX; j++) {
339 pthread_mutex_lock(&(th_manager[j].mutex));
340 DD_LIST_FOREACH(th_manager[j].block_dev_list, elem, bdev) {
341 if (bdev->data->id == id) {
346 pthread_mutex_unlock(&(th_manager[j].mutex));
361 static void remove_file(int id, bool extendedsd)
363 char file_name[PATH_LEN];
370 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
372 snprintf(file_name, sizeof(file_name), EXTERNAL_STORAGE_PATH"/%d", id);
374 ret = remove(file_name);
376 _E("Failed to remove '%s': %d", file_name, errno);
379 static void create_file(int id, char *mount_point, bool extendedsd)
382 char file_name[PATH_LEN];
388 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
390 snprintf(file_name, PATH_LEN, EXTERNAL_STORAGE_PATH"/%d", id);
392 fp = fopen(file_name, "w+");
394 fprintf(fp, "%s", mount_point);
397 _E("Failed to open '%s'.", file_name);
400 static void broadcast_device_blocked(struct block_device *bdev)
402 struct block_data *data;
405 if (!bdev || !bdev->data)
410 ret = dbus_handle_emit_dbus_signal(NULL,
411 STORAGED_PATH_BLOCK_MANAGER,
412 STORAGED_INTERFACE_BLOCK_MANAGER,
413 BLOCK_DEVICE_BLOCKED,
414 block_data_to_gvariant(data, 0));
416 _E("Failed to send dbus signal");
419 static void broadcast_device_changed(struct block_device *bdev,
420 enum block_dev_operation op)
422 struct block_data *data;
423 GVariant *param = NULL;
424 const char *signal_name = NULL;
428 if (!bdev || !bdev->data) {
429 _E("Failed to broadcast device changed signal. op(%d)", op);
435 /* set flags and signal name */
437 case BLOCK_DEV_MOUNT:
438 BLOCK_GET_MOUNT_FLAGS(data, flags);
439 signal_name = BLOCK_DEVICE_CHANGED;
441 case BLOCK_DEV_UNMOUNT:
442 BLOCK_GET_UNMOUNT_FLAGS(data, flags);
443 signal_name = BLOCK_DEVICE_CHANGED;
445 case BLOCK_DEV_FORMAT:
446 BLOCK_GET_FORMAT_FLAGS(data, flags);
447 signal_name = BLOCK_DEVICE_CHANGED;
449 case BLOCK_DEV_INSERT:
451 signal_name = BLOCK_DEVICE_ADDED;
453 case BLOCK_DEV_REMOVE:
455 signal_name = BLOCK_DEVICE_REMOVED;
459 _E("Failed to broadcast device changed signal. op(%d)", op);
463 /* Broadcast outside with BlockManager iface */
464 param = block_data_to_gvariant(data, flags);
466 ret = dbus_handle_emit_dbus_signal(NULL,
467 STORAGED_PATH_BLOCK_MANAGER,
468 STORAGED_INTERFACE_BLOCK_MANAGER,
472 _E("Failed to broadcast device changed signal. op(%d)", op);
475 static int get_mmc_mount_node(char *devnode, char *node, size_t len)
477 char *name = devnode;
478 int dev = -1, part = -1;
479 char emul[32] = { 0, };
486 sscanf(name, "mmcblk%dp%d", &dev, &part);
489 snprintf(node, len, "%s%c", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1);
491 snprintf(node, len, "%s%c%d", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1, part);
496 sscanf(name, "vd%31s", emul);
499 for (i = 0 ; i < strlen(emul) ; i++)
500 emul[i] = toupper(emul[i]);
501 snprintf(node, len, "%s%s", BLOCK_MMC_NODE_PREFIX, emul);
505 static int get_scsi_mount_node(char *devnode, char *node, size_t len)
513 snprintf(dev, sizeof(dev), "%s", devnode);
515 if (!strstr(dev, "sd"))
519 name += strlen("sd");
521 for (i = 0 ; i < strlen(name) ; i++)
522 name[i] = toupper(name[i]);
523 snprintf(node, len, "%s%s", BLOCK_SCSI_NODE_PREFIX, name);
528 static char *generate_mount_path(struct block_data *data)
531 char *name, node[64];
534 if (!data || !data->devnode || !data->fs_usage || (strcmp(data->fs_usage, FILESYSTEM_NAME) && strncmp(data->fs_usage, "crypto", strlen("crypto"))))
537 name = strrchr(data->devnode, '/');
542 switch (data->block_type) {
544 ret = get_mmc_mount_node(name, node, sizeof(node));
547 ret = get_scsi_mount_node(name, node, sizeof(node));
549 case BLOCK_EXTENDEDSD_DEV:
550 return strdup(EXTENDEDSD_MOUNT_PATH);
552 _E("Invalid block type(%d).", data->block_type);
558 str = tzplatform_mkpath(TZ_SYS_MEDIA, node);
564 _E("Invalid devnode(%s).", data->devnode ? data->devnode : "NULL");
568 static bool check_primary_partition(const char *devnode)
570 struct block_fs_ops *fs;
573 const char *filesystem = NULL;
583 if (fnmatch(MMC_LINK_PATH, devnode, 0) &&
584 fnmatch(MMC_PATH, devnode, 0) &&
585 fnmatch(SCSI_PATH, devnode, 0) &&
586 fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
589 temp = strrchr(devnode, '/');
592 if (fnmatch("/"SCSI_PARTITION_PATH, temp, 0) &&
593 fnmatch("/"MMC_PARTITION_PATH, temp, 0))
596 /* Emulator support only one partition */
600 snprintf(str, sizeof(str), "%s", devnode);
605 for (i = 1; i <= 9; ++i) {
606 if ((ret = snprintf(str2, sizeof(str2), "%s%d", str, i)) > sizeof(str2) - 1) {
607 _E("Filename is longer than buffer. Need %d size of buffer.", ret + 1);
611 if (access(str2, R_OK) != 0)
614 probe = blkid_new_probe_from_filename(str2);
617 if (blkid_do_probe(probe) != 0)
620 ret = blkid_probe_lookup_value(probe, "TYPE", &filesystem, &fs_len);
622 blkid_free_probe(probe);
625 DD_LIST_FOREACH(fs_head, elem, fs) {
626 if (!strncmp(fs->name, filesystem, fs_len)) {
631 blkid_free_probe(probe);
637 if (found && !strncmp(devnode, str2, strlen(str2) + 1))
643 /* Whole data in struct block_data should be freed. */
644 static struct block_data *make_block_data(const char *devnode,
646 const char *fs_usage,
648 const char *fs_version,
649 const char *fs_uuid_enc,
650 const char *readonly)
652 struct block_data *data;
654 /* devnode is unique value so it should exist. */
659 _I("Unknown fs type.");
661 data = calloc(1, sizeof(struct block_data));
663 _E("Failed to calloc().");
667 data->devnode = strdup(devnode);
669 data->syspath = strdup(syspath);
671 data->fs_usage = strdup(fs_usage);
673 data->fs_type = strdup(fs_type);
675 data->fs_version = strdup(fs_version);
677 data->fs_uuid_enc = strdup(fs_uuid_enc);
679 data->readonly = atoi(readonly);
680 data->primary = check_primary_partition(devnode);
682 /* TODO should we know block dev type? */
683 if (!fnmatch(MMC_LINK_PATH, devnode, 0))
684 data->block_type = BLOCK_MMC_DEV;
685 else if (!fnmatch(MMC_PATH, devnode, 0))
686 data->block_type = BLOCK_MMC_DEV;
687 else if (!fnmatch(SCSI_PATH, devnode, 0))
688 data->block_type = BLOCK_SCSI_DEV;
689 else if (!fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
690 data->block_type = BLOCK_EXTENDEDSD_DEV;
692 data->block_type = -1;
694 data->mount_point = generate_mount_path(data);
695 BLOCK_FLAG_CLEAR_ALL(data);
697 /* for 2.4 backward compatibility */
698 // What if storage id 1 is existed? (multi sdcard case)
699 if (data->primary == true && data->block_type == BLOCK_MMC_DEV &&
700 data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME))
701 data->id = EXT_PRIMARY_SD_FIXID;
703 data->id = block_get_new_id();
708 static void free_block_data(struct block_data *data)
714 free(data->fs_usage);
716 free(data->fs_version);
717 free(data->fs_uuid_enc);
718 free(data->mount_point);
722 static int update_block_data(struct block_data *data,
723 const char *fs_usage,
725 const char *fs_version,
726 const char *fs_uuid_enc,
727 const char *readonly,
728 bool mount_point_updated)
733 free(data->fs_usage);
734 data->fs_usage = NULL;
736 data->fs_usage = strdup(fs_usage);
739 data->fs_type = NULL;
741 data->fs_type = strdup(fs_type);
743 free(data->fs_version);
744 data->fs_version = NULL;
746 data->fs_version = strdup(fs_version);
748 free(data->fs_uuid_enc);
749 data->fs_uuid_enc = NULL;
751 data->fs_uuid_enc = strdup(fs_uuid_enc);
753 /* generate_mount_path function should be invoked
754 * after fs_uuid_enc is updated */
755 if (!mount_point_updated) {
756 free(data->mount_point);
757 data->mount_point = generate_mount_path(data);
760 data->readonly = false;
762 data->readonly = atoi(readonly);
764 BLOCK_FLAG_MOUNT_CLEAR(data);
769 static struct block_device *make_block_device(struct block_data *data)
771 struct block_device *bdev;
776 bdev = calloc(1, sizeof(struct block_device));
781 bdev->thread_id = -1;
782 bdev->removed = false;
783 bdev->on_private_op = REQ_NORMAL;
784 bdev->private_pid = 0;
785 bdev->mount_point_updated = false;
790 // Called by MainThread - Remove DevNode
791 static void free_block_device(struct block_device *bdev)
794 struct operation_queue *op;
800 thread_id = bdev->thread_id;
801 if (thread_id < 0 || thread_id >= THREAD_MAX)
804 pthread_mutex_lock(&(th_manager[thread_id].mutex));
806 th_manager[thread_id].num_dev--;
807 DD_LIST_REMOVE(th_manager[thread_id].block_dev_list, bdev);
808 free_block_data(bdev->data);
810 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
812 th_manager[thread_id].op_len--;
813 DD_LIST_REMOVE(bdev->op_queue, op);
816 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
821 // Called By MainThread - Remove Device
822 static struct block_device *find_block_device(const char *devnode)
824 struct block_device *bdev;
829 len = strlen(devnode) + 1;
830 for (i = 0; i < THREAD_MAX; i++) {
831 pthread_mutex_lock(&(th_manager[i].mutex));
832 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
833 if (bdev->data && !bdev->removed &&
834 !strncmp(bdev->data->devnode, devnode, len)) {
835 pthread_mutex_unlock(&(th_manager[i].mutex));
839 pthread_mutex_unlock(&(th_manager[i].mutex));
845 // Called By MainThread - Remove Device
846 static struct block_device *find_block_device_path(const char *mount_point)
848 struct block_device *bdev;
853 len = strlen(mount_point) + 1;
854 for (i = 0; i < THREAD_MAX; i++) {
855 pthread_mutex_lock(&(th_manager[i].mutex));
856 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
857 if (bdev->data && !bdev->removed &&
858 (bdev->data->mount_point != NULL && !strncmp(bdev->data->mount_point, mount_point, len))) {
859 pthread_mutex_unlock(&(th_manager[i].mutex));
863 pthread_mutex_unlock(&(th_manager[i].mutex));
869 // Called By MainThread - Mount,Unmount,Format,GetInfo
870 static struct block_device *find_block_device_by_id(int id)
872 struct block_device *bdev;
876 for (i = 0; i < THREAD_MAX; i++) {
877 pthread_mutex_lock(&(th_manager[i].mutex));
878 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
883 if (bdev->data->id == id) {
884 pthread_mutex_unlock(&(th_manager[i].mutex));
888 pthread_mutex_unlock(&(th_manager[i].mutex));
894 static const char *get_operation_char(enum block_dev_operation op)
897 case BLOCK_DEV_MOUNT:
900 case BLOCK_DEV_UNMOUNT:
903 case BLOCK_DEV_FORMAT:
906 case BLOCK_DEV_INSERT:
909 case BLOCK_DEV_REMOVE:
912 case BLOCK_LUKS_CLOSE:
916 _E("Invalid operation(%d).", op);
920 void mmc_make_default_path(const char *mount_path)
924 char mmc_path[FILE_NAME_LEN_MAX + 1] = {0, };
926 for (i = 0; i < DIR_NUM; ++i) {
927 if ((ret = snprintf(mmc_path, sizeof(mmc_path), "%s/%s", mount_path, mmc_default_path[i])) > sizeof(mmc_path) - 1) {
928 _E("Path is longer than buffer. Need %d size of buffer.", ret + 1);
932 if (!g_file_test(mmc_path, G_FILE_TEST_IS_DIR)) {
933 _D("Path(%s) did not exist.", mmc_path);
934 ret = mkdir(mmc_path, 0777);
936 _E("Failed to mkdir: %d", errno);
938 /*this fuction for emulator*/
939 /*at the first time, the directroies are made permission 755*/
940 ret = chmod(mmc_path, 0777);
942 _E("Failed to chmod: %d", errno);
944 ret = chown(mmc_path, 0, 10001);
946 _E("Failed to chown: %d", errno);
951 static void create_external_apps_directory(void)
955 ret = dbus_handle_method_async(PKGDIR_BUS_NAME, PKGDIR_PATH,
956 PKGDIR_INTERFACE, "CreateExternalDirsForAllPkgs", NULL, NULL);
958 _E("Failed to create external directory.");
961 static int pipe_trigger(enum block_dev_operation op,
962 struct block_device *bdev, int result)
964 struct pipe_data pdata = { op, bdev, result };
967 _D("op=%s bdev=%p result=%d",
968 get_operation_char(pdata.op),
969 pdata.bdev, pdata.result);
971 // Multi thread should not write at the same time
972 pthread_mutex_lock(&pipe_mutex);
973 n = write(pfds[1], &pdata, sizeof(struct pipe_data));
974 pthread_mutex_unlock(&pipe_mutex);
976 return (n != sizeof(struct pipe_data)) ? -EPERM : 0;
979 static bool pipe_cb(int fd, void *data)
981 struct pipe_data pdata = {0,};
986 n = read(fd, &pdata, sizeof(pdata));
987 if (n != sizeof(pdata) || !pdata.bdev) {
988 _E("Failed to read struct pipe data.");
992 _I("op=%s bdev=%p result=%d",
993 get_operation_char(pdata.op),
994 pdata.bdev, pdata.result);
996 if (pdata.op == BLOCK_LUKS_CLOSE)
999 if (pdata.op == BLOCK_DEV_MOUNT && pdata.result < 0) {
1000 if (pdata.bdev->data->state == BLOCK_UNMOUNT) {
1001 ret = change_mount_point(pdata.bdev, "");
1002 /* Modify /run/external-storage/id file */
1004 if (pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV)
1005 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, true);
1007 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, false);
1013 if (pdata.op == BLOCK_DEV_MOUNT && (pdata.result == 0)) {
1014 /* Create file for block device /run/external-storage/id */
1015 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
1018 if (pdata.op == BLOCK_DEV_MOUNT &&
1019 pdata.bdev->data->state == BLOCK_MOUNT &&
1020 pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
1021 pdata.bdev->data->primary) {
1022 create_external_apps_directory();
1023 mmc_make_default_path(pdata.bdev->data->mount_point);
1025 ret = dbus_handle_method_sync_var(POPUP_BUS_NAME,
1027 POPUP_INTERFACE_NOTI,
1029 g_variant_new("(s)", MMC_INSERTED));
1031 _E("Failed to popup: %d", ret);
1034 if (pdata.op == BLOCK_DEV_UNMOUNT) {
1035 /* Remove file for block device /run/xxxxxx/id */
1036 remove_file(pdata.bdev->data->id, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
1038 if (pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
1039 pdata.bdev->data->primary &&
1040 BLOCK_IS_FLAG_SET(pdata.bdev->data, UNMOUNT_UNSAFE)) {
1042 ret = dbus_handle_method_sync_var(POPUP_BUS_NAME,
1044 POPUP_INTERFACE_NOTI,
1046 g_variant_new("(s)", MMC_REMOVED));
1048 _E("Failed to popup: %d", ret);
1052 /* Broadcast to mmc and usb storage module */
1053 broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
1055 /* Broadcast outside with Block iface */
1056 if (pdata.bdev->on_private_op == REQ_NORMAL)
1057 broadcast_device_changed(pdata.bdev, pdata.op);
1058 else if (pdata.bdev->on_private_op == REQ_PRIVATE) {
1059 if (pdata.op == BLOCK_DEV_UNMOUNT) {
1060 pdata.bdev->on_private_op = REQ_NORMAL;
1061 _D("Private operation state(%d).", pdata.bdev->on_private_op);
1064 if (pdata.op == BLOCK_DEV_MOUNT) {
1065 pdata.bdev->on_private_op = REQ_PRIVATE;
1066 _D("Private operation state(%d).", pdata.bdev->on_private_op);
1070 if (pdata.op == BLOCK_DEV_REMOVE) {
1071 thread_id = pdata.bdev->thread_id;
1072 if (thread_id < 0 || thread_id >= THREAD_MAX)
1074 free_block_device(pdata.bdev);
1081 static int pipe_init(void)
1085 ret = pipe2(pfds, O_CLOEXEC);
1089 ret = add_fd_read_handler(pfds[0], pipe_cb,
1090 NULL, NULL, &phandler);
1092 _E("Failed to add pipe handler: %d", ret);
1099 static void pipe_exit(void)
1102 remove_fd_read_handler(&phandler);
1112 static int mmc_check_and_unmount(const char *path)
1120 while (mount_check(path)) {
1124 if (retry > UNMOUNT_RETRY)
1131 static bool check_rw_mount(const char *szPath)
1133 struct statvfs mount_stat;
1135 if (!statvfs(szPath, &mount_stat)) {
1136 if ((mount_stat.f_flag & ST_RDONLY) == ST_RDONLY)
1142 static int retrieve_udev_device(struct block_data *data, bool mount_point_updated)
1145 struct udev_device *dev;
1146 const char *fs_type;
1147 const char *fs_usage;
1154 for (wait = 0; wait < 10; wait++) {
1157 _E("Failed to create udev library context.");
1161 dev = udev_device_new_from_syspath(udev, data->syspath);
1163 _E("Failed to create new udev device.");
1168 fs_type = udev_device_get_property_value(dev, "ID_FS_TYPE");
1169 fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE");
1170 /* fs_usage for crpto_LUKS is crypto */
1171 if (!fs_type || (strncmp(fs_type, VFAT_NAME, strlen(VFAT_NAME)) && strncmp(fs_type, EXT4_NAME, strlen(EXT4_NAME))))
1173 else if (!fs_usage || strncmp(FILESYSTEM_NAME, fs_usage, strlen(FILESYSTEM_NAME)))
1178 udev_device_unref(dev);
1182 r = update_block_data(data,
1183 udev_device_get_property_value(dev, "ID_FS_USAGE"),
1184 udev_device_get_property_value(dev, "ID_FS_TYPE"),
1185 udev_device_get_property_value(dev, "ID_FS_VERSION"),
1186 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
1187 udev_device_get_sysattr_value(dev, "ro"),
1188 mount_point_updated);
1190 _E("Failed to update block data for %s.", data->devnode);
1192 udev_device_unref(dev);
1197 static int block_mount(struct block_data *data)
1199 struct block_fs_ops *fs;
1204 if (!data || !data->devnode || !data->mount_point)
1207 /* check existing mounted */
1208 if (mount_check(data->mount_point))
1211 /* create mount point */
1212 if (access(data->mount_point, R_OK) != 0) {
1213 if (mkdir(data->mount_point, 0755) < 0)
1217 /* check matched file system */
1218 if (!data->fs_usage ||
1219 strncmp(data->fs_usage, FILESYSTEM_NAME,
1220 sizeof(FILESYSTEM_NAME)) != 0) {
1225 if (!data->fs_type) {
1226 _E("There is no file system.");
1227 BLOCK_FLAG_SET(data, FS_EMPTY);
1233 len = strlen(data->fs_type) + 1;
1234 DD_LIST_FOREACH(fs_head, elem, fs) {
1235 if (!strncmp(fs->name, data->fs_type, len))
1240 _E("Not supported file system(%s).", data->fs_type);
1241 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1246 if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1247 r = fs->mount(false, data->devnode, data->mount_point);
1249 r = fs->mount(smack, data->devnode, data->mount_point);
1252 BLOCK_FLAG_SET(data, FS_BROKEN);
1257 r = check_rw_mount(data->mount_point);
1264 rmdir(data->mount_point);
1268 static int mount_start(struct block_device *bdev)
1270 struct block_data *data;
1278 _I("Mount Start (%s -> %s).",
1279 data->devnode, data->mount_point);
1281 /* mount operation */
1282 r = block_mount(data);
1283 if (r != -EROFS && r < 0) {
1284 _E("Failed to mount device(%s): %d", data->devnode, r);
1289 data->readonly = true;
1290 BLOCK_FLAG_SET(data, MOUNT_READONLY);
1293 data->state = BLOCK_MOUNT;
1295 if (data->block_type == BLOCK_MMC_DEV) {
1296 /* app2ext_migrate_legacy_all has dbus method call to deviced */
1297 ret = app2ext_migrate_legacy_all();
1299 _E("Failed to app2ext.");
1303 if (r < 0 && r != -EROFS)
1304 data->state = BLOCK_UNMOUNT;
1306 _I("%s result=%s: %d", __func__, data->devnode, r);
1308 if (pipe_trigger(BLOCK_DEV_MOUNT, bdev, r) < 0)
1309 _E("Failed to trigger pipe.");
1314 static int change_mount_point(struct block_device *bdev,
1315 const char *mount_point)
1317 struct block_data *data;
1323 free(data->mount_point);
1325 /* If the mount path already exists, the path cannot be used */
1327 access(mount_point, F_OK) != 0) {
1328 data->mount_point = strdup(mount_point);
1329 bdev->mount_point_updated = true;
1331 data->mount_point = generate_mount_path(data);
1332 bdev->mount_point_updated = false;
1338 static int mount_block_device(struct block_device *bdev)
1340 struct block_data *data;
1343 if (!bdev || !bdev->data)
1347 if (data->state == BLOCK_MOUNT) {
1348 _I("%s is already mounted.", data->devnode);
1352 if (!block_conf[data->block_type].multimount &&
1354 _I("Not support multi mount by config info.");
1358 r = mount_start(bdev);
1360 _E("Failed to mount %s.", data->devnode);
1367 static int block_unmount(struct block_device *bdev,
1368 enum unmount_operation option)
1370 struct block_data *data;
1373 if (!bdev || !bdev->data || !bdev->data->mount_point)
1378 if (bdev->on_private_op == REQ_NORMAL)
1379 broadcast_device_blocked(bdev);
1381 /* it must called before unmounting mmc */
1382 r = mmc_check_and_unmount(data->mount_point);
1385 if (option == UNMOUNT_NORMAL) {
1386 _I("Failed to unmount with normal option: %d", r);
1390 _I("Execute force unmount.");
1391 /* Force Unmount Scenario */
1394 * should unmount the below vconf key. */
1395 if ((data->block_type == BLOCK_MMC_DEV ||
1396 data->block_type == BLOCK_EXTENDEDSD_DEV) &&
1398 /* At first, notify to other app who already access sdcard */
1399 _I("Notify to other app who already access sdcard.");
1400 vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS,
1401 VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
1403 /* Wait for 700 msec to release open files */
1409 if (umount2(data->mount_point, MNT_DETACH) != 0) {
1410 _I("Failed to unmount with lazy option: %m");
1414 while (retry++ < UNMOUNT_RETRY) {
1415 _I("Kill app with SIGTERM.");
1416 terminate_process(data->devnode, false);
1419 if (!is_in_use_partition(data->devnode))
1422 _I("Kill app with SIGKILL.");
1423 terminate_process(data->devnode, true);
1426 if (!is_in_use_partition(data->devnode))
1433 data->state = BLOCK_UNMOUNT;
1435 if (rmdir(data->mount_point) < 0)
1436 _E("Failed to remove '%s' directory.", data->mount_point);
1441 static int unmount_block_device(struct block_device *bdev,
1442 enum unmount_operation option)
1444 struct block_data *data;
1447 if (!bdev || !bdev->data)
1451 if (data->state == BLOCK_UNMOUNT) {
1452 _I("%s is already unmounted.", data->devnode);
1453 r = mmc_check_and_unmount(data->mount_point);
1455 _E("The path was existed, but could not delete it(%s).",
1460 _I("Unmount Start. '%s' -> '%s'.",
1461 data->devnode, data->mount_point);
1463 r = block_unmount(bdev, option);
1465 _E("Failed to unmount %s device: %d", data->devnode, r);
1469 BLOCK_FLAG_MOUNT_CLEAR(data);
1472 _I("%s result=%s: %d", __func__, data->devnode, r);
1474 if (pipe_trigger(BLOCK_DEV_UNMOUNT, bdev, r) < 0)
1475 _E("Failed to trigger pipe.");
1480 static int block_format(struct block_data *data,
1481 const char *fs_type, bool mount_point_updated)
1483 const struct block_fs_ops *fs;
1489 if (!data || !data->devnode || !data->mount_point)
1492 if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1498 fstype = data->fs_type;
1502 if (!strcmp(fstype, EXFAT_NAME))
1506 len = strlen(fstype);
1507 DD_LIST_FOREACH(fs_head, elem, fs) {
1508 if (!strncmp(fs->name, fstype, len))
1512 if (!fs || !fs->format) {
1513 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1514 _E("Not supported file system(%s).", fstype);
1518 _I("Format path=%s", data->devnode);
1519 r = fs->format(data->devnode);
1521 _E("Failed to format block data for %s.", data->devnode);
1525 /* need to update the partition data.
1526 * It can be changed in doing format. */
1527 retrieve_udev_device(data, mount_point_updated);
1532 static int format_block_device(struct block_device *bdev,
1533 const char *fs_type,
1534 enum unmount_operation option)
1536 struct block_data *data;
1544 _I("Format Start. '%s' -> '%s'.",
1545 data->devnode, data->mount_point);
1547 if (data->state == BLOCK_MOUNT) {
1548 r = block_unmount(bdev, option);
1550 _E("Failed to unmount %s device: %d", data->devnode, r);
1555 r = block_format(data, fs_type, bdev->mount_point_updated);
1557 _E("Failed to format %s device: %d", data->devnode, r);
1560 _I("%s result=%s: %d", __func__, data->devnode, r);
1562 r = pipe_trigger(BLOCK_DEV_FORMAT, bdev, r);
1564 _E("Failed to trigger pipe.");
1569 static struct format_data *get_format_data(
1570 const char *fs_type, enum unmount_operation option)
1572 struct format_data *fdata;
1574 fdata = (struct format_data *)malloc(sizeof(struct format_data));
1576 _E("Failed to allocate format data.");
1581 fdata->fs_type = strdup(fs_type);
1583 fdata->fs_type = NULL;
1584 fdata->option = option;
1589 static void release_format_data(struct format_data *data)
1593 free(data->fs_type);
1598 // Called by BlockThread - Real Mount Op
1599 static int block_mount_device(struct block_device *bdev, void *data)
1608 thread_id = bdev->thread_id;
1609 if (thread_id < 0 || thread_id >= THREAD_MAX)
1611 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1612 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1613 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1615 _E("'%s' does not exist in the device list.", bdev->data->devnode);
1619 /* mount automatically */
1620 ret = mount_block_device(bdev);
1622 _E("Failed to mount block device for %s.", bdev->data->devnode);
1627 // Called by BlockThread - Real Format Op
1628 static int block_format_device(struct block_device *bdev, void *data)
1633 struct format_data *fdata = (struct format_data *)data;
1635 if (!bdev || !fdata) {
1640 thread_id = bdev->thread_id;
1641 if (thread_id < 0 || thread_id >= THREAD_MAX)
1643 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1644 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1645 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1647 _E("'%s' does not exist in the device list.", bdev->data->devnode);
1652 ret = format_block_device(bdev, fdata->fs_type, fdata->option);
1654 _E("Failed to format block device for %s.", bdev->data->devnode);
1657 release_format_data(fdata);
1662 // Called by BlockThread - Real Unmount Op
1663 static int block_unmount_device(struct block_device *bdev, void *data)
1666 long option = (long)data;
1671 ret = unmount_block_device(bdev, option);
1673 _E("Failed to unmount block device(%s).", bdev->data->devnode);
1680 /* Called by BlockThread - Remove Operation
1681 Direct Call at BlockThread
1682 Previously this function was called by MainThread. However, it will increase complexity.
1683 Need thread lock before to call remove_operation
1685 static void remove_operation(struct block_device *bdev)
1687 struct operation_queue *op;
1693 thread_id = bdev->thread_id;
1694 if (thread_id < 0 || thread_id >= THREAD_MAX)
1697 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
1699 _D("Remove operation(%s, %s).",
1700 get_operation_char(op->op),
1701 bdev->data->devnode);
1703 DD_LIST_REMOVE(bdev->op_queue, op);
1709 // Called by BlockThread
1710 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1712 struct operation_queue *temp;
1725 thread_id = bdev->thread_id;
1726 if (thread_id < 0 || thread_id >= THREAD_MAX)
1729 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1731 DD_LIST_FOREACH(*queue, l, temp) {
1732 if (temp->op == BLOCK_DEV_REMOVE) {
1737 th_manager[thread_id].op_len--;
1738 block_send_dbus_reply((*op)->invocation, 0);
1741 remove_operation(bdev);
1742 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1745 // Called by BlockThread
1746 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1748 struct operation_queue *temp;
1751 bool unmounted = false;
1762 thread_id = bdev->thread_id;
1763 if (thread_id < 0 || thread_id >= THREAD_MAX)
1766 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1767 DD_LIST_FOREACH(*queue, l, temp) {
1768 if (temp->op == BLOCK_DEV_UNMOUNT) {
1770 _D("Operation queue has unmount operation.");
1774 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1779 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1781 DD_LIST_FOREACH(*queue, l, temp) {
1782 if (temp->op == BLOCK_DEV_UNMOUNT) {
1787 th_manager[thread_id].op_len--;
1788 block_send_dbus_reply((*op)->invocation, 0);
1791 remove_operation(bdev);
1792 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1797 // Called by BlockThread
1798 static void trigger_operation(struct block_device *bdev, dd_list *queue, struct operation_queue *op)
1802 char devnode[PATH_MAX];
1803 enum block_dev_operation operation;
1804 bool unmounted = false;
1811 thread_id = bdev->thread_id;
1812 if (thread_id < 0 || thread_id >= THREAD_MAX)
1815 snprintf(devnode, sizeof(devnode), "%s", bdev->data->devnode);
1825 _D("Thread id(%d) Trigger operation(%s, %s)", thread_id,
1826 get_operation_char(operation), devnode);
1829 if (operation == BLOCK_DEV_INSERT && bdev->removed) {
1830 check_removed(bdev, &queue, &op);
1832 _D("Trigger operation again(%s, %s).",
1833 get_operation_char(operation), devnode);
1835 if (operation == BLOCK_DEV_MOUNT) {
1836 unmounted = check_unmount(bdev, &queue, &op);
1839 _D("Trigger operation again(%s, %s).",
1840 get_operation_char(operation), devnode);
1844 switch (operation) {
1845 case BLOCK_DEV_INSERT:
1847 case BLOCK_DEV_MOUNT:
1848 ret = block_mount_device(bdev, op->data);
1849 _D("Mount '%s': %d", devnode, ret);
1851 case BLOCK_DEV_FORMAT:
1852 ret = block_format_device(bdev, op->data);
1853 _D("Format '%s': %d", devnode, ret);
1855 case BLOCK_DEV_UNMOUNT:
1856 ret = block_unmount_device(bdev, op->data);
1857 _D("Unmount '%s': %d", devnode, ret);
1859 case BLOCK_DEV_REMOVE:
1862 case BLOCK_LUKS_CLOSE:
1863 ret = ode_luks_close_sync(EXTENDEDSD_NAME);
1865 _E("Failed on ode_luks_close(%s).", EXTENDEDSD_NAME);
1868 _E("Operation type(%d) is invalid.", op->op);
1874 * during checking the queue length */
1875 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1878 th_manager[thread_id].op_len--;
1880 block_send_dbus_reply(op->invocation, ret);
1882 queue = bdev->op_queue;
1883 if (queue != NULL) {
1884 queue = DD_LIST_NEXT(queue);
1886 op = DD_LIST_NTH(queue, 0);
1892 remove_operation(bdev);
1894 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1897 if (operation == BLOCK_DEV_INSERT || operation == BLOCK_DEV_REMOVE || operation == BLOCK_LUKS_CLOSE) {
1898 if (pipe_trigger(operation, bdev, 0) < 0)
1899 _E("Failed to trigger pipe.");
1906 // Called by BlockThread
1907 static void *block_th_start(void *arg)
1909 struct block_device *temp;
1910 struct manage_thread *th = (struct manage_thread *)arg;
1911 struct operation_queue *op = NULL;
1913 dd_list *queue = NULL;
1918 thread_id = th->thread_id;
1919 if (thread_id < 0 || thread_id >= THREAD_MAX) {
1920 _E("Thread Number=%d.", th->thread_id);
1925 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1926 if (th_manager[thread_id].op_len == 0) {
1927 _D("Operation queue of thread is empty.");
1928 pthread_cond_wait(&(th_manager[thread_id].cond), &(th_manager[thread_id].mutex));
1929 _D("Wake up thread=%d.", thread_id);
1932 DD_LIST_FOREACH(th_manager[thread_id].block_dev_list, elem, temp) {
1933 queue = temp->op_queue;
1935 op = DD_LIST_NTH(queue, 0);
1937 _D("Operation queue for device %s is Empty.", temp->data->devnode);
1941 queue = DD_LIST_NEXT(queue);
1949 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1951 if (op && !op->done)
1952 trigger_operation(temp, queue, op);
1957 // This function will be refactored later
1958 // Especially, we don't need to keep th_node_list.
1959 static int find_thread(char *devnode)
1966 int i, len, min, min_num;
1967 int dev_mmc = -1, part = -1, num;
1970 if (!fnmatch("*/"MMC_PARTITION_PATH, devnode, 0)) {
1971 sscanf(devnode, "/dev/mmcblk%dp%d", &dev_mmc, &part);
1978 snprintf(str, len, "/dev/mmcblk%d", dev_mmc);
1979 th_node = strdup(str);
1980 } else if (!fnmatch("*/"SCSI_PARTITION_PATH, devnode, 0)) {
1981 sscanf(devnode, "/dev/sd%c%d", &dev_scsi, &part);
1982 snprintf(str, SCSI_PARTITION_LENGTH, "/dev/sd%c", dev_scsi);
1983 th_node = strdup(str);
1985 th_node = strdup(devnode);
1987 len = strlen(th_node) + 1;
1990 for (i = 0; i < THREAD_MAX; i++) {
1991 DD_LIST_FOREACH(th_manager[i].th_node_list, elem, temp) {
1992 if (!strncmp(temp, th_node, len)) {
1997 if (th_manager[i].num_dev < min_num) {
1998 min_num = th_manager[i].num_dev;
2003 if (min >= 0 && min < THREAD_MAX) {
2004 DD_LIST_APPEND(th_manager[min].th_node_list, th_node);
2008 _E("Failed to find thread.");
2009 DD_LIST_APPEND(th_manager[0].th_node_list, th_node);
2013 /* Only Main thread is permmited */
2014 // Called by MainThread
2015 static int add_operation(struct block_device *bdev,
2016 enum block_dev_operation operation,
2017 GDBusMethodInvocation *invocation, void *data)
2019 struct operation_queue *op;
2028 _I("Add operation(%s, %s).",
2029 get_operation_char(operation),
2030 bdev->data->devnode);
2032 thread_id = bdev->thread_id;
2033 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2034 _E("Failed to find thread to add.");
2038 op = (struct operation_queue *)malloc(sizeof(struct operation_queue));
2040 _E("Failed to malloc.");
2046 op->invocation = invocation;
2048 /* Need to disble app2ext whenever unmounting mmc */
2049 /* app2ext_disable_all_external_pkgs inside a critical section need to be avoided. */
2050 if (operation == BLOCK_DEV_UNMOUNT &&
2051 bdev->data->state == BLOCK_MOUNT &&
2052 bdev->data->block_type == BLOCK_MMC_DEV &&
2053 bdev->data->primary)
2054 if (app2ext_disable_all_external_pkgs() < 0)
2055 _E("Failed to app2ext_disable_all_external_pkgs().");
2058 * during adding queue and checking the queue length */
2059 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2061 /* Only modified between lock and unlock of mutex */
2064 start_th = th_manager[thread_id].start_th;
2065 DD_LIST_APPEND(bdev->op_queue, op);
2066 th_manager[thread_id].op_len++;
2068 if (th_manager[thread_id].op_len == 1 && start_th)
2069 pthread_cond_signal(&(th_manager[thread_id].cond));
2071 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2075 _D("Start new thread for block device.");
2076 th_manager[thread_id].start_th = true;
2077 ret = pthread_create(&(th_manager[thread_id].th), NULL, block_th_start, &th_manager[thread_id]);
2079 _E("Failed to create thread for %s.", bdev->data->devnode);
2083 pthread_detach(th_manager[thread_id].th);
2089 static bool disk_is_partitioned_by_kernel(struct udev_device *dev)
2092 struct dirent entry;
2094 const char *syspath;
2097 syspath = udev_device_get_syspath(dev);
2101 dp = opendir(syspath);
2103 _E("Failed to open '%s'.", syspath);
2107 /* TODO compare devname and d_name */
2108 while (readdir_r(dp, &entry, &dir) == 0 && dir != NULL) {
2109 if (!fnmatch(MMC_PARTITION_PATH, dir->d_name, 0) ||
2110 !fnmatch(SCSI_PARTITION_PATH, dir->d_name, 0)) {
2122 static bool check_partition(struct udev_device *dev)
2124 const char *devtype;
2125 const char *part_table_type;
2126 const char *fs_usage;
2129 /* only consider disk type, never partitions */
2130 devtype = udev_device_get_devtype(dev);
2134 if (strncmp(devtype, BLOCK_DEVTYPE_DISK,
2135 sizeof(BLOCK_DEVTYPE_DISK)) != 0)
2138 part_table_type = udev_device_get_property_value(dev,
2139 "ID_PART_TABLE_TYPE");
2140 if (part_table_type) {
2141 fs_usage = udev_device_get_property_value(dev,
2144 strncmp(fs_usage, FILESYSTEM_NAME, sizeof(FILESYSTEM_NAME)) == 0) {
2145 if (!disk_is_partitioned_by_kernel(dev))
2152 if (disk_is_partitioned_by_kernel(dev)) {
2161 // Called by MainThread
2162 static int add_block_device(struct udev_device *dev, const char *devnode, bool mapper)
2164 struct block_data *data;
2165 struct block_device *bdev;
2166 //char id_string[PATH_LEN];
2170 bool need_format = false;
2172 partition = check_partition(dev);
2174 /* if there is a partition, skip this request */
2175 _I("%s device has partitions, skip this time.", devnode);
2179 if (mapper && !udev_device_get_property_value(dev, "ID_FS_TYPE")) {
2180 char syspath[128] = {0};
2183 r = rindex(udev_device_get_syspath(dev), '/');
2184 if (!r) return -ENODEV;
2186 snprintf(syspath, sizeof(syspath), "/sys/block%s", r);
2188 data = make_block_data(devnode,
2193 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2194 udev_device_get_sysattr_value(dev, "ro"));
2197 data = make_block_data(devnode,
2198 udev_device_get_syspath(dev),
2199 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2200 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2201 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2202 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2203 udev_device_get_sysattr_value(dev, "ro"));
2207 _E("Failed to make block data for %s.", devnode);
2211 if (!block_conf[data->block_type].multimount && !data->primary &&
2212 data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME)) {
2213 _D("Not support multi mount by config info.");
2214 free_block_data(data);
2218 if (!block_control) {
2219 if (!mapper && strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2220 _D("Block module is disabled.");
2221 free_block_data(data);
2227 bdev = make_block_device(data);
2229 _E("Failed to make block device for %s.", devnode);
2230 free_block_data(data);
2234 thread_id = find_thread(bdev->data->devnode);
2235 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2236 _E("Failed to find thread to add.");
2237 free_block_device(bdev);
2240 bdev->thread_id = thread_id;
2242 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2243 th_manager[thread_id].num_dev++;
2244 DD_LIST_APPEND(th_manager[thread_id].block_dev_list, bdev);
2245 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2248 struct format_data *fdata;
2250 fdata = get_format_data(NULL, UNMOUNT_FORCE);
2252 _E("Failed to get format data.");
2256 ret = add_operation(bdev, BLOCK_DEV_FORMAT, NULL, (void *)fdata);
2258 _E("Failed to add operation(format, %s).", bdev->data->devnode);
2259 release_format_data(fdata);
2263 if (!bdev->data->fs_type) {
2264 _E("Unformatted Storage.");
2265 free_block_device(bdev);
2267 } else if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2268 // bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2269 bdev->data->primary = true;
2270 _D("Need to unlock encrypted sdcard.");
2271 // ---- ODE UI launch ----
2272 ret = launch_system_app(POPUP_DEFAULT
2275 , "unlockextendedsd"
2279 , bdev->data->devnode
2283 _E("Failed to launch popup.");
2285 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2287 _E("Failed to add operation(insert, %s).", devnode);
2288 free_block_device(bdev);
2293 } else if (mapper && !strncmp(bdev->data->fs_type, EXT4_NAME, strlen(EXT4_NAME))) {
2294 bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2295 ret = change_mount_point(bdev, EXTENDEDSD_MOUNT_PATH);
2298 free_block_device(bdev);
2303 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2305 _E("Failed to add operation(insert, %s).", devnode);
2306 free_block_device(bdev);
2310 // Not a regular filesystem -> skip mounting
2311 if (!bdev->data->fs_usage || strcmp(bdev->data->fs_usage, FILESYSTEM_NAME)) {
2312 _I("Not a filesystem. Not mounting.");
2316 ret = add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL);
2318 _E("Failed to add operation(mount, %s).", devnode);
2324 static int remove_block_device(struct udev_device *dev, const char *devnode)
2326 struct block_device *bdev;
2327 struct block_device *bdev_extended;
2330 bdev = find_block_device(devnode);
2332 _E("Failed to find block data for %s.", devnode);
2336 BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
2338 bdev->removed = true;
2339 if (bdev->on_private_op != REQ_NORMAL) {
2340 bdev->on_private_op = REQ_NORMAL;
2341 _D("Private operation state(%d).", bdev->on_private_op);
2344 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2345 bdev_extended = find_block_device_path(EXTENDEDSD_MOUNT_PATH);
2347 if (bdev_extended) {
2348 BLOCK_FLAG_SET(bdev_extended->data, UNMOUNT_UNSAFE);
2350 bdev_extended->removed = true;
2351 if (bdev_extended->on_private_op != REQ_NORMAL) {
2352 bdev_extended->on_private_op = REQ_NORMAL;
2353 _D("Private operation state(%d).", bdev_extended->on_private_op);
2356 ret = add_operation(bdev_extended, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2358 _E("Failed to add operation(unmount, %s).", devnode);
2362 ret = add_operation(bdev_extended, BLOCK_LUKS_CLOSE, NULL, NULL);
2364 _E("Failed to add operation(luks_close, %s).", devnode);
2368 ret = add_operation(bdev_extended, BLOCK_DEV_REMOVE, NULL, NULL);
2370 _E("Failed to add operation(remove, %s).", devnode);
2374 _E("Failed to find block data for extended sd card.");
2377 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2379 _E("Failed to add operation(unmount, %s).", devnode);
2383 ret = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2385 _E("Failed to add operation(remove, %s).", devnode);
2392 static int get_internal_storage_number(void)
2394 struct libmnt_table *t = NULL;
2395 struct libmnt_fs *fs;
2398 int r = 0, dev_temp;
2400 if ((!is_emulator() && (dev_internal >= 0 || dev_internal_scsi != '\0')) ||
2401 (is_emulator() && dev_internal_emul != '\0'))
2404 t = mnt_new_table();
2408 r = mnt_table_parse_mtab(t, NULL);
2414 fs = mnt_table_find_target(t, ROOT_DIR, MNT_ITER_BACKWARD);
2420 temp = mnt_fs_get_srcpath(fs);
2424 name = strrchr(temp, '/');
2428 /* Boot from USB is not handled */
2429 if (!is_emulator()) {
2430 if (!fnmatch(MMC_PATH, temp, 0))
2431 sscanf(name, "mmcblk%d", &dev_internal);
2432 else if (!fnmatch(SCSI_PATH, temp, 0))
2433 sscanf(name, "sd%c", &dev_internal_scsi);
2435 if (!fnmatch(MMC_LINK_PATH, temp, 0))
2436 sscanf(name, "vd%c%d", &dev_internal_emul, &dev_temp);
2438 dev_internal_emul = '\0';
2446 static int check_external_storage(const char* devnode)
2448 char dev_scsi = '\0';
2451 int dev_num = -1, dev_temp;
2456 name = strrchr(devnode, '/');
2460 if (!is_emulator()) {
2461 if (!fnmatch(MMC_PATH, devnode, 0)) {
2462 sscanf(name, "mmcblk%d", &dev_num);
2463 if (dev_internal == dev_num) {
2464 _D("%s is internal storage.", devnode);
2467 } else if (!fnmatch(SCSI_PATH, devnode, 0)) {
2468 sscanf(name, "sd%c", &dev_scsi);
2469 if (dev_internal_scsi == dev_scsi) {
2470 _D("%s is internal storage.", devnode);
2475 if (!fnmatch(MMC_LINK_PATH, devnode, 0)) {
2476 sscanf(name, "vd%c%d", &emul, &dev_temp);
2477 if (dev_internal_emul == emul) {
2478 _D("%s is internal storage.", devnode);
2487 static int check_already_handled(const char* devnode)
2489 struct block_device *bdev;
2490 struct block_data *data;
2494 for (i = 0; i < THREAD_MAX; i++) {
2495 pthread_mutex_lock(&(th_manager[i].mutex));
2496 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2502 if (!strncmp(data->devnode, devnode, strlen(devnode) + 1)) {
2503 pthread_mutex_unlock(&(th_manager[i].mutex));
2507 pthread_mutex_unlock(&(th_manager[i].mutex));
2513 static int block_init_from_udev_enumerate(void)
2516 struct udev_enumerate *enumerate;
2517 struct udev_list_entry *list_entry, *list_sub_entry;
2518 struct udev_device *dev;
2519 const char *syspath;
2520 const char *devnode;
2525 _E("Failed to create udev library context.");
2529 /* create a list of the devices in the 'usb' subsystem */
2530 enumerate = udev_enumerate_new(udev);
2532 _E("Failed to create an enumeration context.");
2536 udev_enumerate_add_match_subsystem(enumerate, BLOCK_SUBSYSTEM);
2537 udev_enumerate_add_match_property(enumerate,
2538 UDEV_DEVTYPE, BLOCK_DEVTYPE_DISK);
2539 udev_enumerate_add_match_property(enumerate,
2540 UDEV_DEVTYPE, BLOCK_DEVTYPE_PARTITION);
2541 udev_enumerate_scan_devices(enumerate);
2543 udev_list_entry_foreach(list_entry,
2544 udev_enumerate_get_list_entry(enumerate)) {
2545 syspath = udev_list_entry_get_name(list_entry);
2549 dev = udev_device_new_from_syspath(
2550 udev_enumerate_get_udev(enumerate),
2556 udev_list_entry_foreach(list_sub_entry,
2557 udev_device_get_devlinks_list_entry(dev)) {
2558 const char *devlink = udev_list_entry_get_name(list_sub_entry);
2559 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2566 devnode = udev_device_get_devnode(dev);
2568 udev_device_unref(dev);
2572 if (fnmatch(MMC_PATH, devnode, 0) &&
2573 fnmatch(SCSI_PATH, devnode, 0) &&
2574 fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0)) {
2575 udev_device_unref(dev);
2580 r = check_external_storage(devnode);
2582 udev_device_unref(dev);
2586 r = check_already_handled(devnode);
2588 _I("%s is already handled.", devnode);
2589 udev_device_unref(dev);
2593 _I("%s device add.", devnode);
2594 add_block_device(dev, devnode, false);
2596 udev_device_unref(dev);
2599 udev_enumerate_unref(enumerate);
2604 // Called by MainThread
2605 static void show_block_device_list(void)
2607 struct block_device *bdev;
2608 struct block_data *data;
2612 for (i = 0; i < THREAD_MAX; i++) {
2613 pthread_mutex_lock(&(th_manager[i].mutex));
2614 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2620 _D("%s:", data->devnode);
2621 _D("\tSyspath=%s", data->syspath);
2622 _D("\tBlock type=%d", data->block_type);
2623 _D("\tFs type=%s", data->fs_type);
2624 _D("\tFs usage=%s", data->fs_usage);
2625 _D("\tFs version=%s", data->fs_version);
2626 _D("\tFs uuid enc=%s", data->fs_uuid_enc);
2628 (data->readonly ? "true" : "false"));
2629 _D("\tMount point=%s", data->mount_point);
2630 _D("\tMount state=%s",
2631 (data->state == BLOCK_MOUNT ?
2632 "mount" : "unmount"));
2634 (data->primary ? "true" : "false"));
2635 _D("\tID=%d", data->id);
2637 pthread_mutex_unlock(&(th_manager[i].mutex));
2641 // Called by MainThread
2642 static void remove_whole_block_device(void)
2644 struct block_device *bdev;
2650 for (i = 0; i < THREAD_MAX; i++) {
2652 pthread_mutex_lock(&(th_manager[i].mutex));
2653 DD_LIST_FOREACH_SAFE(th_manager[i].block_dev_list, elem, next, bdev) {
2654 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2655 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2657 if (bdev->removed == false)
2660 pthread_mutex_unlock(&(th_manager[i].mutex));
2662 if (bdev && bdev->removed == false) {
2663 bdev->removed = true;
2664 r = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2666 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
2668 r = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2670 _E("Failed to add operation(remove, %s).", bdev->data->devnode);
2677 static void booting_done(void)
2679 static int done = 0;
2685 _I("Booting done.");
2687 /* register mmc uevent control routine */
2688 ret = register_udev_uevent_control(&uh);
2690 _E("Failed to register block uevent: %d", ret);
2692 block_control = true;
2693 /* if there is the attached device, try to mount */
2694 block_init_from_udev_enumerate();
2696 ret = dbus_handle_method_sync(DEVICED_BUS_NAME,
2697 DEVICED_PATH_POWEROFF,
2698 DEVICED_INTERFACE_POWEROFF,
2699 METHOD_ADD_POWEROFF_WAIT,
2702 _E("Failed to call "METHOD_ADD_POWEROFF_WAIT" method.");
2704 add_poweroff_wait = true;
2709 static void block_poweroff(GDBusConnection *conn,
2710 const gchar *sender,
2717 static int status = 0;
2724 /* unregister mmc uevent control routine */
2725 unregister_udev_uevent_control(&uh);
2726 remove_whole_block_device();
2727 terminate_threads();
2729 if (add_poweroff_wait) {
2730 ret = dbus_handle_method_sync(DEVICED_BUS_NAME,
2731 DEVICED_PATH_POWEROFF,
2732 DEVICED_INTERFACE_POWEROFF,
2733 METHOD_REMOVE_POWEROFF_WAIT,
2736 _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method.");
2738 add_poweroff_wait = false;
2742 static void uevent_block_handler(struct udev_device *dev)
2744 const char *devnode = NULL;
2746 struct udev_list_entry *list_entry;
2748 bool mapper = false;
2750 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
2751 const char *devlink = udev_list_entry_get_name(list_entry);
2752 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2756 if (!fnmatch(EXTENDEDSD_NODE_PATH, devlink, 0)) {
2764 devnode = udev_device_get_devnode(dev);
2768 if (fnmatch(MMC_PATH, devnode, 0) &&
2769 fnmatch(SCSI_PATH, devnode, 0))
2773 r = check_external_storage(devnode);
2777 action = udev_device_get_action(dev);
2781 _I("%s device %s.", devnode, action);
2782 if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD)) ||
2783 (mapper && !strcmp(action, UDEV_CHANGE))) {
2784 r = check_already_handled(devnode);
2786 _I("%s is already handled.", devnode);
2790 add_block_device(dev, devnode, mapper);
2791 } else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE))) {
2792 remove_block_device(dev, devnode);
2793 } else if (!strncmp(action, UDEV_CHANGE, sizeof(UDEV_CHANGE))) {
2794 struct block_device *bdev;
2795 bdev = find_block_device(devnode);
2797 _E("Failed to find block data for %s.", devnode);
2800 if (!udev_device_get_property_value(dev, "ID_FS_TYPE"))
2803 r = update_block_data(bdev->data,
2804 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2805 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2806 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2807 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2808 udev_device_get_sysattr_value(dev, "ro"),
2811 _E("Failed to update block data for %s.", bdev->data->devnode);
2812 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2813 _I("Filesystem type(crypto_LUKS) is updated.");
2814 if (bdev->data->fs_usage)
2815 _I("fs_usage=%s", bdev->data->fs_usage);
2819 static GVariant *request_mount_block(GDBusConnection *conn,
2820 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2821 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2823 struct block_device *bdev;
2824 char *mount_point = NULL;
2828 if (!block_control) {
2829 _D("Block module is disabled.");
2834 g_variant_get(param, "(is)", &id, &mount_point);
2836 bdev = find_block_device_by_id(id);
2838 _E("Failed to find (%d) in the device list.", id);
2843 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2844 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2845 _D("Mount dbus request for extended internal storage is blocked.");
2850 if (bdev->on_private_op != REQ_NORMAL) {
2855 if (bdev->data->state == BLOCK_MOUNT) {
2856 _I("%s is already mounted.", bdev->data->devnode);
2862 bdev->on_private_op = REQ_PRIVATE;
2863 bdev->private_pid = dbus_handle_get_sender_pid(NULL, sender);
2864 _D("Private operation state(%d). pid=%d.", bdev->on_private_op, bdev->private_pid);
2867 /* if requester want to use a specific mount point */
2868 if (mount_point && strncmp(mount_point, "", 1) != 0) {
2869 ret = change_mount_point(bdev, mount_point);
2876 ret = add_operation(bdev, BLOCK_DEV_MOUNT, invocation, NULL);
2878 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
2882 g_free(mount_point);
2886 g_free(mount_point);
2887 return g_variant_new("(i)", ret);
2890 static GVariant *request_public_mount_block(GDBusConnection *conn,
2891 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2892 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2894 return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
2897 static GVariant *request_private_mount_block(GDBusConnection *conn,
2898 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2899 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2901 return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
2904 static GVariant *request_unmount_block(GDBusConnection *conn,
2905 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2906 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2908 struct block_device *bdev;
2914 if (!block_control) {
2915 _D("Block module is disabled.");
2920 g_variant_get(param, "(ii)", &id, &option);
2922 bdev = find_block_device_by_id(id);
2924 _E("Failed to find (%d) in the device list.", id);
2929 /* Unmount dbus call is needed when app proceeds extended internal -> portable storage */
2930 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2931 _D("Unmount dbus request for extended internal storage is blocked.");
2937 pid = dbus_handle_get_sender_pid(NULL, sender);
2938 if (bdev->on_private_op == REQ_NORMAL || (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid)) {
2939 _E("Failed to process private unmount operation pid=%d private_pid=%d.", pid, bdev->private_pid);
2944 if (bdev->on_private_op != REQ_NORMAL) {
2945 _E("Failed to process unmount operation.");
2951 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, invocation, (void *)option);
2953 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
2957 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
2958 ret = add_operation(bdev, BLOCK_LUKS_CLOSE, NULL, NULL);
2960 _E("Failed to add operation(luks_close, %s).", bdev->data->devnode);
2966 return g_variant_new("(i)", ret);
2969 static GVariant *request_public_unmount_block(GDBusConnection *conn,
2970 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2971 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2973 return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
2976 static GVariant *request_private_unmount_block(GDBusConnection *conn,
2977 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2978 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2980 return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
2983 static GVariant *request_format_block(GDBusConnection *conn,
2984 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2985 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2987 struct block_device *bdev;
2988 struct format_data *fdata;
2995 if (!block_control) {
2996 _D("Block module is disabled.");
3001 g_variant_get(param, "(ii)", &id, &option);
3003 bdev = find_block_device_by_id(id);
3005 _E("Failed to find (%d) in the device list.", id);
3009 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
3010 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
3011 _D("Format dbus request for extended internal storage is blocked.");
3016 pid = dbus_handle_get_sender_pid(NULL, sender);
3017 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
3018 _E("Failed to format on private state.");
3023 fdata = get_format_data(NULL, option);
3025 _E("Failed to get format data.");
3029 prev_state = bdev->data->state;
3030 if (prev_state == BLOCK_MOUNT) {
3031 if (bdev->on_private_op == REQ_PRIVATE) {
3032 bdev->on_private_op = REQ_PRIVATE_FORMAT;
3033 _D("Private operation state(%d)", bdev->on_private_op);
3035 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3037 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
3038 release_format_data(fdata);
3043 ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3045 _E("Failed to add operation(format, %s).", bdev->data->devnode);
3046 release_format_data(fdata);
3049 /* Maintain previous state of mount/unmount */
3050 if (prev_state == BLOCK_MOUNT) {
3051 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3052 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
3060 return g_variant_new("(i)", ret);
3063 static GVariant *request_format_block_type(GDBusConnection *conn,
3064 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3065 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3067 struct block_device *bdev;
3068 struct format_data *fdata;
3076 if (!block_control) {
3077 _D("Block module is disabled.");
3082 g_variant_get(param, "(iis)", &id, &option, &type);
3084 bdev = find_block_device_by_id(id);
3086 _E("Failed to find (%d) in the device list.", id);
3090 /* FormatwithType dbus call is needed when app proceeds extended internal -> portable storage */
3091 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
3092 _D("FormatwithType dbus request for extended internal storage is blocked.");
3097 pid = dbus_handle_get_sender_pid(NULL, sender);
3098 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
3099 _E("Failed to format on private state.");
3104 fdata = get_format_data(type, option);
3106 _E("Failed to get format data.");
3110 prev_state = bdev->data->state;
3111 if (prev_state == BLOCK_MOUNT) {
3112 if (bdev->on_private_op == REQ_PRIVATE) {
3113 bdev->on_private_op = REQ_PRIVATE_FORMAT;
3114 _D("Private operation state(%d).", bdev->on_private_op);
3116 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3118 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
3119 release_format_data(fdata);
3124 ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3126 _E("Failed to add operation(format, %s).", bdev->data->devnode);
3127 release_format_data(fdata);
3130 /* Maintain previous state of mount/unmount */
3131 if (prev_state == BLOCK_MOUNT) {
3132 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3133 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
3143 return g_variant_new("(i)", ret);
3146 static GVariant *block_data_to_gvariant(struct block_data *data, int flags)
3149 return dbus_handle_new_g_variant_tuple();
3151 return g_variant_new("(issssssisibii)",
3153 nullstr(data->devnode),
3154 nullstr(data->syspath),
3155 nullstr(data->fs_usage),
3156 nullstr(data->fs_type),
3157 nullstr(data->fs_version),
3158 nullstr(data->fs_uuid_enc),
3160 nullstr(data->mount_point),
3163 flags >= 0 ? flags : data->flags,
3167 //static int add_device_to_struct_iter(struct block_data *data, DBusMessageIter *iter)
3169 // //DBusMessageIter piter;
3171 // //if (!data || !iter)
3172 // // return -EINVAL;
3174 // //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3175 // //add_device_to_iter(data, &piter);
3176 // //dbus_message_iter_close_container(iter, &piter);
3181 //static int add_device_to_iter_2(struct block_data *data, DBusMessageIter *iter)
3183 // DBusMessageIter piter;
3184 // char *str_null = "";
3186 // if (!data || !iter)
3189 // //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3190 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3191 // // &(data->block_type));
3192 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3193 // // data->devnode ? &(data->devnode) : &str_null);
3194 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3195 // // data->syspath ? &(data->syspath) : &str_null);
3196 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3197 // // data->fs_usage ? &(data->fs_usage) : &str_null);
3198 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3199 // // data->fs_type ? &(data->fs_type) : &str_null);
3200 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3201 // // data->fs_version ? &(data->fs_version) : &str_null);
3202 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3203 // // data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
3204 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3205 // // &(data->readonly));
3206 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3207 // // data->mount_point ? &(data->mount_point) : &str_null);
3208 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3209 // // &(data->state));
3210 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_BOOLEAN,
3211 // // &(data->primary));
3212 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3213 // // &(data->flags));
3214 // //dbus_message_iter_close_container(iter, &piter);
3219 static GVariant *request_get_device_info(GDBusConnection *conn,
3220 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3221 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3223 struct block_device *bdev = NULL;
3224 struct block_data *data = NULL;
3225 struct block_data nodata = {0,};
3228 g_variant_get(param, "(i)", &id);
3230 bdev = find_block_device_by_id(id);
3239 nodata.id = -ENODEV;
3243 return block_data_to_gvariant(data, -1);
3246 static GVariant *request_show_device_list(GDBusConnection *conn,
3247 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3248 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3250 show_block_device_list();
3251 return dbus_handle_new_g_variant_tuple();
3254 static enum block_device_type get_bdev_type_from_type_string(const char *type_str)
3257 return BLOCK_UNKNOWN_DEV;
3259 if (strcmp(type_str, BLOCK_TYPE_SCSI) == 0)
3260 return BLOCK_SCSI_DEV;
3261 if (strcmp(type_str, BLOCK_TYPE_MMC) == 0)
3262 return BLOCK_MMC_DEV;
3263 if (strcmp(type_str, BLOCK_TYPE_ALL) == 0)
3264 return BLOCK_ALL_DEV;
3266 return BLOCK_UNKNOWN_DEV;
3269 // Called by MainThread
3270 static GVariant *request_get_device_list(GDBusConnection *conn,
3271 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3272 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3274 GVariant *reply = NULL;
3275 struct block_device *bdev;
3276 struct block_data *data;
3279 enum block_device_type block_type;
3281 GVariantBuilder *builder = NULL;
3282 const char *error = NULL;
3284 g_variant_get(param, "(s)", &type);
3286 _D("Block (%s) device list is requested.", type);
3288 block_type = get_bdev_type_from_type_string(type);
3289 if (block_type == BLOCK_UNKNOWN_DEV) {
3290 _E("Invalid type (%s) is requested.", type);
3291 error = "Invalid type is requested";
3295 builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibii)"));
3297 for (i = 0; i < THREAD_MAX; i++) {
3298 pthread_mutex_lock(&(th_manager[i].mutex));
3299 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3300 if (!bdev->data || bdev->removed)
3305 if (block_type != BLOCK_ALL_DEV) {
3306 if (data->block_type != block_type)
3310 g_variant_builder_add(builder, "(issssssisibii)",
3312 nullstr(data->devnode),
3313 nullstr(data->syspath),
3314 nullstr(data->fs_usage),
3315 nullstr(data->fs_type),
3316 nullstr(data->fs_version),
3317 nullstr(data->fs_uuid_enc),
3319 nullstr(data->mount_point),
3325 pthread_mutex_unlock(&(th_manager[i].mutex));
3328 reply = g_variant_new("(a(issssssisibii))", builder);
3330 g_variant_builder_unref(builder);
3336 g_dbus_method_invocation_return_error(invocation,
3337 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3342 // Called by MainThread
3343 static GVariant *request_get_device_list_2(GDBusConnection *conn,
3344 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3345 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3347 GVariant *reply = NULL;
3348 struct block_device *bdev;
3349 struct block_data *data;
3352 enum block_device_type block_type;
3354 GVariantBuilder *builder = NULL;
3355 const char *error = NULL;
3357 g_variant_get(param, "(s)", &type);
3359 _E("Delivered type is NULL.");
3360 error = "Delivered type is NULL";
3364 _D("Block (%s) device list is requested.", type);
3366 block_type = get_bdev_type_from_type_string(type);
3367 if (block_type == BLOCK_UNKNOWN_DEV) {
3368 _E("Invalid type (%s) is requested.", type);
3369 error = "Invalid type is requested";
3373 builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibi)"));
3375 for (i = 0; i < THREAD_MAX; i++) {
3376 pthread_mutex_lock(&(th_manager[i].mutex));
3377 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3378 if (!bdev->data || bdev->removed)
3383 if (block_type != BLOCK_ALL_DEV) {
3384 if (data->block_type != block_type)
3388 g_variant_builder_add(builder, "(issssssisibi)",
3390 nullstr(data->devnode),
3391 nullstr(data->syspath),
3392 nullstr(data->fs_usage),
3393 nullstr(data->fs_type),
3394 nullstr(data->fs_version),
3395 nullstr(data->fs_uuid_enc),
3397 nullstr(data->mount_point),
3402 pthread_mutex_unlock(&(th_manager[i].mutex));
3405 reply = g_variant_new("(a(issssssisibi))", builder);
3407 g_variant_builder_unref(builder);
3413 g_dbus_method_invocation_return_error(invocation,
3414 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3419 static GVariant *request_get_mmc_primary(GDBusConnection *conn,
3420 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3421 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3423 struct block_device *bdev;
3424 struct block_data *data = NULL, nodata = {0,};
3429 for (i = 0; i < THREAD_MAX; i++) {
3430 pthread_mutex_lock(&(th_manager[i].mutex));
3431 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3437 if (data->block_type != BLOCK_MMC_DEV &&
3438 data->block_type != BLOCK_EXTENDEDSD_DEV)
3442 // Return mapper node(/dev/mapper/extendedsd) for primary mmc (not /dev/mmcblk1p1(ex))
3443 if (!strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
3448 pthread_mutex_unlock(&(th_manager[i].mutex));
3454 nodata.id = -ENODEV;
3458 return block_data_to_gvariant(data, -1);
3461 static GVariant *request_check_speed(GDBusConnection *conn,
3462 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3463 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3465 struct timespec start_time, end_time;
3466 struct block_device *bdev;
3467 struct block_data *data;
3475 g_variant_get(param, "(i)", &id);
3477 bdev = find_block_device_by_id(id);
3488 _D("Speed check %s.", data->devnode);
3489 fd = open(data->devnode, O_RDONLY | O_DIRECT);
3491 _E("Failed to open fd(%s): %d", data->devnode, errno);
3495 ret = posix_memalign((void**)&buf, 4096, SPEEDCHECK_SIZE << 20);
3497 _E("Failed to posix_memalign().");
3502 clock_gettime(CLOCK_REALTIME, &start_time);
3503 _I("Start time=%lu.%lu", start_time.tv_sec, start_time.tv_nsec);
3504 ret = read(fd, buf, SPEEDCHECK_SIZE << 20);
3505 clock_gettime(CLOCK_REALTIME, &end_time);
3506 _I("End time=%lu.%lu", end_time.tv_sec, end_time.tv_nsec);
3511 _E("Failed to read(): %d", errno);
3516 time_diff = end_time.tv_sec - start_time.tv_sec;
3517 if (time_diff > 0 && (SPEEDCHECK_SIZE / time_diff < SPEEDCHECK_CRITERION)) {
3525 return g_variant_new("(i)", result);
3529 static GVariant *request_control_block(GDBusConnection *conn,
3530 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3531 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3536 g_variant_get(param, "(i)", &enable);
3540 _I("Control block disable.");
3545 _I("Control block enable.");
3550 _E("Control block. Wrong request by client.");
3555 return g_variant_new("(i)", result);
3558 static GVariant *request_getcontrol_block(GDBusConnection *conn,
3559 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3560 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3564 _I("Get control block.");
3566 result = block_control;
3568 return g_variant_new("(i)", result);
3572 Method name Method call format string Reply format string
3573 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3574 { "GetDeviceList", "s", "a(issssssisibii)", request_get_device_list },
3575 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3576 { "Mount", "is", "i", request_public_mount_block },
3577 { "Unmoun, "ii", "i", request_public_unmount_block },
3578 { "Format", "ii", "i", request_format_block },
3579 { "GetDeviceInfo", "i", "(issssssisibii)", request_get_device_info },
3580 { "GetMmcPrimary", NULL, "(issssssisibii)" , request_get_mmc_primary },
3581 { "PrivateMount", "is", "i", request_private_mount_block },
3582 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3585 static const dbus_method_s manager_methods[] = {
3586 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3587 { "GetDeviceList" , "s", "a(issssssisibii)", request_get_device_list },
3588 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3589 { "Mount", "is", "i", request_public_mount_block },
3590 { "Unmount", "ii", "i", request_public_unmount_block },
3591 { "Format", "ii", "i", request_format_block },
3592 { "FormatwithType", "iis", "i", request_format_block_type },
3593 { "GetDeviceInfo", "i", "issssssisibii", request_get_device_info },
3594 { "GetMmcPrimary", NULL, "issssssisibii", request_get_mmc_primary },
3595 { "PrivateMount", "is", "i", request_private_mount_block },
3596 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3597 { "CheckSpeed", "i", "i", request_check_speed },
3598 { "Control", "i", "i", request_control_block },
3599 { "GetControl", NULL, "i", request_getcontrol_block },
3602 static const dbus_interface_u block_interface = {
3603 .name = STORAGED_INTERFACE_BLOCK_MANAGER,
3604 .methods = manager_methods,
3605 .nr_methods = ARRAY_SIZE(manager_methods),
3608 static int load_config(struct parse_result *result, void *user_data)
3612 if (MATCH(result->section, "Block"))
3615 if (MATCH(result->section, "SCSI"))
3616 index = BLOCK_SCSI_DEV;
3617 else if (MATCH(result->section, "MMC"))
3618 index = BLOCK_MMC_DEV;
3619 else if (MATCH(result->section, "Mapper"))
3620 index = BLOCK_EXTENDEDSD_DEV;
3624 if (MATCH(result->name, "Multimount"))
3625 block_conf[index].multimount =
3626 (MATCH(result->value, "yes") ? true : false);
3627 if (MATCH(result->name, "ExtendedInternalStorage"))
3628 block_conf[index].extendedinternal =
3629 (MATCH(result->value, "yes") ? true : false);
3635 static int mount_root_path_tmpfs(void)
3640 root = tzplatform_getenv(TZ_SYS_MEDIA);
3644 if (access(root, F_OK) != 0)
3647 if (mount_check(root))
3650 ret = mount("tmpfs", root, "tmpfs", 0, "smackfsroot=System::Shared");
3653 _E("Failed to mount tmpfs: %d", ret);
3660 #define mount_root_path_tmpfs() 0
3663 static guint id_block_poweroff;
3665 static void block_init(void *data)
3673 ret = config_parse(BLOCK_CONF_FILE, load_config, NULL);
3675 _E("Failed to load '%s'. Use default value.", BLOCK_CONF_FILE);
3677 ret = mount_root_path_tmpfs();
3679 _E("Failed to mount tmpfs to root mount path: %d", ret);
3681 /* register block manager object and interface */
3682 ret = dbus_handle_register_dbus_object(NULL, STORAGED_PATH_BLOCK_MANAGER, &block_interface);
3684 _E("Failed to register block interface and methods: %d", ret);
3689 _E("Failed to init pipe.");
3691 for (i = 0; i < THREAD_MAX; i++) {
3692 th_manager[i].num_dev = 0;
3693 th_manager[i].op_len = 0;
3694 th_manager[i].start_th = false;
3695 th_manager[i].thread_id = i;
3696 pthread_mutex_init(&(th_manager[i].mutex), NULL);
3697 pthread_cond_init(&(th_manager[i].cond), NULL);
3700 ret = remove_directory(EXTERNAL_STORAGE_PATH);
3702 _E("Failed to remove directory.");
3703 ret = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3705 _E("Failed to make directory: %d", errno);
3707 ret = remove_directory(EXTENDED_INTERNAL_PATH);
3709 _E("Failed to remove directory.");
3710 ret = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3712 _E("Failed to make directory: %d", errno);
3714 ret = get_internal_storage_number();
3716 _E("Failed to get internal storage number.");
3718 id_block_poweroff = subscribe_dbus_signal(NULL, DEVICED_PATH_POWEROFF,
3719 DEVICED_INTERFACE_POWEROFF,
3720 SIGNAL_POWEROFF_STATE,
3721 block_poweroff, NULL, NULL);
3725 static void terminate_threads(void)
3727 dd_list *elem, *elem_next;
3730 const int WAIT_TIME = 10;
3732 for (i = 0; i < THREAD_MAX; i++) {
3733 if (th_manager[i].start_th) {
3735 while ((th_manager[i].op_len != 0) && (count < WAIT_TIME)) {
3736 _I("Thread(%d) job is not finished. Wait a second.", th_manager[i].thread_id);
3740 pthread_cancel(th_manager[i].th);
3741 pthread_join(th_manager[i].th, NULL);
3743 DD_LIST_FOREACH_SAFE(th_manager[i].th_node_list, elem, elem_next, temp) {
3744 DD_LIST_REMOVE(th_manager[i].th_node_list, temp);
3750 static void block_exit(void *data)
3756 /* unregister notifier for below each event */
3757 unsubscribe_dbus_signal(NULL, id_block_poweroff);
3759 /* unregister mmc uevent control routine */
3760 ret = unregister_udev_uevent_control(&uh);
3762 _E("Failed to unregister block uevent: %d", ret);
3764 /* remove remaining blocks */
3765 remove_whole_block_device();
3767 terminate_threads();
3772 if (add_poweroff_wait) {
3773 ret = dbus_handle_method_sync(DEVICED_BUS_NAME,
3774 DEVICED_PATH_POWEROFF,
3775 DEVICED_INTERFACE_POWEROFF,
3776 METHOD_REMOVE_POWEROFF_WAIT,
3779 _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method.");
3781 add_poweroff_wait = false;
3784 block_control = false;
3787 static int block_start(void *data)
3790 _E("Cannot be started. Booting is not ready.");
3794 if (block_control) {
3795 _I("Already started.");
3799 block_control = true;
3801 block_init_from_udev_enumerate();
3807 static int block_stop(void *data)
3810 _E("Cannot be stopped. Booting is not ready.");
3814 if (!block_control) {
3815 _I("Already stopped.");
3819 /* remove the existing blocks */
3820 remove_whole_block_device();
3822 block_control = false;
3828 static storaged_module_interface block_module = {
3832 .start = block_start,
3836 __attribute__ ((visibility("default")))storaged_module_interface *
3837 storaged_get_module_interface(void)
3839 return &block_module;