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"
82 #define BLOCK_DEVICE_ADDED "DeviceAdded"
83 #define BLOCK_DEVICE_REMOVED "DeviceRemoved"
84 #define BLOCK_DEVICE_BLOCKED "DeviceBlocked"
85 #define BLOCK_DEVICE_CHANGED "DeviceChanged"
86 #define BLOCK_DEVICE_CHANGED_2 "DeviceChanged2"
88 #define BLOCK_TYPE_MMC "mmc"
89 #define BLOCK_TYPE_SCSI "scsi"
90 #define BLOCK_TYPE_ALL "all"
92 #define BLOCK_MMC_NODE_PREFIX "SDCard"
93 #define BLOCK_SCSI_NODE_PREFIX "USBDrive"
95 #define BLOCK_CONF_FILE "/etc/storaged/block.conf"
97 #define EXTERNAL_STORAGE_PATH "/run/storaged/external-storage"
98 #define EXTENDED_INTERNAL_PATH "/run/storaged/extended-internal-sd"
101 #define EXTENDEDSD_MOUNT_PATH "/opt/extendedsd"
103 #define VFAT_NAME "vfat"
104 #define EXT4_NAME "ext4"
105 #define LUKS_NAME "crypto_LUKS"
106 #define EXTENDEDSD_NAME "extendedsd"
108 /* Minimum value of block id */
109 #define BLOCK_ID_MIN 10
110 /* For 2.4 Backward Compatibility */
111 #define EXT_PRIMARY_SD_FIXID 1
113 /* Maximum number of thread */
116 #define SPEEDCHECK_SIZE 16
117 #define SPEEDCHECK_CRITERION 4 /* MB/s */
119 #define PKGDIR_BUS_NAME "org.tizen.pkgdir_tool"
120 #define PKGDIR_PATH "/org/tizen/pkgdir_tool"
121 #define PKGDIR_INTERFACE "org.tizen.pkgdir_tool"
123 #define POPUP_KEY_CONTENT "_SYSPOPUP_CONTENT_"
124 #define VIEWTYPE_KEY "viewtype"
125 #define DEVPATH_KEY "dev_path"
126 #define MAPPING_NODE_KEY "mapping_node"
127 #define INSERT_SD_CARD "INSERT_SD_CARD"
129 #define MMC_POPUP_NOTI "SDcardNoti"
130 #define MMC_INSERTED "inserted"
131 #define MMC_REMOVED "removed"
133 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
135 #define FILE_NAME_LEN_MAX 255
137 enum block_dev_operation {
146 enum private_operation_state {
152 struct operation_queue {
153 enum block_dev_operation op;
154 GDBusMethodInvocation *invocation;
159 struct block_device {
160 struct block_data *data;
162 int thread_id; /* Current thread ID */
163 bool removed; /* True when device is physically removed but operation is not precessed yet */
164 enum private_operation_state on_private_op;
165 bool mount_point_updated;
170 struct block_device *bdev;
172 enum unmount_operation option;
176 enum block_dev_operation op;
177 struct block_device *bdev;
181 static struct block_conf {
183 bool extendedinternal;
184 } block_conf[BLOCK_EXTENDEDSD_DEV + 1];
186 static struct manage_thread {
187 dd_list *th_node_list; /* List of devnode which thread dealt with. Only main thread access */
188 dd_list *block_dev_list; /* Use thread mutex */
190 pthread_mutex_t mutex;
192 int num_dev; /* Number of devices which thread holds. Only main thread access */
193 int op_len; /* Number of operation of thread. Use thread mutex */
194 int thread_id; /* Never changed */
196 } th_manager[THREAD_MAX];
198 char mmc_default_path[][FILE_NAME_LEN_MAX + 1] = {
205 #define DIR_NUM ((int)(sizeof(mmc_default_path)/sizeof(mmc_default_path[0])))
207 static dd_list *fs_head;
208 static dd_list *block_ops_list;
211 static fd_handler_h phandler;
212 static bool block_control = false;
213 static bool block_boot = false;
214 static pthread_mutex_t pipe_mutex = PTHREAD_MUTEX_INITIALIZER;
216 /* Assume there is only one physical internal storage */
217 static int dev_internal = -1;
218 static char dev_internal_scsi = '\0';
219 static char dev_internal_emul = '\0';
221 static int block_start(void *data);
222 static int block_stop(void *data);
224 static int add_operation(struct block_device *bdev,
225 enum block_dev_operation operation,
226 GDBusMethodInvocation *invocation, void *data);
227 static void remove_operation(struct block_device *bdev);
228 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
229 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
230 static int change_mount_point(struct block_device *bdev, const char *mount_point);
232 #define nullstr(x) (x ? x : "")
233 static GVariant *block_data_to_gvariant(struct block_data *data, int flags);
234 static GVariant *block_data_to_gvariant2(struct block_data *data, int flags);
236 #define block_send_dbus_reply(invocation, result) if (invocation) {g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", result)); }
238 static void uevent_block_handler(struct udev_device *dev);
239 static struct uevent_handler uh = {
240 .subsystem = BLOCK_SUBSYSTEM,
241 .uevent_func = uevent_block_handler,
244 static void __CONSTRUCTOR__ smack_check(void)
249 fp = fopen("/proc/filesystems", "r");
253 while (fgets(buf, sizeof(buf), fp) != NULL) {
254 if (strstr(buf, "smackfs")) {
263 void add_fs(const struct block_fs_ops *fs)
265 DD_LIST_APPEND(fs_head, (void *)fs);
268 void remove_fs(const struct block_fs_ops *fs)
270 DD_LIST_REMOVE(fs_head, (void *)fs);
273 const struct block_fs_ops *find_fs(enum block_fs_type type)
275 struct block_fs_ops *fs;
278 DD_LIST_FOREACH(fs_head, elem, fs) {
279 if (fs->type == type)
285 void add_block_dev(const struct block_dev_ops *ops)
287 DD_LIST_APPEND(block_ops_list, (void *)ops);
290 void remove_block_dev(const struct block_dev_ops *ops)
292 DD_LIST_REMOVE(block_ops_list, (void *)ops);
295 static void broadcast_block_info(enum block_dev_operation op,
296 struct block_data *data, int result)
298 struct block_dev_ops *ops;
301 if (data->primary != true)
304 DD_LIST_FOREACH(block_ops_list, elem, ops) {
305 int data_block_type = (data->block_type == BLOCK_EXTENDEDSD_DEV)
306 ? BLOCK_MMC_DEV : data->block_type;
308 if (ops->block_type != data_block_type)
310 // TODO What happend on extended internal storage case?
311 if (op == BLOCK_DEV_MOUNT) {
312 ops->mounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
313 } else if (op == BLOCK_DEV_UNMOUNT) {
314 ops->unmounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
315 } else if (op == BLOCK_DEV_FORMAT) {
316 ops->formatted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
317 } else if (op == BLOCK_DEV_INSERT)
319 else if (op == BLOCK_DEV_REMOVE)
324 // Called by MainThread - Insert
325 static int block_get_new_id(void)
327 static int id = BLOCK_ID_MIN;
328 struct block_device *bdev;
333 for (i = 0 ; i < INT_MAX ; i++) {
335 for (j = 0; j < THREAD_MAX; j++) {
336 pthread_mutex_lock(&(th_manager[j].mutex));
337 DD_LIST_FOREACH(th_manager[j].block_dev_list, elem, bdev) {
338 if (bdev->data->id == id) {
343 pthread_mutex_unlock(&(th_manager[j].mutex));
358 static void remove_file(int id, bool extendedsd)
360 char file_name[PATH_LEN];
367 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
369 snprintf(file_name, sizeof(file_name), EXTERNAL_STORAGE_PATH"/%d", id);
371 ret = remove(file_name);
373 _E("Failed to remove '%s': %d", file_name, errno);
376 static void create_file(int id, char *mount_point, bool extendedsd)
379 char file_name[PATH_LEN];
385 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
387 snprintf(file_name, PATH_LEN, EXTERNAL_STORAGE_PATH"/%d", id);
389 fp = fopen(file_name, "w+");
391 fprintf(fp, "%s", mount_point);
394 _E("Failed to open '%s'.", file_name);
397 static void signal_device_blocked(struct block_device *bdev)
399 struct block_data *data;
401 if (!bdev || !bdev->data)
406 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
407 STORAGED_INTERFACE_BLOCK_MANAGER,
408 BLOCK_DEVICE_BLOCKED,
409 block_data_to_gvariant(data, 0));
412 static void signal_device_changed(struct block_device *bdev,
413 enum block_dev_operation op)
415 struct block_data *data;
416 GVariant *var = NULL;
419 if (!bdev || !bdev->data)
425 case BLOCK_DEV_MOUNT:
426 BLOCK_GET_MOUNT_FLAGS(data, flags);
428 case BLOCK_DEV_UNMOUNT:
429 BLOCK_GET_UNMOUNT_FLAGS(data, flags);
431 case BLOCK_DEV_FORMAT:
432 BLOCK_GET_FORMAT_FLAGS(data, flags);
439 /* Broadcast outside with BlockManager iface */
440 var = block_data_to_gvariant(data, flags);
442 if (op == BLOCK_DEV_INSERT)
443 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
444 STORAGED_INTERFACE_BLOCK_MANAGER,
447 else if (op == BLOCK_DEV_REMOVE)
448 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
449 STORAGED_INTERFACE_BLOCK_MANAGER,
450 BLOCK_DEVICE_REMOVED,
453 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
454 STORAGED_INTERFACE_BLOCK_MANAGER,
455 BLOCK_DEVICE_CHANGED,
457 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
458 STORAGED_INTERFACE_BLOCK_MANAGER,
459 BLOCK_DEVICE_CHANGED_2,
460 block_data_to_gvariant2(data, flags));
464 static int get_mmc_mount_node(char *devnode, char *node, size_t len)
466 char *name = devnode;
467 int dev = -1, part = -1;
468 char emul[32] = { 0, };
475 sscanf(name, "mmcblk%dp%d", &dev, &part);
478 snprintf(node, len, "%s%c", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1);
480 snprintf(node, len, "%s%c%d", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1, part);
485 sscanf(name, "vd%31s", emul);
488 for (i = 0 ; i < strlen(emul) ; i++)
489 emul[i] = toupper(emul[i]);
490 snprintf(node, len, "%s%s", BLOCK_MMC_NODE_PREFIX, emul);
494 static int get_scsi_mount_node(char *devnode, char *node, size_t len)
502 snprintf(dev, sizeof(dev), "%s", devnode);
504 if (!strstr(dev, "sd"))
508 name += strlen("sd");
510 for (i = 0 ; i < strlen(name) ; i++)
511 name[i] = toupper(name[i]);
512 snprintf(node, len, "%s%s", BLOCK_SCSI_NODE_PREFIX, name);
517 static char *generate_mount_path(struct block_data *data)
520 char *name, node[64];
523 if (!data || !data->devnode || !data->fs_usage || (strcmp(data->fs_usage, FILESYSTEM_NAME) && strncmp(data->fs_usage, "crypto", strlen("crypto"))))
526 name = strrchr(data->devnode, '/');
531 switch (data->block_type) {
533 ret = get_mmc_mount_node(name, node, sizeof(node));
536 ret = get_scsi_mount_node(name, node, sizeof(node));
538 case BLOCK_EXTENDEDSD_DEV:
539 return strdup(EXTENDEDSD_MOUNT_PATH);
541 _E("Invalid block type(%d).", data->block_type);
547 str = tzplatform_mkpath(TZ_SYS_MEDIA, node);
553 _E("Invalid devnode(%s).", data->devnode ? data->devnode : "NULL");
557 static bool check_primary_partition(const char *devnode)
559 struct block_fs_ops *fs;
562 const char *filesystem = NULL;
572 if (fnmatch(MMC_LINK_PATH, devnode, 0) &&
573 fnmatch(MMC_PATH, devnode, 0) &&
574 fnmatch(SCSI_PATH, devnode, 0) &&
575 fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
578 temp = strrchr(devnode, '/');
581 if (fnmatch("/"SCSI_PARTITION_PATH, temp, 0) &&
582 fnmatch("/"MMC_PARTITION_PATH, temp, 0))
585 /* Emulator support only one partition */
589 snprintf(str, sizeof(str), "%s", devnode);
594 for (i = 1; i <= 9; ++i) {
595 snprintf(str2, sizeof(str2), "%s%d", str, i);
596 if (access(str2, R_OK) != 0)
599 probe = blkid_new_probe_from_filename(str2);
602 if (blkid_do_probe(probe) != 0)
605 ret = blkid_probe_lookup_value(probe, "TYPE", &filesystem, &fs_len);
607 blkid_free_probe(probe);
610 DD_LIST_FOREACH(fs_head, elem, fs) {
611 if (!strncmp(fs->name, filesystem, fs_len)) {
616 blkid_free_probe(probe);
622 if (found && !strncmp(devnode, str2, strlen(str2) + 1))
628 /* Whole data in struct block_data should be freed. */
629 static struct block_data *make_block_data(const char *devnode,
631 const char *fs_usage,
633 const char *fs_version,
634 const char *fs_uuid_enc,
635 const char *readonly)
637 struct block_data *data;
639 /* devnode is unique value so it should exist. */
644 _I("Unknown fs type.");
646 data = calloc(1, sizeof(struct block_data));
648 _E("Failed to calloc().");
652 data->devnode = strdup(devnode);
654 data->syspath = strdup(syspath);
656 data->fs_usage = strdup(fs_usage);
658 data->fs_type = strdup(fs_type);
660 data->fs_version = strdup(fs_version);
662 data->fs_uuid_enc = strdup(fs_uuid_enc);
664 data->readonly = atoi(readonly);
665 data->primary = check_primary_partition(devnode);
667 /* TODO should we know block dev type? */
668 if (!fnmatch(MMC_LINK_PATH, devnode, 0))
669 data->block_type = BLOCK_MMC_DEV;
670 else if (!fnmatch(MMC_PATH, devnode, 0))
671 data->block_type = BLOCK_MMC_DEV;
672 else if (!fnmatch(SCSI_PATH, devnode, 0))
673 data->block_type = BLOCK_SCSI_DEV;
674 else if (!fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
675 data->block_type = BLOCK_EXTENDEDSD_DEV;
677 data->block_type = -1;
679 data->mount_point = generate_mount_path(data);
680 BLOCK_FLAG_CLEAR_ALL(data);
682 /* for 2.4 backward compatibility */
683 // What if storage id 1 is existed? (multi sdcard case)
684 if (data->primary == true && data->block_type == BLOCK_MMC_DEV &&
685 data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME))
686 data->id = EXT_PRIMARY_SD_FIXID;
688 data->id = block_get_new_id();
693 static void free_block_data(struct block_data *data)
699 free(data->fs_usage);
701 free(data->fs_version);
702 free(data->fs_uuid_enc);
703 free(data->mount_point);
707 static int update_block_data(struct block_data *data,
708 const char *fs_usage,
710 const char *fs_version,
711 const char *fs_uuid_enc,
712 const char *readonly,
713 bool mount_point_updated)
718 free(data->fs_usage);
719 data->fs_usage = NULL;
721 data->fs_usage = strdup(fs_usage);
724 data->fs_type = NULL;
726 data->fs_type = strdup(fs_type);
728 free(data->fs_version);
729 data->fs_version = NULL;
731 data->fs_version = strdup(fs_version);
733 free(data->fs_uuid_enc);
734 data->fs_uuid_enc = NULL;
736 data->fs_uuid_enc = strdup(fs_uuid_enc);
738 /* generate_mount_path function should be invoked
739 * after fs_uuid_enc is updated */
740 if (!mount_point_updated) {
741 free(data->mount_point);
742 data->mount_point = generate_mount_path(data);
745 data->readonly = false;
747 data->readonly = atoi(readonly);
749 BLOCK_FLAG_MOUNT_CLEAR(data);
754 static struct block_device *make_block_device(struct block_data *data)
756 struct block_device *bdev;
761 bdev = calloc(1, sizeof(struct block_device));
766 bdev->thread_id = -1;
767 bdev->removed = false;
768 bdev->on_private_op = REQ_NORMAL;
769 bdev->private_pid = 0;
770 bdev->mount_point_updated = false;
775 // Called by MainThread - Remove DevNode
776 static void free_block_device(struct block_device *bdev)
779 struct operation_queue *op;
785 thread_id = bdev->thread_id;
786 if (thread_id < 0 || thread_id >= THREAD_MAX)
789 pthread_mutex_lock(&(th_manager[thread_id].mutex));
791 th_manager[thread_id].num_dev--;
792 DD_LIST_REMOVE(th_manager[thread_id].block_dev_list, bdev);
793 free_block_data(bdev->data);
795 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
797 th_manager[thread_id].op_len--;
798 DD_LIST_REMOVE(bdev->op_queue, op);
801 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
806 // Called By MainThread - Remove Device
807 static struct block_device *find_block_device(const char *devnode)
809 struct block_device *bdev;
814 len = strlen(devnode) + 1;
815 for (i = 0; i < THREAD_MAX; i++) {
816 pthread_mutex_lock(&(th_manager[i].mutex));
817 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
818 if (bdev->data && !bdev->removed &&
819 !strncmp(bdev->data->devnode, devnode, len)) {
820 pthread_mutex_unlock(&(th_manager[i].mutex));
824 pthread_mutex_unlock(&(th_manager[i].mutex));
830 // Called By MainThread - Remove Device
831 static struct block_device *find_block_device_path(const char *mount_point)
833 struct block_device *bdev;
838 len = strlen(mount_point) + 1;
839 for (i = 0; i < THREAD_MAX; i++) {
840 pthread_mutex_lock(&(th_manager[i].mutex));
841 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
842 if (bdev->data && !bdev->removed &&
843 (bdev->data->mount_point != NULL && !strncmp(bdev->data->mount_point, mount_point, len))) {
844 pthread_mutex_unlock(&(th_manager[i].mutex));
848 pthread_mutex_unlock(&(th_manager[i].mutex));
854 // Called By MainThread - Mount,Unmount,Format,GetInfo
855 static struct block_device *find_block_device_by_id(int id)
857 struct block_device *bdev;
861 for (i = 0; i < THREAD_MAX; i++) {
862 pthread_mutex_lock(&(th_manager[i].mutex));
863 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
868 if (bdev->data->id == id) {
869 pthread_mutex_unlock(&(th_manager[i].mutex));
873 pthread_mutex_unlock(&(th_manager[i].mutex));
879 static const char *get_operation_char(enum block_dev_operation op)
882 case BLOCK_DEV_MOUNT:
885 case BLOCK_DEV_UNMOUNT:
888 case BLOCK_DEV_FORMAT:
891 case BLOCK_DEV_INSERT:
894 case BLOCK_DEV_REMOVE:
897 case BLOCK_LUKS_CLOSE:
901 _E("Invalid operation(%d).", op);
905 void mmc_make_default_path(const char *mount_path)
909 char mmc_path[FILE_NAME_LEN_MAX + 1] = {0, };
911 for (i = 0; i < DIR_NUM; ++i) {
912 snprintf(mmc_path, sizeof(mmc_path), "%s/%s", mount_path, mmc_default_path[i]);
913 if (!g_file_test(mmc_path, G_FILE_TEST_IS_DIR)) {
914 _D("Path(%s) did not exist.", mmc_path);
915 ret = mkdir(mmc_path, 0777);
917 _E("Failed to mkdir: %d", errno);
919 /*this fuction for emulator*/
920 /*at the first time, the directroies are made permission 755*/
921 ret = chmod(mmc_path, 0777);
923 _E("Failed to chmod: %d", errno);
925 ret = chown(mmc_path, 0, 10001);
927 _E("Failed to chown: %d", errno);
932 static void create_external_apps_directory(void)
936 ret = dbus_handle_method_async(PKGDIR_BUS_NAME, PKGDIR_PATH,
937 PKGDIR_INTERFACE, "CreateExternalDirsForAllPkgs", NULL, NULL);
939 _E("Failed to create external directory.");
942 static int pipe_trigger(enum block_dev_operation op,
943 struct block_device *bdev, int result)
945 struct pipe_data pdata = { op, bdev, result };
948 _D("op=%s bdev=%p result=%d",
949 get_operation_char(pdata.op),
950 pdata.bdev, pdata.result);
952 // Multi thread should not write at the same time
953 pthread_mutex_lock(&pipe_mutex);
954 n = write(pfds[1], &pdata, sizeof(struct pipe_data));
955 pthread_mutex_unlock(&pipe_mutex);
957 return (n != sizeof(struct pipe_data)) ? -EPERM : 0;
960 static bool pipe_cb(int fd, void *data)
962 struct pipe_data pdata = {0,};
967 n = read(fd, &pdata, sizeof(pdata));
968 if (n != sizeof(pdata) || !pdata.bdev) {
969 _E("Failed to read struct pipe data.");
973 _I("op=%s bdev=%p result=%d",
974 get_operation_char(pdata.op),
975 pdata.bdev, pdata.result);
977 if (pdata.op == BLOCK_LUKS_CLOSE)
980 if (pdata.op == BLOCK_DEV_MOUNT && pdata.result < 0) {
981 if (pdata.bdev->data->state == BLOCK_UNMOUNT) {
982 ret = change_mount_point(pdata.bdev, "");
983 /* Modify /run/external-storage/id file */
985 if (pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV)
986 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, true);
988 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, false);
993 if (pdata.op == BLOCK_DEV_MOUNT &&
994 pdata.bdev->data->state == BLOCK_MOUNT &&
995 pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
996 pdata.bdev->data->primary) {
997 create_external_apps_directory();
998 mmc_make_default_path(pdata.bdev->data->mount_point);
1000 ret = dbus_handle_method_sync_var(POPUP_BUS_NAME,
1002 POPUP_INTERFACE_NOTI,
1004 g_variant_new("(s)", MMC_INSERTED));
1006 _E("Failed to popup: %d", ret);
1008 if (pdata.op == BLOCK_DEV_UNMOUNT) {
1009 /* Remove file for block device /run/xxxxxx/id */
1010 remove_file(pdata.bdev->data->id, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
1012 if (pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
1013 pdata.bdev->data->primary &&
1014 BLOCK_IS_FLAG_SET(pdata.bdev->data, UNMOUNT_UNSAFE)) {
1016 ret = dbus_handle_method_sync_var(POPUP_BUS_NAME,
1018 POPUP_INTERFACE_NOTI,
1020 g_variant_new("(s)", MMC_REMOVED));
1022 _E("Failed to popup: %d", ret);
1026 /* Broadcast to mmc and usb storage module */
1027 broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
1029 /* Broadcast outside with Block iface */
1030 if (pdata.bdev->on_private_op == REQ_NORMAL)
1031 signal_device_changed(pdata.bdev, pdata.op);
1032 else if (pdata.bdev->on_private_op == REQ_PRIVATE) {
1033 if (pdata.op == BLOCK_DEV_UNMOUNT) {
1034 pdata.bdev->on_private_op = REQ_NORMAL;
1035 _D("Private operation state(%d).", pdata.bdev->on_private_op);
1038 if (pdata.op == BLOCK_DEV_MOUNT) {
1039 pdata.bdev->on_private_op = REQ_PRIVATE;
1040 _D("Private operation state(%d).", pdata.bdev->on_private_op);
1044 if (pdata.op == BLOCK_DEV_REMOVE) {
1045 thread_id = pdata.bdev->thread_id;
1046 if (thread_id < 0 || thread_id >= THREAD_MAX)
1048 free_block_device(pdata.bdev);
1055 static int pipe_init(void)
1059 ret = pipe2(pfds, O_CLOEXEC);
1063 ret = add_fd_read_handler(pfds[0], pipe_cb,
1064 NULL, NULL, &phandler);
1066 _E("Failed to add pipe handler: %d", ret);
1073 static void pipe_exit(void)
1076 remove_fd_read_handler(&phandler);
1086 static int mmc_check_and_unmount(const char *path)
1094 while (mount_check(path)) {
1098 if (retry > UNMOUNT_RETRY)
1105 static bool check_rw_mount(const char *szPath)
1107 struct statvfs mount_stat;
1109 if (!statvfs(szPath, &mount_stat)) {
1110 if ((mount_stat.f_flag & ST_RDONLY) == ST_RDONLY)
1116 static int retrieve_udev_device(struct block_data *data, bool mount_point_updated)
1119 struct udev_device *dev;
1120 const char *fs_type;
1121 const char *fs_usage;
1128 for (wait = 0; wait < 10; wait++) {
1131 _E("Failed to create udev library context.");
1135 dev = udev_device_new_from_syspath(udev, data->syspath);
1137 _E("Failed to create new udev device.");
1142 fs_type = udev_device_get_property_value(dev, "ID_FS_TYPE");
1143 fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE");
1144 /* fs_usage for crpto_LUKS is crypto */
1145 if (!fs_type || (strncmp(fs_type, VFAT_NAME, strlen(VFAT_NAME)) && strncmp(fs_type, EXT4_NAME, strlen(EXT4_NAME))))
1147 else if (!fs_usage || strncmp(FILESYSTEM_NAME, fs_usage, strlen(FILESYSTEM_NAME)))
1152 udev_device_unref(dev);
1156 r = update_block_data(data,
1157 udev_device_get_property_value(dev, "ID_FS_USAGE"),
1158 udev_device_get_property_value(dev, "ID_FS_TYPE"),
1159 udev_device_get_property_value(dev, "ID_FS_VERSION"),
1160 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
1161 udev_device_get_sysattr_value(dev, "ro"),
1162 mount_point_updated);
1164 _E("Failed to update block data for %s.", data->devnode);
1166 udev_device_unref(dev);
1171 static int block_mount(struct block_data *data)
1173 struct block_fs_ops *fs;
1178 if (!data || !data->devnode || !data->mount_point)
1181 /* check existing mounted */
1182 if (mount_check(data->mount_point))
1185 /* create mount point */
1186 if (access(data->mount_point, R_OK) != 0) {
1187 if (mkdir(data->mount_point, 0755) < 0)
1191 /* check matched file system */
1192 if (!data->fs_usage ||
1193 strncmp(data->fs_usage, FILESYSTEM_NAME,
1194 sizeof(FILESYSTEM_NAME)) != 0) {
1199 if (!data->fs_type) {
1200 _E("There is no file system.");
1201 BLOCK_FLAG_SET(data, FS_EMPTY);
1207 len = strlen(data->fs_type) + 1;
1208 DD_LIST_FOREACH(fs_head, elem, fs) {
1209 if (!strncmp(fs->name, data->fs_type, len))
1214 _E("Not supported file system(%s).", data->fs_type);
1215 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1220 if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1221 r = fs->mount(false, data->devnode, data->mount_point);
1223 r = fs->mount(smack, data->devnode, data->mount_point);
1226 BLOCK_FLAG_SET(data, FS_BROKEN);
1231 r = check_rw_mount(data->mount_point);
1238 rmdir(data->mount_point);
1242 static int mount_start(struct block_device *bdev)
1244 struct block_data *data;
1252 _I("Mount Start (%s -> %s).",
1253 data->devnode, data->mount_point);
1255 /* mount operation */
1256 r = block_mount(data);
1257 if (r != -EROFS && r < 0) {
1258 _E("Failed to mount device(%s): %d", data->devnode, r);
1263 data->readonly = true;
1264 BLOCK_FLAG_SET(data, MOUNT_READONLY);
1267 data->state = BLOCK_MOUNT;
1269 if (data->block_type == BLOCK_MMC_DEV) {
1270 /* app2ext_migrate_legacy_all has dbus method call to deviced */
1271 ret = app2ext_migrate_legacy_all();
1273 _E("Failed to app2ext.");
1277 if (r < 0 && r != -EROFS)
1278 data->state = BLOCK_UNMOUNT;
1280 _I("%s result=%s: %d", __func__, data->devnode, r);
1282 if (pipe_trigger(BLOCK_DEV_MOUNT, bdev, r) < 0)
1283 _E("Failed to trigger pipe.");
1288 static int change_mount_point(struct block_device *bdev,
1289 const char *mount_point)
1291 struct block_data *data;
1297 free(data->mount_point);
1299 /* If the mount path already exists, the path cannot be used */
1301 access(mount_point, F_OK) != 0) {
1302 data->mount_point = strdup(mount_point);
1303 bdev->mount_point_updated = true;
1305 data->mount_point = generate_mount_path(data);
1306 bdev->mount_point_updated = false;
1312 static int mount_block_device(struct block_device *bdev)
1314 struct block_data *data;
1317 if (!bdev || !bdev->data)
1321 if (data->state == BLOCK_MOUNT) {
1322 _I("%s is already mounted.", data->devnode);
1326 if (!block_conf[data->block_type].multimount &&
1328 _I("Not support multi mount by config info.");
1332 r = mount_start(bdev);
1334 _E("Failed to mount %s.", data->devnode);
1341 static int block_unmount(struct block_device *bdev,
1342 enum unmount_operation option)
1344 struct block_data *data;
1346 struct timespec time = {0,};
1348 if (!bdev || !bdev->data || !bdev->data->mount_point)
1353 if (bdev->on_private_op == REQ_NORMAL)
1354 signal_device_blocked(bdev);
1356 /* it must called before unmounting mmc */
1357 r = mmc_check_and_unmount(data->mount_point);
1360 if (option == UNMOUNT_NORMAL) {
1361 _I("Failed to unmount with normal option: %d", r);
1365 _I("Execute force unmount.");
1366 /* Force Unmount Scenario */
1371 * should unmount the below vconf key. */
1372 if ((data->block_type == BLOCK_MMC_DEV ||
1373 data->block_type == BLOCK_EXTENDEDSD_DEV) &&
1375 /* At first, notify to other app
1376 * who already access sdcard */
1377 _I("Notify to other app who already access sdcard.");
1378 vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS,
1379 VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
1383 /* Second, kill app with SIGTERM */
1384 _I("Kill app with SIGTERM.");
1385 terminate_process(data->mount_point, false);
1388 /* Last time, kill app with SIGKILL */
1389 _I("Kill app with SIGKILL.");
1390 terminate_process(data->mount_point, true);
1393 if (umount2(data->mount_point, MNT_DETACH) != 0) {
1394 _I("Failed to unmount with lazy option: %d",
1401 /* it takes some seconds til other app completely clean up */
1402 time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER;
1403 nanosleep(&time, NULL);
1405 print_open_files(data->mount_point);
1407 r = mmc_check_and_unmount(data->mount_point);
1409 _D("Success to unmount '%s'.", data->mount_point);
1415 data->state = BLOCK_UNMOUNT;
1417 if (rmdir(data->mount_point) < 0)
1418 _E("Failed to remove '%s' directory.", data->mount_point);
1423 static int unmount_block_device(struct block_device *bdev,
1424 enum unmount_operation option)
1426 struct block_data *data;
1429 if (!bdev || !bdev->data)
1433 if (data->state == BLOCK_UNMOUNT) {
1434 _I("%s is already unmounted.", data->devnode);
1435 r = mmc_check_and_unmount(data->mount_point);
1437 _E("The path was existed, but could not delete it(%s).",
1442 _I("Unmount Start. '%s' -> '%s'.",
1443 data->devnode, data->mount_point);
1445 r = block_unmount(bdev, option);
1447 _E("Failed to unmount %s device: %d", data->devnode, r);
1451 BLOCK_FLAG_MOUNT_CLEAR(data);
1454 _I("%s result=%s: %d", __func__, data->devnode, r);
1456 if (pipe_trigger(BLOCK_DEV_UNMOUNT, bdev, r) < 0)
1457 _E("Failed to trigger pipe.");
1462 static int block_format(struct block_data *data,
1463 const char *fs_type, bool mount_point_updated)
1465 const struct block_fs_ops *fs;
1471 if (!data || !data->devnode || !data->mount_point)
1474 if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1480 fstype = data->fs_type;
1486 len = strlen(fstype);
1487 DD_LIST_FOREACH(fs_head, elem, fs) {
1488 if (!strncmp(fs->name, fstype, len))
1493 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1494 _E("Not supported file system(%s).", fstype);
1498 _I("Format path=%s", data->devnode);
1499 fs->check(data->devnode);
1500 r = fs->format(data->devnode);
1502 _E("Failed to format block data for %s.", data->devnode);
1506 /* need to update the partition data.
1507 * It can be changed in doing format. */
1508 retrieve_udev_device(data, mount_point_updated);
1513 static int format_block_device(struct block_device *bdev,
1514 const char *fs_type,
1515 enum unmount_operation option)
1517 struct block_data *data;
1525 _I("Format Start. '%s' -> '%s'.",
1526 data->devnode, data->mount_point);
1528 if (data->state == BLOCK_MOUNT) {
1529 r = block_unmount(bdev, option);
1531 _E("Failed to unmount %s device: %d", data->devnode, r);
1536 r = block_format(data, fs_type, bdev->mount_point_updated);
1538 _E("Failed to format %s device: %d", data->devnode, r);
1541 _I("%s result=%s: %d", __func__, data->devnode, r);
1543 r = pipe_trigger(BLOCK_DEV_FORMAT, bdev, r);
1545 _E("Failed to trigger pipe.");
1550 static struct format_data *get_format_data(
1551 const char *fs_type, enum unmount_operation option)
1553 struct format_data *fdata;
1555 fdata = (struct format_data *)malloc(sizeof(struct format_data));
1557 _E("Failed to allocate format data.");
1562 fdata->fs_type = strdup(fs_type);
1564 fdata->fs_type = NULL;
1565 fdata->option = option;
1570 static void release_format_data(struct format_data *data)
1574 free(data->fs_type);
1579 // Called by BlockThread - Real Mount Op
1580 static int block_mount_device(struct block_device *bdev, void *data)
1589 thread_id = bdev->thread_id;
1590 if (thread_id < 0 || thread_id >= THREAD_MAX)
1592 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1593 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1594 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1596 _E("'%s' does not exist in the device list.", bdev->data->devnode);
1600 /* mount automatically */
1601 ret = mount_block_device(bdev);
1603 _E("Failed to mount block device for %s.", bdev->data->devnode);
1608 // Called by BlockThread - Real Format Op
1609 static int block_format_device(struct block_device *bdev, void *data)
1614 struct format_data *fdata = (struct format_data *)data;
1616 if (!bdev || !fdata) {
1621 thread_id = bdev->thread_id;
1622 if (thread_id < 0 || thread_id >= THREAD_MAX)
1624 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1625 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1626 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1628 _E("'%s' does not exist in the device list.", bdev->data->devnode);
1633 ret = format_block_device(bdev, fdata->fs_type, fdata->option);
1635 _E("Failed to format block device for %s.", bdev->data->devnode);
1638 release_format_data(fdata);
1643 // Called by BlockThread - Real Unmount Op
1644 static int block_unmount_device(struct block_device *bdev, void *data)
1647 long option = (long)data;
1652 ret = unmount_block_device(bdev, option);
1654 _E("Failed to unmount block device(%s).", bdev->data->devnode);
1661 /* Called by BlockThread - Remove Operation
1662 Direct Call at BlockThread
1663 Previously this function was called by MainThread. However, it will increase complexity.
1664 Need thread lock before to call remove_operation
1666 static void remove_operation(struct block_device *bdev)
1668 struct operation_queue *op;
1674 thread_id = bdev->thread_id;
1675 if (thread_id < 0 || thread_id >= THREAD_MAX)
1678 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
1680 _D("Remove operation(%s, %s).",
1681 get_operation_char(op->op),
1682 bdev->data->devnode);
1684 DD_LIST_REMOVE(bdev->op_queue, op);
1690 // Called by BlockThread
1691 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1693 struct operation_queue *temp;
1706 thread_id = bdev->thread_id;
1707 if (thread_id < 0 || thread_id >= THREAD_MAX)
1710 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1712 DD_LIST_FOREACH(*queue, l, temp) {
1713 if (temp->op == BLOCK_DEV_REMOVE) {
1718 th_manager[thread_id].op_len--;
1719 block_send_dbus_reply((*op)->invocation, 0);
1722 remove_operation(bdev);
1723 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1726 // Called by BlockThread
1727 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1729 struct operation_queue *temp;
1732 bool unmounted = false;
1743 thread_id = bdev->thread_id;
1744 if (thread_id < 0 || thread_id >= THREAD_MAX)
1747 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1748 DD_LIST_FOREACH(*queue, l, temp) {
1749 if (temp->op == BLOCK_DEV_UNMOUNT) {
1751 _D("Operation queue has unmount operation.");
1755 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1760 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1762 DD_LIST_FOREACH(*queue, l, temp) {
1763 if (temp->op == BLOCK_DEV_UNMOUNT) {
1768 th_manager[thread_id].op_len--;
1769 block_send_dbus_reply((*op)->invocation, 0);
1772 remove_operation(bdev);
1773 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1778 // Called by BlockThread
1779 static void trigger_operation(struct block_device *bdev, dd_list *queue, struct operation_queue *op)
1783 char devnode[PATH_MAX];
1784 enum block_dev_operation operation;
1785 bool unmounted = false;
1792 thread_id = bdev->thread_id;
1793 if (thread_id < 0 || thread_id >= THREAD_MAX)
1796 snprintf(devnode, sizeof(devnode), "%s", bdev->data->devnode);
1806 _D("Thread id(%d) Trigger operation(%s, %s)", thread_id,
1807 get_operation_char(operation), devnode);
1810 if (operation == BLOCK_DEV_INSERT && bdev->removed) {
1811 check_removed(bdev, &queue, &op);
1813 _D("Trigger operation again(%s, %s).",
1814 get_operation_char(operation), devnode);
1816 if (operation == BLOCK_DEV_MOUNT) {
1817 unmounted = check_unmount(bdev, &queue, &op);
1820 _D("Trigger operation again(%s, %s).",
1821 get_operation_char(operation), devnode);
1825 switch (operation) {
1826 case BLOCK_DEV_INSERT:
1828 case BLOCK_DEV_MOUNT:
1829 ret = block_mount_device(bdev, op->data);
1830 _D("Mount '%s': %d", devnode, ret);
1832 case BLOCK_DEV_FORMAT:
1833 ret = block_format_device(bdev, op->data);
1834 _D("Format '%s': %d", devnode, ret);
1836 case BLOCK_DEV_UNMOUNT:
1837 ret = block_unmount_device(bdev, op->data);
1838 _D("Unmount '%s': %d", devnode, ret);
1840 case BLOCK_DEV_REMOVE:
1843 case BLOCK_LUKS_CLOSE:
1844 ret = ode_luks_close_sync(EXTENDEDSD_NAME);
1846 _E("Failed on ode_luks_close(%s).", EXTENDEDSD_NAME);
1849 _E("Operation type(%d) is invalid.", op->op);
1855 * during checking the queue length */
1856 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1859 th_manager[thread_id].op_len--;
1861 block_send_dbus_reply(op->invocation, ret);
1863 queue = bdev->op_queue;
1864 if (queue != NULL) {
1865 queue = DD_LIST_NEXT(queue);
1867 op = DD_LIST_NTH(queue, 0);
1873 remove_operation(bdev);
1875 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1878 if (operation == BLOCK_DEV_INSERT || operation == BLOCK_DEV_REMOVE || operation == BLOCK_LUKS_CLOSE) {
1879 if (pipe_trigger(operation, bdev, 0) < 0)
1880 _E("Failed to trigger pipe.");
1887 // Called by BlockThread
1888 static void *block_th_start(void *arg)
1890 struct block_device *temp;
1891 struct manage_thread *th = (struct manage_thread *)arg;
1892 struct operation_queue *op = NULL;
1894 dd_list *queue = NULL;
1899 thread_id = th->thread_id;
1900 if (thread_id < 0 || thread_id >= THREAD_MAX) {
1901 _E("Thread Number=%d.", th->thread_id);
1906 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1907 if (th_manager[thread_id].op_len == 0) {
1908 _D("Operation queue of thread is empty.");
1909 pthread_cond_wait(&(th_manager[thread_id].cond), &(th_manager[thread_id].mutex));
1910 _D("Wake up thread=%d.", thread_id);
1913 DD_LIST_FOREACH(th_manager[thread_id].block_dev_list, elem, temp) {
1914 queue = temp->op_queue;
1916 op = DD_LIST_NTH(queue, 0);
1918 _D("Operation queue for device %s is Empty.", temp->data->devnode);
1922 queue = DD_LIST_NEXT(queue);
1930 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1932 if (op && !op->done)
1933 trigger_operation(temp, queue, op);
1938 // This function will be refactored later
1939 // Especially, we don't need to keep th_node_list.
1940 static int find_thread(char *devnode)
1947 int i, len, min, min_num;
1948 int dev_mmc = -1, part = -1, num;
1951 if (!fnmatch("*/"MMC_PARTITION_PATH, devnode, 0)) {
1952 sscanf(devnode, "/dev/mmcblk%dp%d", &dev_mmc, &part);
1959 snprintf(str, len, "/dev/mmcblk%d", dev_mmc);
1960 th_node = strdup(str);
1961 } else if (!fnmatch("*/"SCSI_PARTITION_PATH, devnode, 0)) {
1962 sscanf(devnode, "/dev/sd%c%d", &dev_scsi, &part);
1963 snprintf(str, SCSI_PARTITION_LENGTH, "/dev/sd%c", dev_scsi);
1964 th_node = strdup(str);
1966 th_node = strdup(devnode);
1968 len = strlen(th_node) + 1;
1971 for (i = 0; i < THREAD_MAX; i++) {
1972 DD_LIST_FOREACH(th_manager[i].th_node_list, elem, temp) {
1973 if (!strncmp(temp, th_node, len)) {
1978 if (th_manager[i].num_dev < min_num) {
1979 min_num = th_manager[i].num_dev;
1984 if (min >= 0 && min < THREAD_MAX) {
1985 DD_LIST_APPEND(th_manager[min].th_node_list, th_node);
1989 _E("Failed to find thread.");
1990 DD_LIST_APPEND(th_manager[0].th_node_list, th_node);
1994 /* Only Main thread is permmited */
1995 // Called by MainThread
1996 static int add_operation(struct block_device *bdev,
1997 enum block_dev_operation operation,
1998 GDBusMethodInvocation *invocation, void *data)
2000 struct operation_queue *op;
2009 _I("Add operation(%s, %s).",
2010 get_operation_char(operation),
2011 bdev->data->devnode);
2013 thread_id = bdev->thread_id;
2014 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2015 _E("Failed to find thread to add.");
2019 op = (struct operation_queue *)malloc(sizeof(struct operation_queue));
2021 _E("Failed to malloc.");
2027 op->invocation = invocation;
2029 /* Need to disble app2ext whenever unmounting mmc */
2030 /* app2ext_disable_all_external_pkgs inside a critical section need to be avoided. */
2031 if (operation == BLOCK_DEV_UNMOUNT &&
2032 bdev->data->state == BLOCK_MOUNT &&
2033 bdev->data->block_type == BLOCK_MMC_DEV &&
2034 bdev->data->primary)
2035 if (app2ext_disable_all_external_pkgs() < 0)
2036 _E("Failed to app2ext_disable_all_external_pkgs().");
2039 * during adding queue and checking the queue length */
2040 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2042 /* Only modified between lock and unlock of mutex */
2045 start_th = th_manager[thread_id].start_th;
2046 DD_LIST_APPEND(bdev->op_queue, op);
2047 th_manager[thread_id].op_len++;
2049 if (th_manager[thread_id].op_len == 1 && start_th)
2050 pthread_cond_signal(&(th_manager[thread_id].cond));
2052 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2056 _D("Start new thread for block device.");
2057 th_manager[thread_id].start_th = true;
2058 ret = pthread_create(&(th_manager[thread_id].th), NULL, block_th_start, &th_manager[thread_id]);
2060 _E("Failed to create thread for %s.", bdev->data->devnode);
2064 pthread_detach(th_manager[thread_id].th);
2070 static bool disk_is_partitioned_by_kernel(struct udev_device *dev)
2073 struct dirent entry;
2075 const char *syspath;
2078 syspath = udev_device_get_syspath(dev);
2082 dp = opendir(syspath);
2084 _E("Failed to open '%s'.", syspath);
2088 /* TODO compare devname and d_name */
2089 while (readdir_r(dp, &entry, &dir) == 0 && dir != NULL) {
2090 if (!fnmatch(MMC_PARTITION_PATH, dir->d_name, 0) ||
2091 !fnmatch(SCSI_PARTITION_PATH, dir->d_name, 0)) {
2103 static bool check_partition(struct udev_device *dev)
2105 const char *devtype;
2106 const char *part_table_type;
2107 const char *fs_usage;
2110 /* only consider disk type, never partitions */
2111 devtype = udev_device_get_devtype(dev);
2115 if (strncmp(devtype, BLOCK_DEVTYPE_DISK,
2116 sizeof(BLOCK_DEVTYPE_DISK)) != 0)
2119 part_table_type = udev_device_get_property_value(dev,
2120 "ID_PART_TABLE_TYPE");
2121 if (part_table_type) {
2122 fs_usage = udev_device_get_property_value(dev,
2125 strncmp(fs_usage, FILESYSTEM_NAME, sizeof(FILESYSTEM_NAME)) == 0) {
2126 if (!disk_is_partitioned_by_kernel(dev))
2133 if (disk_is_partitioned_by_kernel(dev)) {
2142 // Called by MainThread
2143 static int add_block_device(struct udev_device *dev, const char *devnode, bool mapper)
2145 struct block_data *data;
2146 struct block_device *bdev;
2147 //char id_string[PATH_LEN];
2151 bool need_format = false;
2153 partition = check_partition(dev);
2155 /* if there is a partition, skip this request */
2156 _I("%s device has partitions, skip this time.", devnode);
2160 if (mapper && !udev_device_get_property_value(dev, "ID_FS_TYPE")) {
2161 char syspath[128] = {0};
2164 r = rindex(udev_device_get_syspath(dev), '/');
2165 if (!r) return -ENODEV;
2167 snprintf(syspath, sizeof(syspath), "/sys/block%s", r);
2169 data = make_block_data(devnode,
2174 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2175 udev_device_get_sysattr_value(dev, "ro"));
2178 data = make_block_data(devnode,
2179 udev_device_get_syspath(dev),
2180 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2181 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2182 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2183 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2184 udev_device_get_sysattr_value(dev, "ro"));
2188 _E("Failed to make block data for %s.", devnode);
2192 if (!block_conf[data->block_type].multimount && !data->primary &&
2193 data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME)) {
2194 _D("Not support multi mount by config info.");
2195 free_block_data(data);
2199 if (!block_control) {
2200 if (!mapper && strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2201 _D("Block module is disabled.");
2202 free_block_data(data);
2208 bdev = make_block_device(data);
2210 _E("Failed to make block device for %s.", devnode);
2211 free_block_data(data);
2215 thread_id = find_thread(bdev->data->devnode);
2216 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2217 _E("Failed to find thread to add.");
2218 free_block_device(bdev);
2221 bdev->thread_id = thread_id;
2223 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2224 th_manager[thread_id].num_dev++;
2225 DD_LIST_APPEND(th_manager[thread_id].block_dev_list, bdev);
2226 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2229 struct format_data *fdata;
2231 fdata = get_format_data(NULL, UNMOUNT_FORCE);
2233 _E("Failed to get format data.");
2237 ret = add_operation(bdev, BLOCK_DEV_FORMAT, NULL, (void *)fdata);
2239 _E("Failed to add operation(format, %s).", bdev->data->devnode);
2240 release_format_data(fdata);
2244 if (!bdev->data->fs_type) {
2245 _E("Unformatted Storage.");
2246 free_block_device(bdev);
2248 } else if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2249 // bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2250 bdev->data->primary = true;
2251 _D("Need to unlock encrypted sdcard.");
2252 // ---- ODE UI launch ----
2253 ret = launch_system_app(POPUP_DEFAULT
2256 , "unlockextendedsd"
2260 , bdev->data->devnode
2264 _E("Failed to launch popup.");
2266 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2268 _E("Failed to add operation(insert, %s).", devnode);
2269 free_block_device(bdev);
2274 } else if (mapper && !strncmp(bdev->data->fs_type, EXT4_NAME, strlen(EXT4_NAME))) {
2275 bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2276 ret = change_mount_point(bdev, EXTENDEDSD_MOUNT_PATH);
2279 free_block_device(bdev);
2284 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2286 _E("Failed to add operation(insert, %s).", devnode);
2287 free_block_device(bdev);
2291 // Not a regular filesystem -> skip mounting
2292 if (!bdev->data->fs_usage || strcmp(bdev->data->fs_usage, FILESYSTEM_NAME)) {
2293 _I("Not a filesystem. Not mounting.");
2297 /* Create file for block device /run/external-storage/id */
2298 create_file(bdev->data->id, bdev->data->mount_point, bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
2299 ret = add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL);
2301 _E("Failed to add operation(mount, %s).", devnode);
2307 static int remove_block_device(struct udev_device *dev, const char *devnode)
2309 struct block_device *bdev;
2310 struct block_device *bdev_extended;
2313 bdev = find_block_device(devnode);
2315 _E("Failed to find block data for %s.", devnode);
2319 BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
2321 bdev->removed = true;
2322 if (bdev->on_private_op != REQ_NORMAL) {
2323 bdev->on_private_op = REQ_NORMAL;
2324 _D("Private operation state(%d).", bdev->on_private_op);
2327 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2328 bdev_extended = find_block_device_path(EXTENDEDSD_MOUNT_PATH);
2330 if (bdev_extended) {
2331 BLOCK_FLAG_SET(bdev_extended->data, UNMOUNT_UNSAFE);
2333 bdev_extended->removed = true;
2334 if (bdev_extended->on_private_op != REQ_NORMAL) {
2335 bdev_extended->on_private_op = REQ_NORMAL;
2336 _D("Private operation state(%d).", bdev_extended->on_private_op);
2339 ret = add_operation(bdev_extended, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2341 _E("Failed to add operation(unmount, %s).", devnode);
2345 ret = add_operation(bdev_extended, BLOCK_LUKS_CLOSE, NULL, NULL);
2347 _E("Failed to add operation(luks_close, %s).", devnode);
2351 ret = add_operation(bdev_extended, BLOCK_DEV_REMOVE, NULL, NULL);
2353 _E("Failed to add operation(remove, %s).", devnode);
2357 _E("Failed to find block data for extended sd card.");
2360 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2362 _E("Failed to add operation(unmount, %s).", devnode);
2366 ret = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2368 _E("Failed to add operation(remove, %s).", devnode);
2375 static int get_internal_storage_number(void)
2377 struct libmnt_table *t = NULL;
2378 struct libmnt_fs *fs;
2381 int r = 0, dev_temp;
2383 if ((!is_emulator() && (dev_internal >= 0 || dev_internal_scsi != '\0')) ||
2384 (is_emulator() && dev_internal_emul != '\0'))
2387 t = mnt_new_table();
2391 r = mnt_table_parse_mtab(t, NULL);
2397 fs = mnt_table_find_target(t, ROOT_DIR, MNT_ITER_BACKWARD);
2403 temp = mnt_fs_get_srcpath(fs);
2407 name = strrchr(temp, '/');
2411 /* Boot from USB is not handled */
2412 if (!is_emulator()) {
2413 if (!fnmatch(MMC_PATH, temp, 0))
2414 sscanf(name, "mmcblk%d", &dev_internal);
2415 else if (!fnmatch(SCSI_PATH, temp, 0))
2416 sscanf(name, "sd%c", &dev_internal_scsi);
2418 if (!fnmatch(MMC_LINK_PATH, temp, 0))
2419 sscanf(name, "vd%c%d", &dev_internal_emul, &dev_temp);
2421 dev_internal_emul = '\0';
2429 static int check_external_storage(const char* devnode)
2431 char dev_scsi = '\0';
2434 int dev_num = -1, dev_temp;
2439 name = strrchr(devnode, '/');
2443 if (!is_emulator()) {
2444 if (!fnmatch(MMC_PATH, devnode, 0)) {
2445 sscanf(name, "mmcblk%d", &dev_num);
2446 if (dev_internal == dev_num) {
2447 _D("%s is internal storage.", devnode);
2450 } else if (!fnmatch(SCSI_PATH, devnode, 0)) {
2451 sscanf(name, "sd%c", &dev_scsi);
2452 if (dev_internal_scsi == dev_scsi) {
2453 _D("%s is internal storage.", devnode);
2458 if (!fnmatch(MMC_LINK_PATH, devnode, 0)) {
2459 sscanf(name, "vd%c%d", &emul, &dev_temp);
2460 if (dev_internal_emul == emul) {
2461 _D("%s is internal storage.", devnode);
2470 static int check_already_handled(const char* devnode)
2472 struct block_device *bdev;
2473 struct block_data *data;
2477 for (i = 0; i < THREAD_MAX; i++) {
2478 pthread_mutex_lock(&(th_manager[i].mutex));
2479 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2485 if (!strncmp(data->devnode, devnode, strlen(devnode) + 1)) {
2486 pthread_mutex_unlock(&(th_manager[i].mutex));
2490 pthread_mutex_unlock(&(th_manager[i].mutex));
2496 static int block_init_from_udev_enumerate(void)
2499 struct udev_enumerate *enumerate;
2500 struct udev_list_entry *list_entry, *list_sub_entry;
2501 struct udev_device *dev;
2502 const char *syspath;
2503 const char *devnode;
2508 _E("Failed to create udev library context.");
2512 /* create a list of the devices in the 'usb' subsystem */
2513 enumerate = udev_enumerate_new(udev);
2515 _E("Failed to create an enumeration context.");
2519 udev_enumerate_add_match_subsystem(enumerate, BLOCK_SUBSYSTEM);
2520 udev_enumerate_add_match_property(enumerate,
2521 UDEV_DEVTYPE, BLOCK_DEVTYPE_DISK);
2522 udev_enumerate_add_match_property(enumerate,
2523 UDEV_DEVTYPE, BLOCK_DEVTYPE_PARTITION);
2524 udev_enumerate_scan_devices(enumerate);
2526 udev_list_entry_foreach(list_entry,
2527 udev_enumerate_get_list_entry(enumerate)) {
2528 syspath = udev_list_entry_get_name(list_entry);
2532 dev = udev_device_new_from_syspath(
2533 udev_enumerate_get_udev(enumerate),
2539 udev_list_entry_foreach(list_sub_entry,
2540 udev_device_get_devlinks_list_entry(dev)) {
2541 const char *devlink = udev_list_entry_get_name(list_sub_entry);
2542 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2549 devnode = udev_device_get_devnode(dev);
2551 udev_device_unref(dev);
2555 if (fnmatch(MMC_PATH, devnode, 0) &&
2556 fnmatch(SCSI_PATH, devnode, 0) &&
2557 fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0)) {
2558 udev_device_unref(dev);
2563 r = check_external_storage(devnode);
2565 udev_device_unref(dev);
2569 r = check_already_handled(devnode);
2571 _I("%s is already handled.", devnode);
2572 udev_device_unref(dev);
2576 _I("%s device add.", devnode);
2577 add_block_device(dev, devnode, false);
2579 udev_device_unref(dev);
2582 udev_enumerate_unref(enumerate);
2587 // Called by MainThread
2588 static void show_block_device_list(void)
2590 struct block_device *bdev;
2591 struct block_data *data;
2595 for (i = 0; i < THREAD_MAX; i++) {
2596 pthread_mutex_lock(&(th_manager[i].mutex));
2597 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2603 _D("%s:", data->devnode);
2604 _D("\tSyspath=%s", data->syspath);
2605 _D("\tBlock type=%d", data->block_type);
2606 _D("\tFs type=%s", data->fs_type);
2607 _D("\tFs usage=%s", data->fs_usage);
2608 _D("\tFs version=%s", data->fs_version);
2609 _D("\tFs uuid enc=%s", data->fs_uuid_enc);
2611 (data->readonly ? "true" : "false"));
2612 _D("\tMount point=%s", data->mount_point);
2613 _D("\tMount state=%s",
2614 (data->state == BLOCK_MOUNT ?
2615 "mount" : "unmount"));
2617 (data->primary ? "true" : "false"));
2618 _D("\tID=%d", data->id);
2620 pthread_mutex_unlock(&(th_manager[i].mutex));
2624 // Called by MainThread
2625 static void remove_whole_block_device(void)
2627 struct block_device *bdev;
2633 for (i = 0; i < THREAD_MAX; i++) {
2635 pthread_mutex_lock(&(th_manager[i].mutex));
2636 DD_LIST_FOREACH_SAFE(th_manager[i].block_dev_list, elem, next, bdev) {
2637 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2638 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2640 if (bdev->removed == false)
2643 pthread_mutex_unlock(&(th_manager[i].mutex));
2645 if (bdev && bdev->removed == false) {
2646 bdev->removed = true;
2647 r = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2649 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
2651 r = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2653 _E("Failed to add operation(remove, %s).", bdev->data->devnode);
2660 static void booting_done(void)
2662 static int done = 0;
2668 _I("Booting done.");
2670 /* register mmc uevent control routine */
2671 ret = register_udev_uevent_control(&uh);
2673 _E("Failed to register block uevent: %d", ret);
2675 block_control = true;
2676 /* if there is the attached device, try to mount */
2677 block_init_from_udev_enumerate();
2682 static void block_poweroff(GDBusConnection *conn,
2683 const gchar *sender,
2690 static int status = 0;
2695 /* unregister mmc uevent control routine */
2696 unregister_udev_uevent_control(&uh);
2697 remove_whole_block_device();
2700 static void uevent_block_handler(struct udev_device *dev)
2702 const char *devnode = NULL;
2704 struct udev_list_entry *list_entry;
2706 bool mapper = false;
2708 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
2709 const char *devlink = udev_list_entry_get_name(list_entry);
2710 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2714 if (!fnmatch(EXTENDEDSD_NODE_PATH, devlink, 0)) {
2722 devnode = udev_device_get_devnode(dev);
2726 if (fnmatch(MMC_PATH, devnode, 0) &&
2727 fnmatch(SCSI_PATH, devnode, 0))
2731 r = check_external_storage(devnode);
2735 action = udev_device_get_action(dev);
2739 _I("%s device %s.", devnode, action);
2740 if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD)) ||
2741 (mapper && !strcmp(action, UDEV_CHANGE))) {
2742 r = check_already_handled(devnode);
2744 _I("%s is already handled.", devnode);
2748 add_block_device(dev, devnode, mapper);
2749 } else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE))) {
2750 remove_block_device(dev, devnode);
2751 } else if (!strncmp(action, UDEV_CHANGE, sizeof(UDEV_CHANGE))) {
2752 struct block_device *bdev;
2753 bdev = find_block_device(devnode);
2755 _E("Failed to find block data for %s.", devnode);
2758 if (!udev_device_get_property_value(dev, "ID_FS_TYPE"))
2761 r = update_block_data(bdev->data,
2762 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2763 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2764 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2765 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2766 udev_device_get_sysattr_value(dev, "ro"),
2769 _E("Failed to update block data for %s.", bdev->data->devnode);
2770 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2771 _I("Filesystem type(crypto_LUKS) is updated.");
2772 if (bdev->data->fs_usage)
2773 _I("fs_usage=%s", bdev->data->fs_usage);
2777 static GVariant *request_mount_block(GDBusConnection *conn,
2778 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2779 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2781 struct block_device *bdev;
2782 char *mount_point = NULL;
2786 if (!block_control) {
2787 _D("Block module is disabled.");
2792 g_variant_get(param, "(is)", &id, &mount_point);
2794 bdev = find_block_device_by_id(id);
2796 _E("Failed to find (%d) in the device list.", id);
2801 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2802 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2803 _D("Mount dbus request for extended internal storage is blocked.");
2808 if (bdev->on_private_op != REQ_NORMAL) {
2813 if (bdev->data->state == BLOCK_MOUNT) {
2814 _I("%s is already mounted.", bdev->data->devnode);
2820 bdev->on_private_op = REQ_PRIVATE;
2821 bdev->private_pid = dbus_handle_get_sender_pid(NULL, sender);
2822 _D("Private operation state(%d). pid=%d.", bdev->on_private_op, bdev->private_pid);
2824 if (bdev->on_private_op != REQ_NORMAL) {
2825 _E("Failed to process mount operation.");
2831 /* if requester want to use a specific mount point */
2832 if (mount_point && strncmp(mount_point, "", 1) != 0) {
2833 ret = change_mount_point(bdev, mount_point);
2839 /* Create /run/external-storage/id file */
2840 create_file(bdev->data->id, bdev->data->mount_point, false);
2842 /* Create file for block device /run/external-storage/id */
2843 create_file(bdev->data->id, bdev->data->mount_point, false);
2846 ret = add_operation(bdev, BLOCK_DEV_MOUNT, invocation, NULL);
2848 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
2852 g_free(mount_point);
2856 g_free(mount_point);
2857 return g_variant_new("(i)", ret);
2860 static GVariant *request_public_mount_block(GDBusConnection *conn,
2861 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2862 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2864 return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
2867 static GVariant *request_private_mount_block(GDBusConnection *conn,
2868 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2869 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2871 return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
2874 static GVariant *request_unmount_block(GDBusConnection *conn,
2875 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2876 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2878 struct block_device *bdev;
2884 if (!block_control) {
2885 _D("Block module is disabled.");
2890 g_variant_get(param, "(ii)", &id, &option);
2892 bdev = find_block_device_by_id(id);
2894 _E("Failed to find (%d) in the device list.", id);
2899 /* Unmount dbus call is needed when app proceeds extended internal -> portable storage */
2900 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2901 _D("Unmount dbus request for extended internal storage is blocked.");
2907 pid = dbus_handle_get_sender_pid(NULL, sender);
2908 if (bdev->on_private_op == REQ_NORMAL || (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid)) {
2909 _E("Failed to process private unmount operation pid=%d private_pid=%d.", pid, bdev->private_pid);
2914 if (bdev->on_private_op != REQ_NORMAL) {
2915 _E("Failed to process unmount operation.");
2921 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, invocation, (void *)option);
2923 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
2927 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
2928 ret = add_operation(bdev, BLOCK_LUKS_CLOSE, NULL, NULL);
2930 _E("Failed to add operation(luks_close, %s).", bdev->data->devnode);
2936 return g_variant_new("(i)", ret);
2939 static GVariant *request_public_unmount_block(GDBusConnection *conn,
2940 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2941 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2943 return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
2946 static GVariant *request_private_unmount_block(GDBusConnection *conn,
2947 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2948 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2950 return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
2953 static GVariant *request_format_block(GDBusConnection *conn,
2954 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2955 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2957 struct block_device *bdev;
2958 struct format_data *fdata;
2965 if (!block_control) {
2966 _D("Block module is disabled.");
2971 g_variant_get(param, "(ii)", &id, &option);
2973 bdev = find_block_device_by_id(id);
2975 _E("Failed to find (%d) in the device list.", id);
2979 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2980 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2981 _D("Format dbus request for extended internal storage is blocked.");
2986 pid = dbus_handle_get_sender_pid(NULL, sender);
2987 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
2988 _E("Failed to format on private state.");
2993 fdata = get_format_data(NULL, option);
2995 _E("Failed to get format data.");
2999 prev_state = bdev->data->state;
3000 if (prev_state == BLOCK_MOUNT) {
3001 if (bdev->on_private_op == REQ_PRIVATE) {
3002 bdev->on_private_op = REQ_PRIVATE_FORMAT;
3003 _D("Private operation state(%d)", bdev->on_private_op);
3005 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3007 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
3008 release_format_data(fdata);
3013 ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3015 _E("Failed to add operation(format, %s).", bdev->data->devnode);
3016 release_format_data(fdata);
3019 /* Maintain previous state of mount/unmount */
3020 if (prev_state == BLOCK_MOUNT) {
3021 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3022 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
3030 return g_variant_new("(i)", ret);
3033 static GVariant *request_format_block_type(GDBusConnection *conn,
3034 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3035 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3037 struct block_device *bdev;
3038 struct format_data *fdata;
3046 if (!block_control) {
3047 _D("Block module is disabled.");
3052 g_variant_get(param, "(iis)", &id, &option, &type);
3054 bdev = find_block_device_by_id(id);
3056 _E("Failed to find (%d) in the device list.", id);
3060 /* FormatwithType dbus call is needed when app proceeds extended internal -> portable storage */
3061 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
3062 _D("FormatwithType dbus request for extended internal storage is blocked.");
3067 pid = dbus_handle_get_sender_pid(NULL, sender);
3068 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
3069 _E("Failed to format on private state.");
3074 fdata = get_format_data(type, option);
3076 _E("Failed to get format data.");
3080 prev_state = bdev->data->state;
3081 if (prev_state == BLOCK_MOUNT) {
3082 if (bdev->on_private_op == REQ_PRIVATE) {
3083 bdev->on_private_op = REQ_PRIVATE_FORMAT;
3084 _D("Private operation state(%d).", bdev->on_private_op);
3086 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3088 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
3089 release_format_data(fdata);
3094 ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3096 _E("Failed to add operation(format, %s).", bdev->data->devnode);
3097 release_format_data(fdata);
3100 /* Maintain previous state of mount/unmount */
3101 if (prev_state == BLOCK_MOUNT) {
3102 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3103 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
3113 return g_variant_new("(i)", ret);
3116 static GVariant *block_data_to_gvariant(struct block_data *data, int flags)
3119 return dbus_handle_new_g_variant_tuple();
3121 return g_variant_new("(issssssisibii)",
3123 nullstr(data->devnode),
3124 nullstr(data->syspath),
3125 nullstr(data->fs_usage),
3126 nullstr(data->fs_type),
3127 nullstr(data->fs_version),
3128 nullstr(data->fs_uuid_enc),
3130 nullstr(data->mount_point),
3133 flags >= 0 ? flags : data->flags,
3137 static GVariant *block_data_to_gvariant2(struct block_data *data, int flags)
3140 return dbus_handle_new_g_variant_tuple();
3142 return g_variant_new("(issssssisibi)",
3144 nullstr(data->devnode),
3145 nullstr(data->syspath),
3146 nullstr(data->fs_usage),
3147 nullstr(data->fs_type),
3148 nullstr(data->fs_version),
3149 nullstr(data->fs_uuid_enc),
3151 nullstr(data->mount_point),
3154 flags >= 0 ? flags : data->flags);
3158 //static int add_device_to_struct_iter(struct block_data *data, DBusMessageIter *iter)
3160 // //DBusMessageIter piter;
3162 // //if (!data || !iter)
3163 // // return -EINVAL;
3165 // //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3166 // //add_device_to_iter(data, &piter);
3167 // //dbus_message_iter_close_container(iter, &piter);
3172 //static int add_device_to_iter_2(struct block_data *data, DBusMessageIter *iter)
3174 // DBusMessageIter piter;
3175 // char *str_null = "";
3177 // if (!data || !iter)
3180 // //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3181 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3182 // // &(data->block_type));
3183 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3184 // // data->devnode ? &(data->devnode) : &str_null);
3185 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3186 // // data->syspath ? &(data->syspath) : &str_null);
3187 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3188 // // data->fs_usage ? &(data->fs_usage) : &str_null);
3189 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3190 // // data->fs_type ? &(data->fs_type) : &str_null);
3191 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3192 // // data->fs_version ? &(data->fs_version) : &str_null);
3193 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3194 // // data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
3195 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3196 // // &(data->readonly));
3197 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3198 // // data->mount_point ? &(data->mount_point) : &str_null);
3199 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3200 // // &(data->state));
3201 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_BOOLEAN,
3202 // // &(data->primary));
3203 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3204 // // &(data->flags));
3205 // //dbus_message_iter_close_container(iter, &piter);
3210 static GVariant *request_get_device_info(GDBusConnection *conn,
3211 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3212 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3214 struct block_device *bdev = NULL;
3215 struct block_data *data = NULL;
3216 struct block_data nodata = {0,};
3219 g_variant_get(param, "(i)", &id);
3221 bdev = find_block_device_by_id(id);
3230 nodata.id = -ENODEV;
3234 return block_data_to_gvariant(data, -1);
3237 static GVariant *request_show_device_list(GDBusConnection *conn,
3238 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3239 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3241 show_block_device_list();
3242 return dbus_handle_new_g_variant_tuple();
3245 static enum block_device_type get_bdev_type_from_type_string(const char *type_str)
3248 return BLOCK_UNKNOWN_DEV;
3250 if (strcmp(type_str, BLOCK_TYPE_SCSI) == 0)
3251 return BLOCK_SCSI_DEV;
3252 if (strcmp(type_str, BLOCK_TYPE_MMC) == 0)
3253 return BLOCK_MMC_DEV;
3254 if (strcmp(type_str, BLOCK_TYPE_ALL) == 0)
3255 return BLOCK_ALL_DEV;
3257 return BLOCK_UNKNOWN_DEV;
3260 // Called by MainThread
3261 static GVariant *request_get_device_list(GDBusConnection *conn,
3262 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3263 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3265 GVariant *reply = NULL;
3266 struct block_device *bdev;
3267 struct block_data *data;
3270 enum block_device_type block_type;
3273 GVariantBuilder *builder = NULL;
3274 const char *error = NULL;
3276 g_variant_get(param, "(s)", &type);
3278 _E("Delivered type is NULL.");
3279 error = "Delivered type is NULL";
3283 _D("Block (%s) device list is requested.", type);
3285 block_type = get_bdev_type_from_type_string(type);
3286 if (block_type == BLOCK_UNKNOWN_DEV) {
3287 _E("Invalid type (%s) is requested.", type);
3288 error = "Invalid type is requested";
3292 builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibii)"));
3295 for (i = 0; i < THREAD_MAX; i++) {
3296 pthread_mutex_lock(&(th_manager[i].mutex));
3297 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3298 if (!bdev->data || bdev->removed)
3303 if (block_type != BLOCK_ALL_DEV) {
3304 if (data->block_type != block_type)
3308 g_variant_builder_add(builder, "(issssssisibii)",
3310 nullstr(data->devnode),
3311 nullstr(data->syspath),
3312 nullstr(data->fs_usage),
3313 nullstr(data->fs_type),
3314 nullstr(data->fs_version),
3315 nullstr(data->fs_uuid_enc),
3317 nullstr(data->mount_point),
3324 pthread_mutex_unlock(&(th_manager[i].mutex));
3326 /* if nothing is added, then gvariant(empty body) is generated */
3327 if (item_cnt == 0) {
3328 _E("Not found matched device(%s).", type);
3329 error = "Not found matched device";
3333 reply = g_variant_new("(a(issssssisibii))", builder);
3337 g_variant_builder_unref(builder);
3342 g_dbus_method_invocation_return_error(invocation,
3343 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3348 // Called by MainThread
3349 static GVariant *request_get_device_list_2(GDBusConnection *conn,
3350 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3351 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3353 GVariant *reply = NULL;
3354 struct block_device *bdev;
3355 struct block_data *data;
3358 enum block_device_type block_type;
3361 GVariantBuilder *builder = NULL;
3362 const char *error = NULL;
3364 g_variant_get(param, "(s)", &type);
3366 _E("Delivered type is NULL.");
3367 error = "Delivered type is NULL";
3371 _D("Block (%s) device list is requested.", type);
3373 block_type = get_bdev_type_from_type_string(type);
3374 if (block_type == BLOCK_UNKNOWN_DEV) {
3375 _E("Invalid type (%s) is requested.", type);
3376 error = "Invalid type is requested";
3380 builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibi)"));
3383 for (i = 0; i < THREAD_MAX; i++) {
3384 pthread_mutex_lock(&(th_manager[i].mutex));
3385 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3386 if (!bdev->data || bdev->removed)
3391 if (block_type != BLOCK_ALL_DEV) {
3392 if (data->block_type != block_type)
3396 g_variant_builder_add(builder, "(issssssisibi)",
3398 nullstr(data->devnode),
3399 nullstr(data->syspath),
3400 nullstr(data->fs_usage),
3401 nullstr(data->fs_type),
3402 nullstr(data->fs_version),
3403 nullstr(data->fs_uuid_enc),
3405 nullstr(data->mount_point),
3411 pthread_mutex_unlock(&(th_manager[i].mutex));
3413 /* if nothing is added, then gvariant(empty body) is generated */
3414 if (item_cnt == 0) {
3415 _E("Not found matched device(%s).", type);
3416 error = "Not found matched device";
3420 reply = g_variant_new("(a(issssssisibi))", builder);
3424 g_variant_builder_unref(builder);
3429 g_dbus_method_invocation_return_error(invocation,
3430 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3435 static GVariant *request_get_mmc_primary(GDBusConnection *conn,
3436 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3437 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3439 struct block_device *bdev;
3440 struct block_data *data, nodata = {0,};
3445 for (i = 0; i < THREAD_MAX; i++) {
3446 pthread_mutex_lock(&(th_manager[i].mutex));
3447 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3453 if (data->block_type != BLOCK_MMC_DEV &&
3454 data->block_type != BLOCK_EXTENDEDSD_DEV)
3458 // Return mapper node(/dev/mapper/extendedsd) for primary mmc (not /dev/mmcblk1p1(ex))
3459 if (!strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
3464 pthread_mutex_unlock(&(th_manager[i].mutex));
3470 nodata.id = -ENODEV;
3474 return block_data_to_gvariant(data, -1);
3477 static GVariant *request_check_speed(GDBusConnection *conn,
3478 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3479 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3481 struct timespec start_time, end_time;
3482 struct block_device *bdev;
3483 struct block_data *data;
3491 g_variant_get(param, "(i)", &id);
3493 bdev = find_block_device_by_id(id);
3504 _D("Speed check %s.", data->devnode);
3505 fd = open(data->devnode, O_RDONLY | O_DIRECT);
3507 _E("Failed to open fd(%s): %d", data->devnode, errno);
3511 ret = posix_memalign((void**)&buf, 4096, SPEEDCHECK_SIZE << 20);
3513 _E("Failed to posix_memalign().");
3518 clock_gettime(CLOCK_REALTIME, &start_time);
3519 _I("Start time=%lu.%lu", start_time.tv_sec, start_time.tv_nsec);
3520 ret = read(fd, buf, SPEEDCHECK_SIZE << 20);
3521 clock_gettime(CLOCK_REALTIME, &end_time);
3522 _I("End time=%lu.%lu", end_time.tv_sec, end_time.tv_nsec);
3527 _E("Failed to read(): %d", errno);
3532 time_diff = end_time.tv_sec - start_time.tv_sec;
3533 if (time_diff > 0 && (SPEEDCHECK_SIZE / time_diff < SPEEDCHECK_CRITERION)) {
3541 return g_variant_new("(i)", result);
3545 static GVariant *request_control_block(GDBusConnection *conn,
3546 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3547 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3552 g_variant_get(param, "(i)", &enable);
3556 _I("Control block disable.");
3561 _I("Control block enable.");
3566 _E("Control block. Wrong request by client.");
3571 return g_variant_new("(i)", result);
3574 static GVariant *request_getcontrol_block(GDBusConnection *conn,
3575 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3576 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3580 _I("Get control block.");
3582 result = block_control;
3584 return g_variant_new("(i)", result);
3588 Method name Method call format string Reply format string
3589 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3590 { "GetDeviceList", "s", "a(issssssisibii)", request_get_device_list },
3591 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3592 { "Mount", "is", "i", request_public_mount_block },
3593 { "Unmoun, "ii", "i", request_public_unmount_block },
3594 { "Format", "ii", "i", request_format_block },
3595 { "GetDeviceInfo", "i", "(issssssisibii)", request_get_device_info },
3596 { "GetMmcPrimary", NULL, "(issssssisibii)" , request_get_mmc_primary },
3597 { "PrivateMount", "is", "i", request_private_mount_block },
3598 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3601 static const dbus_method_s manager_methods[] = {
3602 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3603 { "GetDeviceList" , "s", "a(issssssisibii)", request_get_device_list },
3604 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3605 { "Mount", "is", "i", request_public_mount_block },
3606 { "Unmount", "ii", "i", request_public_unmount_block },
3607 { "Format", "ii", "i", request_format_block },
3608 { "FormatwithType", "iis", "i", request_format_block_type },
3609 { "GetDeviceInfo", "i", "issssssisibii", request_get_device_info },
3610 { "GetMmcPrimary", NULL, "issssssisibii", request_get_mmc_primary },
3611 { "PrivateMount", "is", "i", request_private_mount_block },
3612 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3613 { "CheckSpeed", "i", "i", request_check_speed },
3614 { "Control", "i", "i", request_control_block },
3615 { "GetControl", NULL, "i", request_getcontrol_block },
3618 static const dbus_interface_u block_interface = {
3619 .name = STORAGED_INTERFACE_BLOCK_MANAGER,
3620 .methods = manager_methods,
3621 .nr_methods = ARRAY_SIZE(manager_methods),
3624 static int load_config(struct parse_result *result, void *user_data)
3628 if (MATCH(result->section, "Block"))
3631 if (MATCH(result->section, "SCSI"))
3632 index = BLOCK_SCSI_DEV;
3633 else if (MATCH(result->section, "MMC"))
3634 index = BLOCK_MMC_DEV;
3635 else if (MATCH(result->section, "Mapper"))
3636 index = BLOCK_EXTENDEDSD_DEV;
3640 if (MATCH(result->name, "Multimount"))
3641 block_conf[index].multimount =
3642 (MATCH(result->value, "yes") ? true : false);
3643 if (MATCH(result->name, "ExtendedInternalStorage"))
3644 block_conf[index].extendedinternal =
3645 (MATCH(result->value, "yes") ? true : false);
3651 static int mount_root_path_tmpfs(void)
3656 root = tzplatform_getenv(TZ_SYS_MEDIA);
3660 if (access(root, F_OK) != 0)
3663 if (mount_check(root))
3666 ret = mount("tmpfs", root, "tmpfs", 0, "smackfsroot=System::Shared");
3669 _E("Failed to mount tmpfs: %d", ret);
3676 #define mount_root_path_tmpfs() 0
3679 static guint id_block_poweroff;
3681 static void block_init(void *data)
3689 ret = config_parse(BLOCK_CONF_FILE, load_config, NULL);
3691 _E("Failed to load '%s'. Use default value.", BLOCK_CONF_FILE);
3693 ret = mount_root_path_tmpfs();
3695 _E("Failed to mount tmpfs to root mount path: %d", ret);
3697 /* register block manager object and interface */
3698 ret = dbus_handle_register_dbus_object(NULL, STORAGED_PATH_BLOCK_MANAGER, &block_interface);
3700 _E("Failed to register block interface and methods: %d", ret);
3705 _E("Failed to init pipe.");
3707 for (i = 0; i < THREAD_MAX; i++) {
3708 th_manager[i].num_dev = 0;
3709 th_manager[i].op_len = 0;
3710 th_manager[i].start_th = false;
3711 th_manager[i].thread_id = i;
3712 pthread_mutex_init(&(th_manager[i].mutex), NULL);
3713 pthread_cond_init(&(th_manager[i].cond), NULL);
3716 ret = remove_directory(EXTERNAL_STORAGE_PATH);
3718 _E("Failed to remove directory.");
3719 ret = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3721 _E("Failed to make directory: %d", errno);
3723 ret = remove_directory(EXTENDED_INTERNAL_PATH);
3725 _E("Failed to remove directory.");
3726 ret = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3728 _E("Failed to make directory: %d", errno);
3730 ret = get_internal_storage_number();
3732 _E("Failed to get internal storage number.");
3734 id_block_poweroff = subscribe_dbus_signal(NULL, DEVICED_PATH_POWEROFF,
3735 DEVICED_INTERFACE_POWEROFF,
3736 SIGNAL_POWEROFF_STATE,
3737 block_poweroff, NULL, NULL);
3741 static void terminate_threads(void)
3743 dd_list *elem, *elem_next;
3746 const int WAIT_TIME = 10;
3748 for (i = 0; i < THREAD_MAX; i++) {
3749 if (th_manager[i].start_th) {
3751 while ((th_manager[i].op_len != 0) && (count < WAIT_TIME)) {
3752 _I("Thread(%d) job is not finished. Wait a second.", th_manager[i].thread_id);
3756 pthread_cancel(th_manager[i].th);
3757 pthread_join(th_manager[i].th, NULL);
3759 DD_LIST_FOREACH_SAFE(th_manager[i].th_node_list, elem, elem_next, temp) {
3760 DD_LIST_REMOVE(th_manager[i].th_node_list, temp);
3766 static void block_exit(void *data)
3772 /* unregister notifier for below each event */
3773 unsubscribe_dbus_signal(NULL, id_block_poweroff);
3775 /* unregister mmc uevent control routine */
3776 ret = unregister_udev_uevent_control(&uh);
3778 _E("Failed to unregister block uevent: %d", ret);
3780 /* remove remaining blocks */
3781 remove_whole_block_device();
3783 terminate_threads();
3788 block_control = false;
3791 static int block_start(void *data)
3794 _E("Cannot be started. Booting is not ready.");
3798 if (block_control) {
3799 _I("Already started.");
3803 block_control = true;
3805 block_init_from_udev_enumerate();
3811 static int block_stop(void *data)
3814 _E("Cannot be stopped. Booting is not ready.");
3818 if (!block_control) {
3819 _I("Already stopped.");
3823 /* remove the existing blocks */
3824 remove_whole_block_device();
3826 block_control = false;
3832 static storaged_module_interface block_module = {
3836 .start = block_start,
3840 __attribute__ ((visibility("default")))storaged_module_interface *
3841 storaged_get_module_interface(void)
3843 return &block_module;