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 <libgdbus/dbus-system.h>
50 #include "config-parser.h"
51 #include "module-intf.h"
55 #include "fd_handler.h"
60 * TODO Assume root device is always mmcblk0*.
62 #define MMC_PATH "*/mmcblk[0-9]*"
63 #define MMC_PARTITION_PATH "mmcblk[0-9]p[0-9]"
64 /* Emulator send devlink for sdcard as \*\/sdcard\/\* */
65 #define MMC_LINK_PATH "*/sdcard/*"
66 #define SCSI_PATH "*/sd[a-z]*"
67 #define SCSI_PARTITION_PATH "sd[a-z][0-9]"
68 #define SCSI_PARTITION_LENGTH 9
69 #define EXTENDEDSD_NODE_PATH "/dev/mapper/extendedsd"
71 #define FILESYSTEM_NAME "filesystem"
73 #define DEV_PREFIX "/dev/"
76 #define UNMOUNT_RETRY 5
77 #define TIMEOUT_MAKE_OBJECT 500 /* milliseconds */
79 #define SIGNAL_POWEROFF_STATE "ChangeState"
81 #define BLOCK_DEVICE_ADDED "DeviceAdded"
82 #define BLOCK_DEVICE_REMOVED "DeviceRemoved"
83 #define BLOCK_DEVICE_BLOCKED "DeviceBlocked"
84 #define BLOCK_DEVICE_CHANGED "DeviceChanged"
85 #define BLOCK_DEVICE_CHANGED_2 "DeviceChanged2"
87 #define BLOCK_TYPE_MMC "mmc"
88 #define BLOCK_TYPE_SCSI "scsi"
89 #define BLOCK_TYPE_ALL "all"
91 #define BLOCK_MMC_NODE_PREFIX "SDCard"
92 #define BLOCK_SCSI_NODE_PREFIX "USBDrive"
94 #define BLOCK_CONF_FILE "/etc/storaged/block.conf"
96 #define EXTERNAL_STORAGE_PATH "/run/external-storage"
97 #define EXTENDED_INTERNAL_PATH "/run/extended-internal-sd"
100 #define EXTENDEDSD_MOUNT_PATH "/opt/extendedsd"
102 #define VFAT_NAME "vfat"
103 #define EXT4_NAME "ext4"
104 #define LUKS_NAME "crypto_LUKS"
105 #define EXTENDEDSD_NAME "extendedsd"
107 /* Minimum value of block id */
108 #define BLOCK_ID_MIN 10
109 /* For 2.4 Backward Compatibility */
110 #define EXT_PRIMARY_SD_FIXID 1
112 /* Maximum number of thread */
115 #define SPEEDCHECK_SIZE 16
116 #define SPEEDCHECK_CRITERION 4 /* MB/s */
118 #define PKGDIR_BUS_NAME "org.tizen.pkgdir_tool"
119 #define PKGDIR_PATH "/org/tizen/pkgdir_tool"
120 #define PKGDIR_INTERFACE "org.tizen.pkgdir_tool"
122 #define POPUP_KEY_CONTENT "_SYSPOPUP_CONTENT_"
123 #define VIEWTYPE_KEY "viewtype"
124 #define DEVPATH_KEY "dev_path"
125 #define MAPPING_NODE_KEY "mapping_node"
126 #define INSERT_SD_CARD "INSERT_SD_CARD"
128 #define MMC_POPUP_NOTI "SDcardNoti"
129 #define MMC_INSERTED "inserted"
130 #define MMC_REMOVED "removed"
132 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
134 #define FILE_NAME_LEN_MAX 255
136 enum block_dev_operation {
145 enum private_operation_state {
151 struct operation_queue {
152 enum block_dev_operation op;
153 GDBusMethodInvocation *invocation;
158 struct block_device {
159 struct block_data *data;
161 int thread_id; /* Current thread ID */
162 bool removed; /* True when device is physically removed but operation is not precessed yet */
163 enum private_operation_state on_private_op;
164 bool mount_point_updated;
169 struct block_device *bdev;
171 enum unmount_operation option;
175 enum block_dev_operation op;
176 struct block_device *bdev;
180 static struct block_conf {
182 bool extendedinternal;
183 } block_conf[BLOCK_EXTENDEDSD_DEV + 1];
185 static struct manage_thread {
186 dd_list *th_node_list; /* List of devnode which thread dealt with. Only main thread access */
187 dd_list *block_dev_list; /* Use thread mutex */
189 pthread_mutex_t mutex;
191 int num_dev; /* Number of devices which thread holds. Only main thread access */
192 int op_len; /* Number of operation of thread. Use thread mutex */
193 int thread_id; /* Never changed */
195 } th_manager[THREAD_MAX];
197 char mmc_default_path[][FILE_NAME_LEN_MAX + 1] = {
204 #define DIR_NUM ((int)(sizeof(mmc_default_path)/sizeof(mmc_default_path[0])))
206 static dd_list *fs_head;
207 static dd_list *block_ops_list;
210 static fd_handler_h phandler;
211 static bool block_control = false;
212 static bool block_boot = false;
213 static pthread_mutex_t pipe_mutex = PTHREAD_MUTEX_INITIALIZER;
215 /* Assume there is only one physical internal storage */
216 static int dev_internal = -1;
217 static char dev_internal_scsi = '\0';
218 static char dev_internal_emul = '\0';
220 static int block_start(void *data);
221 static int block_stop(void *data);
223 static int add_operation(struct block_device *bdev,
224 enum block_dev_operation operation,
225 GDBusMethodInvocation *invocation, void *data);
226 static void remove_operation(struct block_device *bdev);
227 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
228 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
229 static int change_mount_point(struct block_device *bdev, const char *mount_point);
231 #define nullstr(x) (x ? x : "")
232 static GVariant *block_data_to_gvariant(struct block_data *data, int flags);
233 static GVariant *block_data_to_gvariant2(struct block_data *data, int flags);
235 #define block_send_dbus_reply(invocation, result) if (invocation) {g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", result)); }
237 static void uevent_block_handler(struct udev_device *dev);
238 static struct uevent_handler uh = {
239 .subsystem = BLOCK_SUBSYSTEM,
240 .uevent_func = uevent_block_handler,
243 static void __CONSTRUCTOR__ smack_check(void)
248 fp = fopen("/proc/filesystems", "r");
252 while (fgets(buf, sizeof(buf), fp) != NULL) {
253 if (strstr(buf, "smackfs")) {
262 void add_fs(const struct block_fs_ops *fs)
264 DD_LIST_APPEND(fs_head, (void *)fs);
267 void remove_fs(const struct block_fs_ops *fs)
269 DD_LIST_REMOVE(fs_head, (void *)fs);
272 const struct block_fs_ops *find_fs(enum block_fs_type type)
274 struct block_fs_ops *fs;
277 DD_LIST_FOREACH(fs_head, elem, fs) {
278 if (fs->type == type)
284 void add_block_dev(const struct block_dev_ops *ops)
286 DD_LIST_APPEND(block_ops_list, (void *)ops);
289 void remove_block_dev(const struct block_dev_ops *ops)
291 DD_LIST_REMOVE(block_ops_list, (void *)ops);
294 static void broadcast_block_info(enum block_dev_operation op,
295 struct block_data *data, int result)
297 struct block_dev_ops *ops;
300 if (data->primary != true)
303 DD_LIST_FOREACH(block_ops_list, elem, ops) {
304 int data_block_type = (data->block_type == BLOCK_EXTENDEDSD_DEV)
305 ? BLOCK_MMC_DEV : data->block_type;
307 if (ops->block_type != data_block_type)
309 // TODO What happend on extended internal storage case?
310 if (op == BLOCK_DEV_MOUNT) {
311 ops->mounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
312 } else if (op == BLOCK_DEV_UNMOUNT) {
313 ops->unmounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
314 } else if (op == BLOCK_DEV_FORMAT) {
315 ops->formatted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
316 } else if (op == BLOCK_DEV_INSERT)
318 else if (op == BLOCK_DEV_REMOVE)
323 // Called by MainThread - Insert
324 static int block_get_new_id(void)
326 static int id = BLOCK_ID_MIN;
327 struct block_device *bdev;
332 for (i = 0 ; i < INT_MAX ; i++) {
334 for (j = 0; j < THREAD_MAX; j++) {
335 pthread_mutex_lock(&(th_manager[j].mutex));
336 DD_LIST_FOREACH(th_manager[j].block_dev_list, elem, bdev) {
337 if (bdev->data->id == id) {
342 pthread_mutex_unlock(&(th_manager[j].mutex));
357 static void remove_file(int id, bool extendedsd)
359 char file_name[PATH_LEN];
366 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
368 snprintf(file_name, sizeof(file_name), EXTERNAL_STORAGE_PATH"/%d", id);
370 ret = remove(file_name);
372 _E("Fail to remove %s. errno: %d", file_name, errno);
375 static void create_file(int id, char *mount_point, bool extendedsd)
378 char file_name[PATH_LEN];
384 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
386 snprintf(file_name, PATH_LEN, EXTERNAL_STORAGE_PATH"/%d", id);
388 fp = fopen(file_name, "w+");
390 fprintf(fp, "%s", mount_point);
393 _E("Fail to open %s", file_name);
396 static void signal_device_blocked(struct block_device *bdev)
398 struct block_data *data;
400 if (!bdev || !bdev->data)
405 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
406 STORAGED_INTERFACE_BLOCK_MANAGER,
407 BLOCK_DEVICE_BLOCKED,
408 block_data_to_gvariant(data, 0));
411 static void signal_device_changed(struct block_device *bdev,
412 enum block_dev_operation op)
414 struct block_data *data;
415 GVariant *var = NULL;
418 if (!bdev || !bdev->data)
424 case BLOCK_DEV_MOUNT:
425 BLOCK_GET_MOUNT_FLAGS(data, flags);
427 case BLOCK_DEV_UNMOUNT:
428 BLOCK_GET_UNMOUNT_FLAGS(data, flags);
430 case BLOCK_DEV_FORMAT:
431 BLOCK_GET_FORMAT_FLAGS(data, flags);
438 /* Broadcast outside with BlockManager iface */
439 var = block_data_to_gvariant(data, flags);
441 if (op == BLOCK_DEV_INSERT)
442 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
443 STORAGED_INTERFACE_BLOCK_MANAGER,
446 else if (op == BLOCK_DEV_REMOVE)
447 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
448 STORAGED_INTERFACE_BLOCK_MANAGER,
449 BLOCK_DEVICE_REMOVED,
452 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
453 STORAGED_INTERFACE_BLOCK_MANAGER,
454 BLOCK_DEVICE_CHANGED,
456 dbus_handle_broadcast_dbus_signal_var(STORAGED_PATH_BLOCK_MANAGER,
457 STORAGED_INTERFACE_BLOCK_MANAGER,
458 BLOCK_DEVICE_CHANGED_2,
459 block_data_to_gvariant2(data, flags));
463 static int get_mmc_mount_node(char *devnode, char *node, size_t len)
465 char *name = devnode;
466 int dev = -1, part = -1;
467 char emul[32] = { 0, };
474 sscanf(name, "mmcblk%dp%d", &dev, &part);
477 snprintf(node, len, "%s%c", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1);
479 snprintf(node, len, "%s%c%d", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1, part);
484 sscanf(name, "vd%31s", emul);
487 for (i = 0 ; i < strlen(emul) ; i++)
488 emul[i] = toupper(emul[i]);
489 snprintf(node, len, "%s%s", BLOCK_MMC_NODE_PREFIX, emul);
493 static int get_scsi_mount_node(char *devnode, char *node, size_t len)
501 snprintf(dev, sizeof(dev), "%s", devnode);
503 if (!strstr(dev, "sd"))
507 name += strlen("sd");
509 for (i = 0 ; i < strlen(name) ; i++)
510 name[i] = toupper(name[i]);
511 snprintf(node, len, "%s%s", BLOCK_SCSI_NODE_PREFIX, name);
516 static char *generate_mount_path(struct block_data *data)
519 char *name, node[64];
522 if (!data || !data->devnode || !data->fs_usage || (strcmp(data->fs_usage, FILESYSTEM_NAME) && strncmp(data->fs_usage, "crypto", strlen("crypto"))))
525 name = strrchr(data->devnode, '/');
530 switch (data->block_type) {
532 ret = get_mmc_mount_node(name, node, sizeof(node));
535 ret = get_scsi_mount_node(name, node, sizeof(node));
537 case BLOCK_EXTENDEDSD_DEV:
538 return strdup(EXTENDEDSD_MOUNT_PATH);
540 _E("Invalid block type (%d)", data->block_type);
546 str = tzplatform_mkpath(TZ_SYS_MEDIA, node);
552 _E("Invalid devnode (%s)", data->devnode ? data->devnode : "NULL");
556 static bool check_primary_partition(const char *devnode)
558 struct block_fs_ops *fs;
561 const char *filesystem = NULL;
571 if (fnmatch(MMC_LINK_PATH, devnode, 0) &&
572 fnmatch(MMC_PATH, devnode, 0) &&
573 fnmatch(SCSI_PATH, devnode, 0) &&
574 fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
577 temp = strrchr(devnode, '/');
580 if (fnmatch("/"SCSI_PARTITION_PATH, temp, 0) &&
581 fnmatch("/"MMC_PARTITION_PATH, temp, 0))
584 /* Emulator support only one partition */
588 snprintf(str, sizeof(str), "%s", devnode);
593 for (i = 1; i <= 9; ++i) {
594 snprintf(str2, sizeof(str2), "%s%d", str, i);
595 if (access(str2, R_OK) != 0)
598 probe = blkid_new_probe_from_filename(str2);
601 if (blkid_do_probe(probe) != 0)
604 ret = blkid_probe_lookup_value(probe, "TYPE", &filesystem, &fs_len);
606 blkid_free_probe(probe);
609 DD_LIST_FOREACH(fs_head, elem, fs) {
610 if (!strncmp(fs->name, filesystem, fs_len)) {
615 blkid_free_probe(probe);
621 if (found && !strncmp(devnode, str2, strlen(str2) + 1))
627 /* Whole data in struct block_data should be freed. */
628 static struct block_data *make_block_data(const char *devnode,
630 const char *fs_usage,
632 const char *fs_version,
633 const char *fs_uuid_enc,
634 const char *readonly)
636 struct block_data *data;
638 /* devnode is unique value so it should exist. */
643 _I("Unknown fs type");
645 data = calloc(1, sizeof(struct block_data));
647 _E("calloc() failed");
651 data->devnode = strdup(devnode);
653 data->syspath = strdup(syspath);
655 data->fs_usage = strdup(fs_usage);
657 data->fs_type = strdup(fs_type);
659 data->fs_version = strdup(fs_version);
661 data->fs_uuid_enc = strdup(fs_uuid_enc);
663 data->readonly = atoi(readonly);
664 data->primary = check_primary_partition(devnode);
666 /* TODO should we know block dev type? */
667 if (!fnmatch(MMC_LINK_PATH, devnode, 0))
668 data->block_type = BLOCK_MMC_DEV;
669 else if (!fnmatch(MMC_PATH, devnode, 0))
670 data->block_type = BLOCK_MMC_DEV;
671 else if (!fnmatch(SCSI_PATH, devnode, 0))
672 data->block_type = BLOCK_SCSI_DEV;
673 else if (!fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
674 data->block_type = BLOCK_EXTENDEDSD_DEV;
676 data->block_type = -1;
678 data->mount_point = generate_mount_path(data);
679 BLOCK_FLAG_CLEAR_ALL(data);
681 /* for 2.4 backward compatibility */
682 // What if storage id 1 is existed? (multi sdcard case)
683 if (data->primary == true && data->block_type == BLOCK_MMC_DEV &&
684 data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME))
685 data->id = EXT_PRIMARY_SD_FIXID;
687 data->id = block_get_new_id();
692 static void free_block_data(struct block_data *data)
698 free(data->fs_usage);
700 free(data->fs_version);
701 free(data->fs_uuid_enc);
702 free(data->mount_point);
706 static int update_block_data(struct block_data *data,
707 const char *fs_usage,
709 const char *fs_version,
710 const char *fs_uuid_enc,
711 const char *readonly,
712 bool mount_point_updated)
717 free(data->fs_usage);
718 data->fs_usage = NULL;
720 data->fs_usage = strdup(fs_usage);
723 data->fs_type = NULL;
725 data->fs_type = strdup(fs_type);
727 free(data->fs_version);
728 data->fs_version = NULL;
730 data->fs_version = strdup(fs_version);
732 free(data->fs_uuid_enc);
733 data->fs_uuid_enc = NULL;
735 data->fs_uuid_enc = strdup(fs_uuid_enc);
737 /* generate_mount_path function should be invoked
738 * after fs_uuid_enc is updated */
739 if (!mount_point_updated) {
740 free(data->mount_point);
741 data->mount_point = generate_mount_path(data);
744 data->readonly = false;
746 data->readonly = atoi(readonly);
748 BLOCK_FLAG_MOUNT_CLEAR(data);
753 static struct block_device *make_block_device(struct block_data *data)
755 struct block_device *bdev;
760 bdev = calloc(1, sizeof(struct block_device));
765 bdev->thread_id = -1;
766 bdev->removed = false;
767 bdev->on_private_op = REQ_NORMAL;
768 bdev->private_pid = 0;
769 bdev->mount_point_updated = false;
774 // Called by MainThread - Remove DevNode
775 static void free_block_device(struct block_device *bdev)
778 struct operation_queue *op;
784 thread_id = bdev->thread_id;
785 if (thread_id < 0 || thread_id >= THREAD_MAX)
788 pthread_mutex_lock(&(th_manager[thread_id].mutex));
790 th_manager[thread_id].num_dev--;
791 DD_LIST_REMOVE(th_manager[thread_id].block_dev_list, bdev);
792 free_block_data(bdev->data);
794 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
796 th_manager[thread_id].op_len--;
797 DD_LIST_REMOVE(bdev->op_queue, op);
800 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
805 // Called By MainThread - Remove Device
806 static struct block_device *find_block_device(const char *devnode)
808 struct block_device *bdev;
813 len = strlen(devnode) + 1;
814 for (i = 0; i < THREAD_MAX; i++) {
815 pthread_mutex_lock(&(th_manager[i].mutex));
816 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
817 if (bdev->data && !bdev->removed &&
818 !strncmp(bdev->data->devnode, devnode, len)) {
819 pthread_mutex_unlock(&(th_manager[i].mutex));
823 pthread_mutex_unlock(&(th_manager[i].mutex));
829 // Called By MainThread - Remove Device
830 static struct block_device *find_block_device_path(const char *mount_point)
832 struct block_device *bdev;
837 len = strlen(mount_point) + 1;
838 for (i = 0; i < THREAD_MAX; i++) {
839 pthread_mutex_lock(&(th_manager[i].mutex));
840 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
841 if (bdev->data && !bdev->removed &&
842 (bdev->data->mount_point != NULL && !strncmp(bdev->data->mount_point, mount_point, len))) {
843 pthread_mutex_unlock(&(th_manager[i].mutex));
847 pthread_mutex_unlock(&(th_manager[i].mutex));
853 // Called By MainThread - Mount,Unmount,Format,GetInfo
854 static struct block_device *find_block_device_by_id(int id)
856 struct block_device *bdev;
860 for (i = 0; i < THREAD_MAX; i++) {
861 pthread_mutex_lock(&(th_manager[i].mutex));
862 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
867 if (bdev->data->id == id) {
868 pthread_mutex_unlock(&(th_manager[i].mutex));
872 pthread_mutex_unlock(&(th_manager[i].mutex));
878 static const char *get_operation_char(enum block_dev_operation op)
881 case BLOCK_DEV_MOUNT:
884 case BLOCK_DEV_UNMOUNT:
887 case BLOCK_DEV_FORMAT:
890 case BLOCK_DEV_INSERT:
893 case BLOCK_DEV_REMOVE:
896 case BLOCK_LUKS_CLOSE:
900 _E("invalid operation (%d)", op);
904 void mmc_make_default_path(const char *mount_path)
908 char mmc_path[FILE_NAME_LEN_MAX + 1] = {0, };
910 for (i = 0; i < DIR_NUM; ++i) {
911 snprintf(mmc_path, sizeof(mmc_path), "%s/%s", mount_path, mmc_default_path[i]);
912 if (!g_file_test(mmc_path, G_FILE_TEST_IS_DIR)) {
913 _D("%s path did not exist", mmc_path);
914 ret = mkdir(mmc_path, 0777);
916 _E("mkdir failed: %d", errno);
918 /*this fuction for emulator*/
919 /*at the first time, the directroies are made permission 755*/
920 ret = chmod(mmc_path, 0777);
922 _E("chmod failed: %d", errno);
924 ret = chown(mmc_path, 0, 10001);
926 _E("chown failed: %d", errno);
931 static void create_external_apps_directory(void)
935 ret = dbus_handle_method_async(PKGDIR_BUS_NAME, PKGDIR_PATH,
936 PKGDIR_INTERFACE, "CreateExternalDirsForAllPkgs", NULL, NULL);
938 _E("Fail to create external directory");
941 static int pipe_trigger(enum block_dev_operation op,
942 struct block_device *bdev, int result)
944 struct pipe_data pdata = { op, bdev, result };
947 _D("op : %s, bdev : %p, result : %d",
948 get_operation_char(pdata.op),
949 pdata.bdev, pdata.result);
951 // Multi thread should not write at the same time
952 pthread_mutex_lock(&pipe_mutex);
953 n = write(pfds[1], &pdata, sizeof(struct pipe_data));
954 pthread_mutex_unlock(&pipe_mutex);
956 return (n != sizeof(struct pipe_data)) ? -EPERM : 0;
959 static bool pipe_cb(int fd, void *data)
961 struct pipe_data pdata = {0,};
966 n = read(fd, &pdata, sizeof(pdata));
967 if (n != sizeof(pdata) || !pdata.bdev) {
968 _E("fail to read struct pipe data");
972 _I("op : %s, bdev : %p, result : %d",
973 get_operation_char(pdata.op),
974 pdata.bdev, pdata.result);
976 if (pdata.op == BLOCK_LUKS_CLOSE)
979 if (pdata.op == BLOCK_DEV_MOUNT && pdata.result < 0) {
980 if (pdata.bdev->data->state == BLOCK_UNMOUNT) {
981 ret = change_mount_point(pdata.bdev, "");
982 /* Modify /run/external-storage/id file */
984 if (pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV)
985 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, true);
987 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, false);
992 if (pdata.op == BLOCK_DEV_MOUNT &&
993 pdata.bdev->data->state == BLOCK_MOUNT &&
994 pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
995 pdata.bdev->data->primary) {
996 create_external_apps_directory();
997 mmc_make_default_path(pdata.bdev->data->mount_point);
999 ret = dbus_handle_method_sync_var(POPUP_BUS_NAME,
1001 POPUP_INTERFACE_NOTI,
1003 g_variant_new("(s)", MMC_INSERTED));
1005 _E("Popup failed: %d", ret);
1007 if (pdata.op == BLOCK_DEV_UNMOUNT) {
1008 /* Remove file for block device /run/xxxxxx/id */
1009 remove_file(pdata.bdev->data->id, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
1011 if (pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
1012 pdata.bdev->data->primary &&
1013 BLOCK_IS_FLAG_SET(pdata.bdev->data, UNMOUNT_UNSAFE)) {
1015 ret = dbus_handle_method_sync_var(POPUP_BUS_NAME,
1017 POPUP_INTERFACE_NOTI,
1019 g_variant_new("(s)", MMC_REMOVED));
1021 _E("Popup failed: %d", ret);
1025 /* Broadcast to mmc and usb storage module */
1026 broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
1028 /* Broadcast outside with Block iface */
1029 if (pdata.bdev->on_private_op == REQ_NORMAL)
1030 signal_device_changed(pdata.bdev, pdata.op);
1031 else if (pdata.bdev->on_private_op == REQ_PRIVATE) {
1032 if (pdata.op == BLOCK_DEV_UNMOUNT) {
1033 pdata.bdev->on_private_op = REQ_NORMAL;
1034 _D("Private operation state: %d", pdata.bdev->on_private_op);
1037 if (pdata.op == BLOCK_DEV_MOUNT) {
1038 pdata.bdev->on_private_op = REQ_PRIVATE;
1039 _D("Private operation state: %d", pdata.bdev->on_private_op);
1043 if (pdata.op == BLOCK_DEV_REMOVE) {
1044 thread_id = pdata.bdev->thread_id;
1045 if (thread_id < 0 || thread_id >= THREAD_MAX)
1047 free_block_device(pdata.bdev);
1054 static int pipe_init(void)
1058 ret = pipe2(pfds, O_CLOEXEC);
1062 ret = add_fd_read_handler(pfds[0], pipe_cb,
1063 NULL, NULL, &phandler);
1065 _E("Failed to add pipe handler (%d)", ret);
1072 static void pipe_exit(void)
1075 remove_fd_read_handler(&phandler);
1085 static int mmc_check_and_unmount(const char *path)
1093 while (mount_check(path)) {
1097 if (retry > UNMOUNT_RETRY)
1104 static bool check_rw_mount(const char *szPath)
1106 struct statvfs mount_stat;
1108 if (!statvfs(szPath, &mount_stat)) {
1109 if ((mount_stat.f_flag & ST_RDONLY) == ST_RDONLY)
1115 static int retrieve_udev_device(struct block_data *data, bool mount_point_updated)
1118 struct udev_device *dev;
1119 const char *fs_type;
1120 const char *fs_usage;
1127 for (wait = 0; wait < 10; wait++) {
1130 _E("fail to create udev library context");
1134 dev = udev_device_new_from_syspath(udev, data->syspath);
1136 _E("fail to create new udev device");
1141 fs_type = udev_device_get_property_value(dev, "ID_FS_TYPE");
1142 fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE");
1143 /* fs_usage for crpto_LUKS is crypto */
1144 if (!fs_type || (strncmp(fs_type, VFAT_NAME, strlen(VFAT_NAME)) && strncmp(fs_type, EXT4_NAME, strlen(EXT4_NAME))))
1146 else if (!fs_usage || strncmp(FILESYSTEM_NAME, fs_usage, strlen(FILESYSTEM_NAME)))
1151 udev_device_unref(dev);
1155 r = update_block_data(data,
1156 udev_device_get_property_value(dev, "ID_FS_USAGE"),
1157 udev_device_get_property_value(dev, "ID_FS_TYPE"),
1158 udev_device_get_property_value(dev, "ID_FS_VERSION"),
1159 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
1160 udev_device_get_sysattr_value(dev, "ro"),
1161 mount_point_updated);
1163 _E("fail to update block data for %s", data->devnode);
1165 udev_device_unref(dev);
1170 static int block_mount(struct block_data *data)
1172 struct block_fs_ops *fs;
1177 if (!data || !data->devnode || !data->mount_point)
1180 /* check existing mounted */
1181 if (mount_check(data->mount_point))
1184 /* create mount point */
1185 if (access(data->mount_point, R_OK) != 0) {
1186 if (mkdir(data->mount_point, 0755) < 0)
1190 /* check matched file system */
1191 if (!data->fs_usage ||
1192 strncmp(data->fs_usage, FILESYSTEM_NAME,
1193 sizeof(FILESYSTEM_NAME)) != 0) {
1198 if (!data->fs_type) {
1199 _E("There is no file system");
1200 BLOCK_FLAG_SET(data, FS_EMPTY);
1206 len = strlen(data->fs_type) + 1;
1207 DD_LIST_FOREACH(fs_head, elem, fs) {
1208 if (!strncmp(fs->name, data->fs_type, len))
1213 _E("Not supported file system (%s)", data->fs_type);
1214 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1219 if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1220 r = fs->mount(false, data->devnode, data->mount_point);
1222 r = fs->mount(smack, data->devnode, data->mount_point);
1225 BLOCK_FLAG_SET(data, FS_BROKEN);
1230 r = check_rw_mount(data->mount_point);
1237 rmdir(data->mount_point);
1241 static int mount_start(struct block_device *bdev)
1243 struct block_data *data;
1251 _I("Mount Start : (%s -> %s)",
1252 data->devnode, data->mount_point);
1254 /* mount operation */
1255 r = block_mount(data);
1256 if (r != -EROFS && r < 0) {
1257 _E("fail to mount %s device : %d", data->devnode, r);
1262 data->readonly = true;
1263 BLOCK_FLAG_SET(data, MOUNT_READONLY);
1266 data->state = BLOCK_MOUNT;
1268 if (data->block_type == BLOCK_MMC_DEV) {
1269 /* app2ext_migrate_legacy_all has dbus method call to deviced */
1270 ret = app2ext_migrate_legacy_all();
1272 _E("app2ext failed");
1276 if (r < 0 && r != -EROFS)
1277 data->state = BLOCK_UNMOUNT;
1279 _I("%s result : %s, %d", __func__, data->devnode, r);
1281 if (pipe_trigger(BLOCK_DEV_MOUNT, bdev, r) < 0)
1282 _E("fail to trigger pipe");
1287 static int change_mount_point(struct block_device *bdev,
1288 const char *mount_point)
1290 struct block_data *data;
1296 free(data->mount_point);
1298 /* If the mount path already exists, the path cannot be used */
1300 access(mount_point, F_OK) != 0) {
1301 data->mount_point = strdup(mount_point);
1302 bdev->mount_point_updated = true;
1304 data->mount_point = generate_mount_path(data);
1305 bdev->mount_point_updated = false;
1311 static int mount_block_device(struct block_device *bdev)
1313 struct block_data *data;
1316 if (!bdev || !bdev->data)
1320 if (data->state == BLOCK_MOUNT) {
1321 _I("%s is already mounted", data->devnode);
1325 if (!block_conf[data->block_type].multimount &&
1327 _I("Not support multi mount by config info");
1331 r = mount_start(bdev);
1333 _E("Failed to mount (%s)", data->devnode);
1340 static int block_unmount(struct block_device *bdev,
1341 enum unmount_operation option)
1343 struct block_data *data;
1345 struct timespec time = {0,};
1347 if (!bdev || !bdev->data || !bdev->data->mount_point)
1352 if (bdev->on_private_op == REQ_NORMAL)
1353 signal_device_blocked(bdev);
1355 /* it must called before unmounting mmc */
1356 r = mmc_check_and_unmount(data->mount_point);
1359 if (option == UNMOUNT_NORMAL) {
1360 _I("Failed to unmount with normal option : %d", r);
1364 _I("Execute force unmount!");
1365 /* Force Unmount Scenario */
1370 * should unmount the below vconf key. */
1371 if ((data->block_type == BLOCK_MMC_DEV ||
1372 data->block_type == BLOCK_EXTENDEDSD_DEV) &&
1374 /* At first, notify to other app
1375 * who already access sdcard */
1376 _I("Notify to other app who already access sdcard");
1377 vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS,
1378 VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
1382 /* Second, kill app with SIGTERM */
1383 _I("Kill app with SIGTERM");
1384 terminate_process(data->mount_point, false);
1387 /* Last time, kill app with SIGKILL */
1388 _I("Kill app with SIGKILL");
1389 terminate_process(data->mount_point, true);
1392 if (umount2(data->mount_point, MNT_DETACH) != 0) {
1393 _I("Failed to unmount with lazy option : %d",
1400 /* it takes some seconds til other app completely clean up */
1401 time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER;
1402 nanosleep(&time, NULL);
1404 print_open_files(data->mount_point);
1406 r = mmc_check_and_unmount(data->mount_point);
1408 _D("Success to unmount (%s)", data->mount_point);
1414 data->state = BLOCK_UNMOUNT;
1416 if (rmdir(data->mount_point) < 0)
1417 _E("fail to remove %s directory", data->mount_point);
1422 static int unmount_block_device(struct block_device *bdev,
1423 enum unmount_operation option)
1425 struct block_data *data;
1428 if (!bdev || !bdev->data)
1432 if (data->state == BLOCK_UNMOUNT) {
1433 _I("%s is already unmounted", data->devnode);
1434 r = mmc_check_and_unmount(data->mount_point);
1436 _E("The path was existed, but could not delete it(%s)",
1441 _I("Unmount Start : (%s -> %s)",
1442 data->devnode, data->mount_point);
1444 r = block_unmount(bdev, option);
1446 _E("fail to unmount %s device : %d", data->devnode, r);
1450 BLOCK_FLAG_MOUNT_CLEAR(data);
1453 _I("%s result : %s, %d", __func__, data->devnode, r);
1455 if (pipe_trigger(BLOCK_DEV_UNMOUNT, bdev, r) < 0)
1456 _E("fail to trigger pipe");
1461 static int block_format(struct block_data *data,
1462 const char *fs_type, bool mount_point_updated)
1464 const struct block_fs_ops *fs;
1470 if (!data || !data->devnode || !data->mount_point)
1473 if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1479 fstype = data->fs_type;
1485 len = strlen(fstype);
1486 DD_LIST_FOREACH(fs_head, elem, fs) {
1487 if (!strncmp(fs->name, fstype, len))
1492 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1493 _E("not supported file system(%s)", fstype);
1497 _I("format path : %s", data->devnode);
1498 fs->check(data->devnode);
1499 r = fs->format(data->devnode);
1501 _E("fail to format block data for %s", data->devnode);
1505 /* need to update the partition data.
1506 * It can be changed in doing format. */
1507 retrieve_udev_device(data, mount_point_updated);
1512 static int format_block_device(struct block_device *bdev,
1513 const char *fs_type,
1514 enum unmount_operation option)
1516 struct block_data *data;
1524 _I("Format Start : (%s -> %s)",
1525 data->devnode, data->mount_point);
1527 if (data->state == BLOCK_MOUNT) {
1528 r = block_unmount(bdev, option);
1530 _E("fail to unmount %s device : %d", data->devnode, r);
1535 r = block_format(data, fs_type, bdev->mount_point_updated);
1537 _E("fail to format %s device : %d", data->devnode, r);
1540 _I("%s result : %s, %d", __func__, data->devnode, r);
1542 r = pipe_trigger(BLOCK_DEV_FORMAT, bdev, r);
1544 _E("fail to trigger pipe");
1549 static struct format_data *get_format_data(
1550 const char *fs_type, enum unmount_operation option)
1552 struct format_data *fdata;
1554 fdata = (struct format_data *)malloc(sizeof(struct format_data));
1556 _E("fail to allocate format data");
1561 fdata->fs_type = strdup(fs_type);
1563 fdata->fs_type = NULL;
1564 fdata->option = option;
1569 static void release_format_data(struct format_data *data)
1573 free(data->fs_type);
1578 // Called by BlockThread - Real Mount Op
1579 static int block_mount_device(struct block_device *bdev, void *data)
1588 thread_id = bdev->thread_id;
1589 if (thread_id < 0 || thread_id >= THREAD_MAX)
1591 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1592 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1593 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1595 _E("(%d) does not exist in the device list", bdev->data->devnode);
1599 /* mount automatically */
1600 ret = mount_block_device(bdev);
1602 _E("fail to mount block device for %s", bdev->data->devnode);
1607 // Called by BlockThread - Real Format Op
1608 static int block_format_device(struct block_device *bdev, void *data)
1613 struct format_data *fdata = (struct format_data *)data;
1615 if (!bdev || !fdata) {
1620 thread_id = bdev->thread_id;
1621 if (thread_id < 0 || thread_id >= THREAD_MAX)
1623 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1624 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1625 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1627 _E("(%d) does not exist in the device list", bdev->data->devnode);
1632 ret = format_block_device(bdev, fdata->fs_type, fdata->option);
1634 _E("fail to format block device for %s", bdev->data->devnode);
1637 release_format_data(fdata);
1642 // Called by BlockThread - Real Unmount Op
1643 static int block_unmount_device(struct block_device *bdev, void *data)
1646 long option = (long)data;
1651 ret = unmount_block_device(bdev, option);
1653 _E("Failed to unmount block device (%s)", bdev->data->devnode);
1660 /* Called by BlockThread - Remove Operation
1661 Direct Call at BlockThread
1662 Previously this function was called by MainThread. However, it will increase complexity.
1663 Need thread lock before to call remove_operation
1665 static void remove_operation(struct block_device *bdev)
1667 struct operation_queue *op;
1673 thread_id = bdev->thread_id;
1674 if (thread_id < 0 || thread_id >= THREAD_MAX)
1677 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
1679 _D("Remove operation (%s, %s)",
1680 get_operation_char(op->op),
1681 bdev->data->devnode);
1683 DD_LIST_REMOVE(bdev->op_queue, op);
1689 // Called by BlockThread
1690 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1692 struct operation_queue *temp;
1705 thread_id = bdev->thread_id;
1706 if (thread_id < 0 || thread_id >= THREAD_MAX)
1709 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1711 DD_LIST_FOREACH(*queue, l, temp) {
1712 if (temp->op == BLOCK_DEV_REMOVE) {
1717 th_manager[thread_id].op_len--;
1718 block_send_dbus_reply((*op)->invocation, 0);
1721 remove_operation(bdev);
1722 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1725 // Called by BlockThread
1726 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1728 struct operation_queue *temp;
1731 bool unmounted = false;
1742 thread_id = bdev->thread_id;
1743 if (thread_id < 0 || thread_id >= THREAD_MAX)
1746 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1747 DD_LIST_FOREACH(*queue, l, temp) {
1748 if (temp->op == BLOCK_DEV_UNMOUNT) {
1750 _D("Operation queue has unmount operation");
1754 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1759 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1761 DD_LIST_FOREACH(*queue, l, temp) {
1762 if (temp->op == BLOCK_DEV_UNMOUNT) {
1767 th_manager[thread_id].op_len--;
1768 block_send_dbus_reply((*op)->invocation, 0);
1771 remove_operation(bdev);
1772 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1777 // Called by BlockThread
1778 static void trigger_operation(struct block_device *bdev, dd_list *queue, struct operation_queue *op)
1782 char devnode[PATH_MAX];
1783 enum block_dev_operation operation;
1784 bool unmounted = false;
1791 thread_id = bdev->thread_id;
1792 if (thread_id < 0 || thread_id >= THREAD_MAX)
1795 snprintf(devnode, sizeof(devnode), "%s", bdev->data->devnode);
1805 _D("Thread id %d Trigger operation (%s, %s)", thread_id,
1806 get_operation_char(operation), devnode);
1809 if (operation == BLOCK_DEV_INSERT && bdev->removed) {
1810 check_removed(bdev, &queue, &op);
1812 _D("Trigger operation again (%s, %s)",
1813 get_operation_char(operation), devnode);
1815 if (operation == BLOCK_DEV_MOUNT) {
1816 unmounted = check_unmount(bdev, &queue, &op);
1819 _D("Trigger operation again (%s, %s)",
1820 get_operation_char(operation), devnode);
1824 switch (operation) {
1825 case BLOCK_DEV_INSERT:
1827 case BLOCK_DEV_MOUNT:
1828 ret = block_mount_device(bdev, op->data);
1829 _D("Mount (%s) result:(%d)", devnode, ret);
1831 case BLOCK_DEV_FORMAT:
1832 ret = block_format_device(bdev, op->data);
1833 _D("Format (%s) result:(%d)", devnode, ret);
1835 case BLOCK_DEV_UNMOUNT:
1836 ret = block_unmount_device(bdev, op->data);
1837 _D("Unmount (%s) result:(%d)", devnode, ret);
1839 case BLOCK_DEV_REMOVE:
1842 case BLOCK_LUKS_CLOSE:
1843 ret = ode_luks_close_sync(EXTENDEDSD_NAME);
1845 _E("Failed on ode_luks_close(%s)", EXTENDEDSD_NAME);
1848 _E("Operation type is invalid (%d)", op->op);
1854 * during checking the queue length */
1855 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1858 th_manager[thread_id].op_len--;
1860 block_send_dbus_reply(op->invocation, ret);
1862 queue = bdev->op_queue;
1863 if (queue != NULL) {
1864 queue = DD_LIST_NEXT(queue);
1866 op = DD_LIST_NTH(queue, 0);
1872 remove_operation(bdev);
1874 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1877 if (operation == BLOCK_DEV_INSERT || operation == BLOCK_DEV_REMOVE || operation == BLOCK_LUKS_CLOSE) {
1878 if (pipe_trigger(operation, bdev, 0) < 0)
1879 _E("fail to trigger pipe");
1886 // Called by BlockThread
1887 static void *block_th_start(void *arg)
1889 struct block_device *temp;
1890 struct manage_thread *th = (struct manage_thread *)arg;
1891 struct operation_queue *op = NULL;
1893 dd_list *queue = NULL;
1898 thread_id = th->thread_id;
1899 if (thread_id < 0 || thread_id >= THREAD_MAX) {
1900 _E("Thread Number: %d", th->thread_id);
1905 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1906 if (th_manager[thread_id].op_len == 0) {
1907 _D("Operation queue of thread is empty");
1908 pthread_cond_wait(&(th_manager[thread_id].cond), &(th_manager[thread_id].mutex));
1909 _D("Wake up %d", thread_id);
1912 DD_LIST_FOREACH(th_manager[thread_id].block_dev_list, elem, temp) {
1913 queue = temp->op_queue;
1915 op = DD_LIST_NTH(queue, 0);
1917 _D("Operation queue for device %s is Empty", temp->data->devnode);
1921 queue = DD_LIST_NEXT(queue);
1929 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1931 if (op && !op->done)
1932 trigger_operation(temp, queue, op);
1937 // This function will be refactored later
1938 // Especially, we don't need to keep th_node_list.
1939 static int find_thread(char *devnode)
1946 int i, len, min, min_num;
1947 int dev_mmc = -1, part = -1, num;
1950 if (!fnmatch("*/"MMC_PARTITION_PATH, devnode, 0)) {
1951 sscanf(devnode, "/dev/mmcblk%dp%d", &dev_mmc, &part);
1958 snprintf(str, len, "/dev/mmcblk%d", dev_mmc);
1959 th_node = strdup(str);
1960 } else if (!fnmatch("*/"SCSI_PARTITION_PATH, devnode, 0)) {
1961 sscanf(devnode, "/dev/sd%c%d", &dev_scsi, &part);
1962 snprintf(str, SCSI_PARTITION_LENGTH, "/dev/sd%c", dev_scsi);
1963 th_node = strdup(str);
1965 th_node = strdup(devnode);
1967 len = strlen(th_node) + 1;
1970 for (i = 0; i < THREAD_MAX; i++) {
1971 DD_LIST_FOREACH(th_manager[i].th_node_list, elem, temp) {
1972 if (!strncmp(temp, th_node, len)) {
1977 if (th_manager[i].num_dev < min_num) {
1978 min_num = th_manager[i].num_dev;
1983 if (min >= 0 && min < THREAD_MAX) {
1984 DD_LIST_APPEND(th_manager[min].th_node_list, th_node);
1988 _E("Finding thread is failed");
1989 DD_LIST_APPEND(th_manager[0].th_node_list, th_node);
1993 /* Only Main thread is permmited */
1994 // Called by MainThread
1995 static int add_operation(struct block_device *bdev,
1996 enum block_dev_operation operation,
1997 GDBusMethodInvocation *invocation, void *data)
1999 struct operation_queue *op;
2008 _I("Add operation (%s, %s)",
2009 get_operation_char(operation),
2010 bdev->data->devnode);
2012 thread_id = bdev->thread_id;
2013 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2014 _E("Fail to find thread to add");
2018 op = (struct operation_queue *)malloc(sizeof(struct operation_queue));
2020 _E("malloc failed");
2026 op->invocation = invocation;
2029 * during adding queue and checking the queue length */
2030 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2032 /* Only modified between lock and unlock of mutex */
2035 start_th = th_manager[thread_id].start_th;
2036 DD_LIST_APPEND(bdev->op_queue, op);
2037 th_manager[thread_id].op_len++;
2039 if (th_manager[thread_id].op_len == 1 && start_th)
2040 pthread_cond_signal(&(th_manager[thread_id].cond));
2042 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2045 /* Need to disble app2ext whenever unmounting mmc */
2046 if (op->op == BLOCK_DEV_UNMOUNT &&
2047 bdev->data->state == BLOCK_MOUNT &&
2048 bdev->data->block_type == BLOCK_MMC_DEV &&
2049 bdev->data->primary)
2050 if (app2ext_disable_all_external_pkgs() < 0)
2051 _E("app2ext_disable_all_external_pkgs() failed");
2055 _D("Start New thread for block device");
2056 th_manager[thread_id].start_th = true;
2057 ret = pthread_create(&(th_manager[thread_id].th), NULL, block_th_start, &th_manager[thread_id]);
2059 _E("fail to create thread for %s", bdev->data->devnode);
2063 pthread_detach(th_manager[thread_id].th);
2069 static bool disk_is_partitioned_by_kernel(struct udev_device *dev)
2072 struct dirent entry;
2074 const char *syspath;
2077 syspath = udev_device_get_syspath(dev);
2081 dp = opendir(syspath);
2083 _E("fail to open %s", syspath);
2087 /* TODO compare devname and d_name */
2088 while (readdir_r(dp, &entry, &dir) == 0 && dir != NULL) {
2089 if (!fnmatch(MMC_PARTITION_PATH, dir->d_name, 0) ||
2090 !fnmatch(SCSI_PARTITION_PATH, dir->d_name, 0)) {
2102 static bool check_partition(struct udev_device *dev)
2104 const char *devtype;
2105 const char *part_table_type;
2106 const char *fs_usage;
2109 /* only consider disk type, never partitions */
2110 devtype = udev_device_get_devtype(dev);
2114 if (strncmp(devtype, BLOCK_DEVTYPE_DISK,
2115 sizeof(BLOCK_DEVTYPE_DISK)) != 0)
2118 part_table_type = udev_device_get_property_value(dev,
2119 "ID_PART_TABLE_TYPE");
2120 if (part_table_type) {
2121 fs_usage = udev_device_get_property_value(dev,
2124 strncmp(fs_usage, FILESYSTEM_NAME, sizeof(FILESYSTEM_NAME)) == 0) {
2125 if (!disk_is_partitioned_by_kernel(dev))
2132 if (disk_is_partitioned_by_kernel(dev)) {
2141 // Called by MainThread
2142 static int add_block_device(struct udev_device *dev, const char *devnode, bool mapper)
2144 struct block_data *data;
2145 struct block_device *bdev;
2146 //char id_string[PATH_LEN];
2150 bool need_format = false;
2152 partition = check_partition(dev);
2154 /* if there is a partition, skip this request */
2155 _I("%s device has partitions, skip this time", devnode);
2159 if (mapper && !udev_device_get_property_value(dev, "ID_FS_TYPE")) {
2160 char syspath[128] = {0};
2163 r = rindex(udev_device_get_syspath(dev), '/');
2164 if (!r) return -ENODEV;
2166 snprintf(syspath, sizeof(syspath), "/sys/block%s", r);
2168 data = make_block_data(devnode,
2173 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2174 udev_device_get_sysattr_value(dev, "ro"));
2177 data = make_block_data(devnode,
2178 udev_device_get_syspath(dev),
2179 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2180 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2181 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2182 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2183 udev_device_get_sysattr_value(dev, "ro"));
2187 _E("fail to make block data for %s", devnode);
2191 if (!block_conf[data->block_type].multimount && !data->primary &&
2192 data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME)) {
2193 _D("Not support multi mount by config info");
2194 free_block_data(data);
2198 if (!block_control) {
2199 if (!mapper && strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2200 _D("Block module is disabled");
2201 free_block_data(data);
2207 bdev = make_block_device(data);
2209 _E("fail to make block device for %s", devnode);
2210 free_block_data(data);
2214 thread_id = find_thread(bdev->data->devnode);
2215 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2216 _E("Fail to find thread to add");
2217 free_block_device(bdev);
2220 bdev->thread_id = thread_id;
2222 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2223 th_manager[thread_id].num_dev++;
2224 DD_LIST_APPEND(th_manager[thread_id].block_dev_list, bdev);
2225 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2228 struct format_data *fdata;
2230 fdata = get_format_data(NULL, UNMOUNT_FORCE);
2232 _E("Failed to get format data");
2236 ret = add_operation(bdev, BLOCK_DEV_FORMAT, NULL, (void *)fdata);
2238 _E("Failed to add operation (format %s)", bdev->data->devnode);
2239 release_format_data(fdata);
2243 if (!bdev->data->fs_type) {
2244 _E("Unformatted Storage");
2245 free_block_device(bdev);
2247 } else if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2248 // bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2249 bdev->data->primary = true;
2250 _D("Need to unlock encrypted sdcard");
2251 // ---- ODE UI launch ----
2252 ret = launch_system_app(POPUP_DEFAULT
2255 , "unlockextendedsd"
2259 , bdev->data->devnode
2263 _E("Failed to launch popup");
2265 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2267 _E("Failed to add operation (insert %s)", devnode);
2268 free_block_device(bdev);
2273 } else if (mapper && !strncmp(bdev->data->fs_type, EXT4_NAME, strlen(EXT4_NAME))) {
2274 bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2275 ret = change_mount_point(bdev, EXTENDEDSD_MOUNT_PATH);
2278 free_block_device(bdev);
2283 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2285 _E("Failed to add operation (insert %s)", devnode);
2286 free_block_device(bdev);
2290 // Not a regular filesystem -> skip mounting
2291 if (!bdev->data->fs_usage || strcmp(bdev->data->fs_usage, FILESYSTEM_NAME)) {
2292 _I("Not a filesystem. Not mounting");
2296 /* Create file for block device /run/external-storage/id */
2297 create_file(bdev->data->id, bdev->data->mount_point, bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
2298 ret = add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL);
2300 _E("Failed to add operation (mount %s)", devnode);
2306 static int remove_block_device(struct udev_device *dev, const char *devnode)
2308 struct block_device *bdev;
2309 struct block_device *bdev_extended;
2312 bdev = find_block_device(devnode);
2314 _E("fail to find block data for %s", devnode);
2318 BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
2320 bdev->removed = true;
2321 if (bdev->on_private_op != REQ_NORMAL) {
2322 bdev->on_private_op = REQ_NORMAL;
2323 _D("Private operation state: %d", bdev->on_private_op);
2326 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2327 bdev_extended = find_block_device_path(EXTENDEDSD_MOUNT_PATH);
2329 if (bdev_extended) {
2330 BLOCK_FLAG_SET(bdev_extended->data, UNMOUNT_UNSAFE);
2332 bdev_extended->removed = true;
2333 if (bdev_extended->on_private_op != REQ_NORMAL) {
2334 bdev_extended->on_private_op = REQ_NORMAL;
2335 _D("Private operation state: %d", bdev_extended->on_private_op);
2338 ret = add_operation(bdev_extended, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2340 _E("Failed to add operation (unmount %s)", devnode);
2344 ret = add_operation(bdev_extended, BLOCK_LUKS_CLOSE, NULL, NULL);
2346 _E("Failed to add operation (luks_close %s)", devnode);
2350 ret = add_operation(bdev_extended, BLOCK_DEV_REMOVE, NULL, NULL);
2352 _E("Failed to add operation (remove %s)", devnode);
2356 _E("fail to find block data for extended sd card");
2359 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2361 _E("Failed to add operation (unmount %s)", devnode);
2365 ret = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2367 _E("Failed to add operation (remove %s)", devnode);
2374 static int get_internal_storage_number(void)
2376 struct libmnt_table *t = NULL;
2377 struct libmnt_fs *fs;
2380 int r = 0, dev_temp;
2382 if ((!is_emulator() && (dev_internal >= 0 || dev_internal_scsi != '\0')) ||
2383 (is_emulator() && dev_internal_emul != '\0'))
2386 t = mnt_new_table();
2390 r = mnt_table_parse_mtab(t, NULL);
2396 fs = mnt_table_find_target(t, ROOT_DIR, MNT_ITER_BACKWARD);
2402 temp = mnt_fs_get_srcpath(fs);
2406 name = strrchr(temp, '/');
2410 /* Boot from USB is not handled */
2411 if (!is_emulator()) {
2412 if (!fnmatch(MMC_PATH, temp, 0))
2413 sscanf(name, "mmcblk%d", &dev_internal);
2414 else if (!fnmatch(SCSI_PATH, temp, 0))
2415 sscanf(name, "sd%c", &dev_internal_scsi);
2417 if (!fnmatch(MMC_LINK_PATH, temp, 0))
2418 sscanf(name, "vd%c%d", &dev_internal_emul, &dev_temp);
2420 dev_internal_emul = '\0';
2428 static int check_external_storage(const char* devnode)
2430 char dev_scsi = '\0';
2433 int dev_num = -1, dev_temp;
2438 name = strrchr(devnode, '/');
2442 if (!is_emulator()) {
2443 if (!fnmatch(MMC_PATH, devnode, 0)) {
2444 sscanf(name, "mmcblk%d", &dev_num);
2445 if (dev_internal == dev_num) {
2446 _D("%s is internal storage", devnode);
2449 } else if (!fnmatch(SCSI_PATH, devnode, 0)) {
2450 sscanf(name, "sd%c", &dev_scsi);
2451 if (dev_internal_scsi == dev_scsi) {
2452 _D("%s is internal storage", devnode);
2457 if (!fnmatch(MMC_LINK_PATH, devnode, 0)) {
2458 sscanf(name, "vd%c%d", &emul, &dev_temp);
2459 if (dev_internal_emul == emul) {
2460 _D("%s is internal storage", devnode);
2469 static int check_already_handled(const char* devnode)
2471 struct block_device *bdev;
2472 struct block_data *data;
2476 for (i = 0; i < THREAD_MAX; i++) {
2477 pthread_mutex_lock(&(th_manager[i].mutex));
2478 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2484 if (!strncmp(data->devnode, devnode, strlen(devnode) + 1)) {
2485 pthread_mutex_unlock(&(th_manager[i].mutex));
2489 pthread_mutex_unlock(&(th_manager[i].mutex));
2495 static int block_init_from_udev_enumerate(void)
2498 struct udev_enumerate *enumerate;
2499 struct udev_list_entry *list_entry, *list_sub_entry;
2500 struct udev_device *dev;
2501 const char *syspath;
2502 const char *devnode;
2507 _E("fail to create udev library context");
2511 /* create a list of the devices in the 'usb' subsystem */
2512 enumerate = udev_enumerate_new(udev);
2514 _E("fail to create an enumeration context");
2518 udev_enumerate_add_match_subsystem(enumerate, BLOCK_SUBSYSTEM);
2519 udev_enumerate_add_match_property(enumerate,
2520 UDEV_DEVTYPE, BLOCK_DEVTYPE_DISK);
2521 udev_enumerate_add_match_property(enumerate,
2522 UDEV_DEVTYPE, BLOCK_DEVTYPE_PARTITION);
2523 udev_enumerate_scan_devices(enumerate);
2525 udev_list_entry_foreach(list_entry,
2526 udev_enumerate_get_list_entry(enumerate)) {
2527 syspath = udev_list_entry_get_name(list_entry);
2531 dev = udev_device_new_from_syspath(
2532 udev_enumerate_get_udev(enumerate),
2538 udev_list_entry_foreach(list_sub_entry,
2539 udev_device_get_devlinks_list_entry(dev)) {
2540 const char *devlink = udev_list_entry_get_name(list_sub_entry);
2541 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2548 devnode = udev_device_get_devnode(dev);
2550 udev_device_unref(dev);
2554 if (fnmatch(MMC_PATH, devnode, 0) &&
2555 fnmatch(SCSI_PATH, devnode, 0) &&
2556 fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0)) {
2557 udev_device_unref(dev);
2562 r = check_external_storage(devnode);
2564 udev_device_unref(dev);
2568 r = check_already_handled(devnode);
2570 _I("%s is already handled", devnode);
2571 udev_device_unref(dev);
2575 _I("%s device add", devnode);
2576 add_block_device(dev, devnode, false);
2578 udev_device_unref(dev);
2581 udev_enumerate_unref(enumerate);
2586 // Called by MainThread
2587 static void show_block_device_list(void)
2589 struct block_device *bdev;
2590 struct block_data *data;
2594 for (i = 0; i < THREAD_MAX; i++) {
2595 pthread_mutex_lock(&(th_manager[i].mutex));
2596 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2602 _D("%s:", data->devnode);
2603 _D("\tSyspath: %s", data->syspath);
2604 _D("\tBlock type: %d", data->block_type);
2605 _D("\tFs type: %s", data->fs_type);
2606 _D("\tFs usage: %s", data->fs_usage);
2607 _D("\tFs version: %s", data->fs_version);
2608 _D("\tFs uuid enc: %s", data->fs_uuid_enc);
2609 _D("\tReadonly: %s",
2610 (data->readonly ? "true" : "false"));
2611 _D("\tMount point: %s", data->mount_point);
2612 _D("\tMount state: %s",
2613 (data->state == BLOCK_MOUNT ?
2614 "mount" : "unmount"));
2616 (data->primary ? "true" : "false"));
2617 _D("\tID: %d", data->id);
2619 pthread_mutex_unlock(&(th_manager[i].mutex));
2623 // Called by MainThread
2624 static void remove_whole_block_device(void)
2626 struct block_device *bdev;
2632 for (i = 0; i < THREAD_MAX; i++) {
2634 pthread_mutex_lock(&(th_manager[i].mutex));
2635 DD_LIST_FOREACH_SAFE(th_manager[i].block_dev_list, elem, next, bdev) {
2636 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2637 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2639 if (bdev->removed == false)
2642 pthread_mutex_unlock(&(th_manager[i].mutex));
2644 if (bdev && bdev->removed == false) {
2645 bdev->removed = true;
2646 r = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2648 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
2650 r = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2652 _E("Failed to add operation (remove %s)", bdev->data->devnode);
2659 static void booting_done(GDBusConnection *conn,
2660 const gchar *sender,
2667 static int done = 0;
2675 /* register mmc uevent control routine */
2676 ret = register_udev_uevent_control(&uh);
2678 _E("fail to register block uevent : %d", ret);
2680 block_control = true;
2681 /* if there is the attached device, try to mount */
2682 block_init_from_udev_enumerate();
2687 static void block_poweroff(GDBusConnection *conn,
2688 const gchar *sender,
2695 static int status = 0;
2700 /* unregister mmc uevent control routine */
2701 unregister_udev_uevent_control(&uh);
2702 remove_whole_block_device();
2705 static void uevent_block_handler(struct udev_device *dev)
2707 const char *devnode = NULL;
2709 struct udev_list_entry *list_entry;
2711 bool mapper = false;
2713 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
2714 const char *devlink = udev_list_entry_get_name(list_entry);
2715 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2719 if (!fnmatch(EXTENDEDSD_NODE_PATH, devlink, 0)) {
2727 devnode = udev_device_get_devnode(dev);
2731 if (fnmatch(MMC_PATH, devnode, 0) &&
2732 fnmatch(SCSI_PATH, devnode, 0))
2736 r = check_external_storage(devnode);
2740 action = udev_device_get_action(dev);
2744 _I("%s device %s", devnode, action);
2745 if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD)) ||
2746 (mapper && !strcmp(action, UDEV_CHANGE))) {
2747 r = check_already_handled(devnode);
2749 _I("%s is already handled", devnode);
2753 add_block_device(dev, devnode, mapper);
2754 } else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE))) {
2755 remove_block_device(dev, devnode);
2756 } else if (!strncmp(action, UDEV_CHANGE, sizeof(UDEV_CHANGE))) {
2757 struct block_device *bdev;
2758 bdev = find_block_device(devnode);
2760 _E("fail to find block data for %s", devnode);
2763 if (!udev_device_get_property_value(dev, "ID_FS_TYPE"))
2766 r = update_block_data(bdev->data,
2767 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2768 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2769 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2770 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2771 udev_device_get_sysattr_value(dev, "ro"),
2774 _E("fail to update block data for %s", bdev->data->devnode);
2775 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2776 _I("filesystem type is updated: crypto_LUKS");
2777 if (bdev->data->fs_usage)
2778 _I("fs_usage: %s", bdev->data->fs_usage);
2782 static GVariant *request_mount_block(GDBusConnection *conn,
2783 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2784 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2786 struct block_device *bdev;
2787 char *mount_point = NULL;
2791 if (!block_control) {
2792 _D("Block module is disabled");
2797 g_variant_get(param, "(is)", &id, &mount_point);
2799 bdev = find_block_device_by_id(id);
2801 _E("Failed to find (%d) in the device list", id);
2806 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2807 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2808 _D("Mount dbus request for extended internal storage is blocked");
2813 if (bdev->on_private_op != REQ_NORMAL) {
2818 if (bdev->data->state == BLOCK_MOUNT) {
2819 _I("%s is already mounted", bdev->data->devnode);
2825 bdev->on_private_op = REQ_PRIVATE;
2826 bdev->private_pid = dbus_handle_get_sender_pid(NULL, sender);
2827 _D("Private operation state: %d pid: %d", bdev->on_private_op, bdev->private_pid);
2829 if (bdev->on_private_op != REQ_NORMAL) {
2830 _E("Failed to process mount operation");
2836 /* if requester want to use a specific mount point */
2837 if (mount_point && strncmp(mount_point, "", 1) != 0) {
2838 ret = change_mount_point(bdev, mount_point);
2844 /* Create /run/external-storage/id file */
2845 create_file(bdev->data->id, bdev->data->mount_point, false);
2847 /* Create file for block device /run/external-storage/id */
2848 create_file(bdev->data->id, bdev->data->mount_point, false);
2851 ret = add_operation(bdev, BLOCK_DEV_MOUNT, invocation, NULL);
2853 _E("Failed to add operation (mount %s)", bdev->data->devnode);
2857 g_free(mount_point);
2861 g_free(mount_point);
2862 return g_variant_new("(i)", ret);
2865 static GVariant *request_public_mount_block(GDBusConnection *conn,
2866 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2867 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2869 return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
2872 static GVariant *request_private_mount_block(GDBusConnection *conn,
2873 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2874 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2876 return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
2879 static GVariant *request_unmount_block(GDBusConnection *conn,
2880 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2881 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2883 struct block_device *bdev;
2889 if (!block_control) {
2890 _D("Block module is disabled");
2895 g_variant_get(param, "(ii)", &id, &option);
2897 bdev = find_block_device_by_id(id);
2899 _E("Failed to find (%d) in the device list", id);
2904 /* Unmount dbus call is needed when app proceeds extended internal -> portable storage */
2905 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2906 _D("Unmount dbus request for extended internal storage is blocked");
2912 pid = dbus_handle_get_sender_pid(NULL, sender);
2913 if (bdev->on_private_op == REQ_NORMAL || (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid)) {
2914 _E("Failed to process private unmount operation pid: %d private_pid: %d", pid, bdev->private_pid);
2919 if (bdev->on_private_op != REQ_NORMAL) {
2920 _E("Failed to process unmount operation");
2926 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, invocation, (void *)option);
2928 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
2932 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
2933 ret = add_operation(bdev, BLOCK_LUKS_CLOSE, NULL, NULL);
2935 _E("Failed to add operation (luks_close %s)", bdev->data->devnode);
2941 return g_variant_new("(i)", ret);
2944 static GVariant *request_public_unmount_block(GDBusConnection *conn,
2945 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2946 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2948 return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
2951 static GVariant *request_private_unmount_block(GDBusConnection *conn,
2952 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2953 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2955 return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
2958 static GVariant *request_format_block(GDBusConnection *conn,
2959 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2960 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2962 struct block_device *bdev;
2963 struct format_data *fdata;
2970 if (!block_control) {
2971 _D("Block module is disabled");
2976 g_variant_get(param, "(ii)", &id, &option);
2978 bdev = find_block_device_by_id(id);
2980 _E("Failed to find (%d) in the device list", id);
2984 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2985 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2986 _D("Format dbus request for extended internal storage is blocked");
2991 pid = dbus_handle_get_sender_pid(NULL, sender);
2992 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
2993 _E("Failed to format on private state");
2998 fdata = get_format_data(NULL, option);
3000 _E("Failed to get format data");
3004 prev_state = bdev->data->state;
3005 if (prev_state == BLOCK_MOUNT) {
3006 if (bdev->on_private_op == REQ_PRIVATE) {
3007 bdev->on_private_op = REQ_PRIVATE_FORMAT;
3008 _D("Private operation state: %d", bdev->on_private_op);
3010 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3012 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
3013 release_format_data(fdata);
3018 ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3020 _E("Failed to add operation (format %s)", bdev->data->devnode);
3021 release_format_data(fdata);
3024 /* Maintain previous state of mount/unmount */
3025 if (prev_state == BLOCK_MOUNT) {
3026 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3027 _E("Failed to add operation (mount %s)", bdev->data->devnode);
3035 return g_variant_new("(i)", ret);
3038 static GVariant *request_format_block_type(GDBusConnection *conn,
3039 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3040 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3042 struct block_device *bdev;
3043 struct format_data *fdata;
3051 if (!block_control) {
3052 _D("Block module is disabled");
3057 g_variant_get(param, "(iis)", &id, &option, &type);
3059 bdev = find_block_device_by_id(id);
3061 _E("Failed to find (%d) in the device list", id);
3065 /* FormatwithType dbus call is needed when app proceeds extended internal -> portable storage */
3066 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
3067 _D("FormatwithType dbus request for extended internal storage is blocked");
3072 pid = dbus_handle_get_sender_pid(NULL, sender);
3073 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
3074 _E("Failed to format on private state");
3079 fdata = get_format_data(type, option);
3081 _E("Failed to get format data");
3085 prev_state = bdev->data->state;
3086 if (prev_state == BLOCK_MOUNT) {
3087 if (bdev->on_private_op == REQ_PRIVATE) {
3088 bdev->on_private_op = REQ_PRIVATE_FORMAT;
3089 _D("Private operation state: %d", bdev->on_private_op);
3091 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3093 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
3094 release_format_data(fdata);
3099 ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3101 _E("Failed to add operation (format %s)", bdev->data->devnode);
3102 release_format_data(fdata);
3105 /* Maintain previous state of mount/unmount */
3106 if (prev_state == BLOCK_MOUNT) {
3107 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3108 _E("Failed to add operation (mount %s)", bdev->data->devnode);
3118 return g_variant_new("(i)", ret);
3121 static GVariant *block_data_to_gvariant(struct block_data *data, int flags)
3124 return dbus_handle_new_g_variant_tuple();
3126 return g_variant_new("(issssssisibii)",
3128 nullstr(data->devnode),
3129 nullstr(data->syspath),
3130 nullstr(data->fs_usage),
3131 nullstr(data->fs_type),
3132 nullstr(data->fs_version),
3133 nullstr(data->fs_uuid_enc),
3135 nullstr(data->mount_point),
3138 flags >= 0 ? flags : data->flags,
3142 static GVariant *block_data_to_gvariant2(struct block_data *data, int flags)
3145 return dbus_handle_new_g_variant_tuple();
3147 return g_variant_new("(issssssisibi)",
3149 nullstr(data->devnode),
3150 nullstr(data->syspath),
3151 nullstr(data->fs_usage),
3152 nullstr(data->fs_type),
3153 nullstr(data->fs_version),
3154 nullstr(data->fs_uuid_enc),
3156 nullstr(data->mount_point),
3159 flags >= 0 ? flags : data->flags);
3163 //static int add_device_to_struct_iter(struct block_data *data, DBusMessageIter *iter)
3165 // //DBusMessageIter piter;
3167 // //if (!data || !iter)
3168 // // return -EINVAL;
3170 // //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3171 // //add_device_to_iter(data, &piter);
3172 // //dbus_message_iter_close_container(iter, &piter);
3177 //static int add_device_to_iter_2(struct block_data *data, DBusMessageIter *iter)
3179 // DBusMessageIter piter;
3180 // char *str_null = "";
3182 // if (!data || !iter)
3185 // //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3186 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3187 // // &(data->block_type));
3188 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3189 // // data->devnode ? &(data->devnode) : &str_null);
3190 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3191 // // data->syspath ? &(data->syspath) : &str_null);
3192 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3193 // // data->fs_usage ? &(data->fs_usage) : &str_null);
3194 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3195 // // data->fs_type ? &(data->fs_type) : &str_null);
3196 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3197 // // data->fs_version ? &(data->fs_version) : &str_null);
3198 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3199 // // data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
3200 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3201 // // &(data->readonly));
3202 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3203 // // data->mount_point ? &(data->mount_point) : &str_null);
3204 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3205 // // &(data->state));
3206 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_BOOLEAN,
3207 // // &(data->primary));
3208 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3209 // // &(data->flags));
3210 // //dbus_message_iter_close_container(iter, &piter);
3215 static GVariant *request_get_device_info(GDBusConnection *conn,
3216 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3217 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3219 struct block_device *bdev = NULL;
3220 struct block_data *data = NULL;
3223 g_variant_get(param, "(i)", &id);
3225 bdev = find_block_device_by_id(id);
3233 return block_data_to_gvariant(data, -1);
3236 static GVariant *request_show_device_list(GDBusConnection *conn,
3237 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3238 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3240 show_block_device_list();
3241 return dbus_handle_new_g_variant_tuple();
3243 // Called by MainThread
3244 static GVariant *request_get_device_list(GDBusConnection *conn,
3245 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3246 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3248 GVariant *reply = NULL;
3249 struct block_device *bdev;
3250 struct block_data *data;
3255 GVariantBuilder *builder = NULL;
3257 g_variant_get(param, "(s)", &type);
3260 _E("Delivered type is NULL");
3264 _D("Block (%s) device list is requested", type);
3266 if (!strncmp(type, BLOCK_TYPE_SCSI, sizeof(BLOCK_TYPE_SCSI)))
3267 block_type = BLOCK_SCSI_DEV;
3268 else if (!strncmp(type, BLOCK_TYPE_MMC, sizeof(BLOCK_TYPE_MMC)))
3269 block_type = BLOCK_MMC_DEV;
3270 else if (!strncmp(type, BLOCK_TYPE_ALL, sizeof(BLOCK_TYPE_ALL)))
3273 _E("Invalid type (%s) is requested", type);
3277 builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibii)"));
3279 for (i = 0; i < THREAD_MAX; i++) {
3280 pthread_mutex_lock(&(th_manager[i].mutex));
3281 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3288 switch (block_type) {
3289 case BLOCK_SCSI_DEV:
3291 if (data->block_type != block_type)
3298 g_variant_builder_add(builder, "(issssssisibii)",
3300 nullstr(data->devnode),
3301 nullstr(data->syspath),
3302 nullstr(data->fs_usage),
3303 nullstr(data->fs_type),
3304 nullstr(data->fs_version),
3305 nullstr(data->fs_uuid_enc),
3307 nullstr(data->mount_point),
3313 pthread_mutex_unlock(&(th_manager[i].mutex));
3315 reply = g_variant_new("(a(issssssisibii))", builder);
3316 g_variant_builder_unref(builder);
3321 reply = dbus_handle_new_g_variant_tuple();
3325 // Called by MainThread
3326 static GVariant *request_get_device_list_2(GDBusConnection *conn,
3327 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3328 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3330 GVariant *reply = NULL;
3331 struct block_device *bdev;
3332 struct block_data *data;
3337 GVariantBuilder *builder = NULL;
3339 g_variant_get(param, "(s)", &type);
3342 _E("Delivered type is NULL");
3346 _D("Block (%s) device list is requested", type);
3348 if (!strncmp(type, BLOCK_TYPE_SCSI, sizeof(BLOCK_TYPE_SCSI)))
3349 block_type = BLOCK_SCSI_DEV;
3350 else if (!strncmp(type, BLOCK_TYPE_MMC, sizeof(BLOCK_TYPE_MMC)))
3351 block_type = BLOCK_MMC_DEV;
3352 else if (!strncmp(type, BLOCK_TYPE_ALL, sizeof(BLOCK_TYPE_ALL)))
3355 _E("Invalid type (%s) is requested", type);
3359 builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibi)"));
3361 for (i = 0; i < THREAD_MAX; i++) {
3362 pthread_mutex_lock(&(th_manager[i].mutex));
3363 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3370 switch (block_type) {
3371 case BLOCK_SCSI_DEV:
3373 if (data->block_type != block_type)
3380 g_variant_builder_add(builder, "(issssssisibi)",
3382 nullstr(data->devnode),
3383 nullstr(data->syspath),
3384 nullstr(data->fs_usage),
3385 nullstr(data->fs_type),
3386 nullstr(data->fs_version),
3387 nullstr(data->fs_uuid_enc),
3389 nullstr(data->mount_point),
3394 pthread_mutex_unlock(&(th_manager[i].mutex));
3396 reply = g_variant_new("(a(issssssisibi))", builder);
3397 g_variant_builder_unref(builder);
3404 static GVariant *request_get_mmc_primary(GDBusConnection *conn,
3405 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3406 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3408 struct block_device *bdev;
3409 struct block_data *data, nodata = {0,};
3414 for (i = 0; i < THREAD_MAX; i++) {
3415 pthread_mutex_lock(&(th_manager[i].mutex));
3416 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3422 if (data->block_type != BLOCK_MMC_DEV &&
3423 data->block_type != BLOCK_EXTENDEDSD_DEV)
3427 // Return mapper node(/dev/mapper/extendedsd) for primary mmc (not /dev/mmcblk1p1(ex))
3428 if (!strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
3433 pthread_mutex_unlock(&(th_manager[i].mutex));
3439 nodata.id = -ENODEV;
3443 return block_data_to_gvariant(data, -1);
3446 static GVariant *request_check_speed(GDBusConnection *conn,
3447 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3448 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3450 struct timespec start_time, end_time;
3451 struct block_device *bdev;
3452 struct block_data *data;
3460 g_variant_get(param, "(i)", &id);
3462 bdev = find_block_device_by_id(id);
3473 _D("speed check: %s", data->devnode);
3474 fd = open(data->devnode, O_RDONLY | O_DIRECT);
3475 ret = posix_memalign((void**)&buf, 4096, SPEEDCHECK_SIZE << 20);
3477 _E("posix_memalign() failed");
3482 clock_gettime(CLOCK_REALTIME, &start_time);
3483 _I("start time: %lu.%lu", start_time.tv_sec, start_time.tv_nsec);
3484 ret = read(fd, buf, SPEEDCHECK_SIZE << 20);
3485 clock_gettime(CLOCK_REALTIME, &end_time);
3486 _I("end time %lu.%lu", end_time.tv_sec, end_time.tv_nsec);
3491 _E("read() failed %d", errno);
3496 time_diff = end_time.tv_sec - start_time.tv_sec;
3497 if (time_diff > 0 && (SPEEDCHECK_SIZE / time_diff < SPEEDCHECK_CRITERION)) {
3505 return g_variant_new("(i)", result);
3509 static GVariant *request_control_block(GDBusConnection *conn,
3510 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3511 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3516 g_variant_get(param, "(i)", &enable);
3520 _I("control block Disable");
3525 _I("control block Enable");
3530 _E("control block : Wrong request by client");
3535 return g_variant_new("(i)", result);
3538 static GVariant *request_getcontrol_block(GDBusConnection *conn,
3539 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3540 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3544 _I("getcontrol block");
3546 result = block_control;
3548 return g_variant_new("(i)", result);
3552 Method name Method call format string Reply format string
3553 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3554 { "GetDeviceList", "s", "a(issssssisibii)", request_get_device_list },
3555 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3556 { "Mount", "is", "i", request_public_mount_block },
3557 { "Unmoun, "ii", "i", request_public_unmount_block },
3558 { "Format", "ii", "i", request_format_block },
3559 { "GetDeviceInfo", "i", "(issssssisibii)", request_get_device_info },
3560 { "GetMmcPrimary", NULL, "(issssssisibii)" , request_get_mmc_primary },
3561 { "PrivateMount", "is", "i", request_private_mount_block },
3562 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3565 static const dbus_method_s manager_methods[] = {
3566 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3567 { "GetDeviceList" , "s", "a(issssssisibii)", request_get_device_list },
3568 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3569 { "Mount", "is", "i", request_public_mount_block },
3570 { "Unmount", "ii", "i", request_public_unmount_block },
3571 { "Format", "ii", "i", request_format_block },
3572 { "FormatwithType", "iis", "i", request_format_block_type },
3573 { "GetDeviceInfo", "i", "issssssisibii", request_get_device_info },
3574 { "GetMmcPrimary", NULL, "issssssisibii", request_get_mmc_primary },
3575 { "PrivateMount", "is", "i", request_private_mount_block },
3576 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3577 { "CheckSpeed", "i", "i", request_check_speed },
3578 { "Control", "i", "i", request_control_block },
3579 { "GetControl", NULL, "i", request_getcontrol_block },
3582 static const dbus_interface_u block_interface = {
3583 .name = STORAGED_INTERFACE_BLOCK_MANAGER,
3584 .methods = manager_methods,
3585 .nr_methods = ARRAY_SIZE(manager_methods),
3588 static int load_config(struct parse_result *result, void *user_data)
3592 if (MATCH(result->section, "Block"))
3595 if (MATCH(result->section, "SCSI"))
3596 index = BLOCK_SCSI_DEV;
3597 else if (MATCH(result->section, "MMC"))
3598 index = BLOCK_MMC_DEV;
3599 else if (MATCH(result->section, "Mapper"))
3600 index = BLOCK_EXTENDEDSD_DEV;
3604 if (MATCH(result->name, "Multimount"))
3605 block_conf[index].multimount =
3606 (MATCH(result->value, "yes") ? true : false);
3607 if (MATCH(result->name, "ExtendedInternalStorage"))
3608 block_conf[index].extendedinternal =
3609 (MATCH(result->value, "yes") ? true : false);
3615 static int mount_root_path_tmpfs(void)
3620 root = tzplatform_getenv(TZ_SYS_MEDIA);
3624 if (access(root, F_OK) != 0)
3627 if (mount_check(root))
3630 ret = mount("tmpfs", root, "tmpfs", 0, "smackfsroot=System::Shared");
3633 _E("tmpfs mount failed (%d)", ret);
3640 #define mount_root_path_tmpfs() 0
3643 static guint id_booting_done;
3644 static guint id_block_poweroff;
3646 static void block_init(void *data)
3655 ret = config_parse(BLOCK_CONF_FILE, load_config, NULL);
3657 _E("fail to load %s, Use default value", BLOCK_CONF_FILE);
3659 ret = mount_root_path_tmpfs();
3661 _E("Failed to mount tmpfs to root mount path (%d)", ret);
3663 /* register block manager object and interface */
3664 ret = dbus_handle_register_dbus_object(NULL, STORAGED_PATH_BLOCK_MANAGER, &block_interface);
3666 _E("Failed to register block interface and methods (%d)", ret);
3671 _E("fail to init pipe");
3673 /* System Session is loaded completely */
3674 id_booting_done = subscribe_dbus_signal(NULL, SYSTEMD_DBUS_PATH,
3675 SYSTEMD_DBUS_IFACE_MANAGER,
3676 SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED,
3677 booting_done, NULL, NULL);
3679 id_block_poweroff = subscribe_dbus_signal(NULL, DEVICED_PATH_POWEROFF,
3680 DEVICED_INTERFACE_POWEROFF,
3681 SIGNAL_POWEROFF_STATE,
3682 block_poweroff, NULL, NULL);
3684 for (i = 0; i < THREAD_MAX; i++) {
3685 th_manager[i].num_dev = 0;
3686 th_manager[i].op_len = 0;
3687 th_manager[i].start_th = false;
3688 th_manager[i].thread_id = i;
3689 pthread_mutex_init(&(th_manager[i].mutex), NULL);
3690 pthread_cond_init(&(th_manager[i].cond), NULL);
3693 ret = stat(EXTERNAL_STORAGE_PATH, &buf);
3695 ret = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3697 _E("Failed to make directory: %d", errno);
3698 } else if (!S_ISDIR(buf.st_mode)) {
3699 ret = remove(EXTERNAL_STORAGE_PATH);
3701 _E("Fail to remove %s. errno: %d", EXTERNAL_STORAGE_PATH, errno);
3702 ret = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3704 _E("Failed to make directory: %d", errno);
3706 ret = chmod(EXTERNAL_STORAGE_PATH, 0644);
3708 _E("Fail to change permissions of a file");
3711 ret = stat(EXTENDED_INTERNAL_PATH, &buf);
3713 ret = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3715 _E("Failed to make directory: %d", errno);
3716 } else if (!S_ISDIR(buf.st_mode)) {
3717 ret = remove(EXTENDED_INTERNAL_PATH);
3719 _E("Fail to remove %s. errno: %d", EXTENDED_INTERNAL_PATH, errno);
3720 ret = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3722 _E("Failed to make directory: %d", errno);
3724 ret = chmod(EXTENDED_INTERNAL_PATH, 0644);
3726 _E("Fail to change permissions of a file");
3729 ret = get_internal_storage_number();
3731 _E("Failed to get internal storage number");
3734 static void block_exit(void *data)
3736 dd_list *elem, *elem_next;
3742 /* unregister notifier for below each event */
3743 unsubscribe_dbus_signal(NULL, id_booting_done);
3744 unsubscribe_dbus_signal(NULL, id_block_poweroff);
3746 /* unregister mmc uevent control routine */
3747 ret = unregister_udev_uevent_control(&uh);
3749 _E("fail to unregister block uevent : %d", ret);
3751 /* remove remaining blocks */
3752 remove_whole_block_device();
3754 for (i = 0; i < THREAD_MAX; i++) {
3755 if (th_manager[i].start_th)
3756 pthread_cancel(th_manager[i].th);
3757 DD_LIST_FOREACH_SAFE(th_manager[i].th_node_list, elem, elem_next, temp) {
3758 DD_LIST_REMOVE(th_manager[i].th_node_list, temp);
3766 block_control = false;
3769 static int block_start(void *data)
3772 _E("Cannot be started. Booting is not ready");
3776 if (block_control) {
3777 _I("Already started");
3781 block_control = true;
3783 block_init_from_udev_enumerate();
3789 static int block_stop(void *data)
3792 _E("Cannot be stopped. Booting is not ready");
3796 if (!block_control) {
3797 _I("Already stopped");
3801 /* remove the existing blocks */
3802 remove_whole_block_device();
3804 block_control = false;
3810 static storaged_module_interface block_module = {
3814 .start = block_start,
3818 __attribute__ ((visibility("default")))storaged_module_interface *
3819 storaged_get_module_interface(void)
3821 return &block_module;