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 "config-parser.h"
46 #include "module-intf.h"
51 #include "fd_handler.h"
56 * TODO Assume root device is always mmcblk0*.
58 #define MMC_PATH "*/mmcblk[0-9]*"
59 #define MMC_PARTITION_PATH "mmcblk[0-9]p[0-9]"
60 /* Emulator send devlink for sdcard as \*\/sdcard\/\* */
61 #define MMC_LINK_PATH "*/sdcard/*"
62 #define SCSI_PATH "*/sd[a-z]*"
63 #define SCSI_PARTITION_PATH "sd[a-z][0-9]"
64 #define SCSI_PARTITION_LENGTH 9
66 #define FILESYSTEM "filesystem"
68 #define DEV_PREFIX "/dev/"
71 #define UNMOUNT_RETRY 5
72 #define TIMEOUT_MAKE_OBJECT 500 /* milliseconds */
74 #define SIGNAL_POWEROFF_STATE "ChangeState"
76 #define BLOCK_DEVICE_ADDED "DeviceAdded"
77 #define BLOCK_DEVICE_REMOVED "DeviceRemoved"
78 #define BLOCK_DEVICE_BLOCKED "DeviceBlocked"
79 #define BLOCK_DEVICE_CHANGED "DeviceChanged"
80 #define BLOCK_DEVICE_CHANGED_2 "DeviceChanged2"
82 #define BLOCK_TYPE_MMC "mmc"
83 #define BLOCK_TYPE_SCSI "scsi"
84 #define BLOCK_TYPE_ALL "all"
86 #define BLOCK_MMC_NODE_PREFIX "SDCard"
87 #define BLOCK_SCSI_NODE_PREFIX "USBDrive"
89 #define BLOCK_CONF_FILE "/etc/storaged/block.conf"
91 #define EXTERNAL_STORAGE_PATH "/run/external-storage"
92 #define EXTENDED_INTERNAL_PATH "/run/extended-internal-sd"
95 #define EXTENDED_SD_PATH "/opt/extendedsd"
96 #define EXTENDED_SD_STRING "ExtendedInternalSD"
98 #define EXT4_NAME "ext4"
99 #define LUKS_NAME "crypto_LUKS"
101 /* Minimum value of block id */
102 #define BLOCK_ID_MIN 10
103 /* For 2.4 Backward Compatibility */
104 #define EXT_PRIMARY_SD_FIXID 1
106 /* Maximum number of thread */
109 #define PKGDIR_BUS_NAME "org.tizen.pkgdir_tool"
110 #define PKGDIR_PATH "/org/tizen/pkgdir_tool"
111 #define PKGDIR_INTERFACE "org.tizen.pkgdir_tool"
113 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
115 enum block_dev_operation {
123 enum private_operation_state {
129 struct operation_queue {
130 enum block_dev_operation op;
131 dbus_method_reply_handle_h reply_handle;
136 struct block_device {
137 struct block_data *data;
139 int thread_id; /* Current thread ID */
140 bool removed; /* True when device is physically removed but operation is not precessed yet */
141 enum private_operation_state on_private_op;
142 bool mount_point_updated;
147 struct block_device *bdev;
149 enum unmount_operation option;
153 enum block_dev_operation op;
154 struct block_device *bdev;
158 static struct block_conf {
160 bool extendedinternal;
161 } block_conf[BLOCK_MMC_EXTENDED_INTERNAL_DEV + 1];
163 static struct manage_thread {
164 dd_list *th_node_list; /* List of devnode which thread dealt with. Only main thread access */
165 dd_list *block_dev_list; /* Use thread mutex */
167 pthread_mutex_t mutex;
169 int num_dev; /* Number of devices which thread holds. Only main thread access */
170 int op_len; /* Number of operation of thread. Use thread mutex */
171 int thread_id; /* Never changed */
173 } th_manager[THREAD_MAX];
175 static dd_list *fs_head;
176 static dd_list *block_ops_list;
179 static fd_handler_h phandler;
180 static bool block_control = false;
181 static bool block_boot = false;
182 static pthread_mutex_t pipe_mutex = PTHREAD_MUTEX_INITIALIZER;
184 /* Assume there is only one physical internal storage */
185 static int dev_internal = -1;
186 static char dev_internal_scsi = '\0';
187 static char dev_internal_emul = '\0';
189 static int add_operation(struct block_device *bdev,
190 enum block_dev_operation operation,
191 dbus_method_reply_handle_h reply_handle, void *data);
192 static void remove_operation(struct block_device *bdev);
193 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
194 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
195 static int change_mount_point(struct block_device *bdev, const char *mount_point);
197 static void uevent_block_handler(struct udev_device *dev);
198 static struct uevent_handler uh = {
199 .subsystem = BLOCK_SUBSYSTEM,
200 .uevent_func = uevent_block_handler,
203 static void __CONSTRUCTOR__ smack_check(void)
208 fp = fopen("/proc/filesystems", "r");
212 while (fgets(buf, sizeof(buf), fp) != NULL) {
213 if (strstr(buf, "smackfs")) {
222 void add_fs(const struct block_fs_ops *fs)
224 DD_LIST_APPEND(fs_head, (void *)fs);
227 void remove_fs(const struct block_fs_ops *fs)
229 DD_LIST_REMOVE(fs_head, (void *)fs);
232 const struct block_fs_ops *find_fs(enum block_fs_type type)
234 struct block_fs_ops *fs;
237 DD_LIST_FOREACH(fs_head, elem, fs) {
238 if (fs->type == type)
244 void add_block_dev(const struct block_dev_ops *ops)
246 DD_LIST_APPEND(block_ops_list, (void *)ops);
249 void remove_block_dev(const struct block_dev_ops *ops)
251 DD_LIST_REMOVE(block_ops_list, (void *)ops);
254 static void broadcast_block_info(enum block_dev_operation op,
255 struct block_data *data, int result)
257 struct block_dev_ops *ops;
260 if (data->primary != true)
263 DD_LIST_FOREACH(block_ops_list, elem, ops) {
264 if (ops->block_type != data->block_type)
266 // TODO What happend on extended internal storage case?
267 if (op == BLOCK_DEV_MOUNT) {
268 if (data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
269 ops->mounted(data, result, true);
271 ops->mounted(data, result, false);
272 } else if (op == BLOCK_DEV_UNMOUNT) {
273 if (data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
274 ops->unmounted(data, result, true);
276 ops->unmounted(data, result, false);
277 } else if (op == BLOCK_DEV_FORMAT) {
278 if (data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
279 ops->formatted(data, result, true);
281 ops->formatted(data, result, false);
282 } else if (op == BLOCK_DEV_INSERT)
284 else if (op == BLOCK_DEV_REMOVE)
289 // Called by MainThread - Insert
290 static int block_get_new_id(void)
292 static int id = BLOCK_ID_MIN;
293 struct block_device *bdev;
298 for (i = 0 ; i < INT_MAX ; i++) {
300 for (j = 0; j < THREAD_MAX; j++) {
301 pthread_mutex_lock(&(th_manager[j].mutex));
302 DD_LIST_FOREACH(th_manager[j].block_dev_list, elem, bdev) {
303 if (bdev->data->id == id) {
308 pthread_mutex_unlock(&(th_manager[j].mutex));
323 static void remove_file(int id, bool extendedsd)
325 char file_name[PATH_LEN];
332 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
334 snprintf(file_name, sizeof(file_name), EXTERNAL_STORAGE_PATH"/%d", id);
336 ret = remove(file_name);
338 _E("Fail to remove %s. errno: %d", file_name, errno);
341 static void create_file(int id, char *mount_point, bool extendedsd)
344 char file_name[PATH_LEN];
350 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
352 snprintf(file_name, PATH_LEN, EXTERNAL_STORAGE_PATH"/%d", id);
354 fp = fopen(file_name, "w+");
356 fprintf(fp, "%s", mount_point);
359 _E("Fail to open %s", file_name);
362 static void signal_device_blocked(struct block_device *bdev)
364 struct block_data *data;
366 char str_block_type[32];
367 char str_readonly[32];
369 char str_primary[32];
375 if (!bdev || !bdev->data)
381 /* Broadcast outside with BlockManager iface */
382 snprintf(str_block_type, sizeof(str_block_type),
383 "%d", data->block_type);
384 arr[0] = str_block_type;
385 arr[1] = (data->devnode ? data->devnode : str_null);
386 arr[2] = (data->syspath ? data->syspath : str_null);
387 arr[3] = (data->fs_usage ? data->fs_usage : str_null);
388 arr[4] = (data->fs_type ? data->fs_type : str_null);
389 arr[5] = (data->fs_version ? data->fs_version : str_null);
390 arr[6] = (data->fs_uuid_enc ? data->fs_uuid_enc : str_null);
391 snprintf(str_readonly, sizeof(str_readonly),
392 "%d", data->readonly);
393 arr[7] = str_readonly;
394 arr[8] = (data->mount_point ? data->mount_point : str_null);
395 snprintf(str_state, sizeof(str_state),
398 snprintf(str_primary, sizeof(str_primary),
399 "%d", data->primary);
400 arr[10] = str_primary;
401 snprintf(str_flags, sizeof(str_flags), "%d", flags);
403 snprintf(str_id, sizeof(str_id), "%d", data->id);
406 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
407 STORAGED_INTERFACE_BLOCK_MANAGER,
408 BLOCK_DEVICE_BLOCKED,
409 "issssssisibii", arr);
412 static void signal_device_changed(struct block_device *bdev,
413 enum block_dev_operation op)
415 struct block_data *data;
417 char str_block_type[32];
418 char str_readonly[32];
420 char str_primary[32];
426 if (!bdev || !bdev->data)
432 case BLOCK_DEV_MOUNT:
433 BLOCK_GET_MOUNT_FLAGS(data, flags);
435 case BLOCK_DEV_UNMOUNT:
436 BLOCK_GET_UNMOUNT_FLAGS(data, flags);
438 case BLOCK_DEV_FORMAT:
439 BLOCK_GET_FORMAT_FLAGS(data, flags);
446 /* Broadcast outside with BlockManager iface */
447 snprintf(str_block_type, sizeof(str_block_type),
448 "%d", data->block_type);
449 arr[0] = str_block_type;
450 arr[1] = (data->devnode ? data->devnode : str_null);
451 arr[2] = (data->syspath ? data->syspath : str_null);
452 arr[3] = (data->fs_usage ? data->fs_usage : str_null);
453 arr[4] = (data->fs_type ? data->fs_type : str_null);
454 arr[5] = (data->fs_version ? data->fs_version : str_null);
455 arr[6] = (data->fs_uuid_enc ? data->fs_uuid_enc : str_null);
456 snprintf(str_readonly, sizeof(str_readonly),
457 "%d", data->readonly);
458 arr[7] = str_readonly;
459 arr[8] = (data->mount_point ? data->mount_point : str_null);
460 snprintf(str_state, sizeof(str_state),
463 snprintf(str_primary, sizeof(str_primary),
464 "%d", data->primary);
465 arr[10] = str_primary;
466 snprintf(str_flags, sizeof(str_flags), "%d", flags);
468 snprintf(str_id, sizeof(str_id), "%d", data->id);
471 if (op == BLOCK_DEV_INSERT)
472 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
473 STORAGED_INTERFACE_BLOCK_MANAGER,
475 "issssssisibii", arr);
476 else if (op == BLOCK_DEV_REMOVE)
477 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
478 STORAGED_INTERFACE_BLOCK_MANAGER,
479 BLOCK_DEVICE_REMOVED,
480 "issssssisibii", arr);
482 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
483 STORAGED_INTERFACE_BLOCK_MANAGER,
484 BLOCK_DEVICE_CHANGED,
485 "issssssisibii", arr);
486 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
487 STORAGED_INTERFACE_BLOCK_MANAGER,
488 BLOCK_DEVICE_CHANGED_2,
489 "issssssisibi", arr);
493 static int get_mmc_mount_node(char *devnode, char *node, size_t len)
495 char *name = devnode;
496 int dev = -1, part = -1;
497 char emul[32] = { 0, };
504 sscanf(name, "mmcblk%dp%d", &dev, &part);
507 snprintf(node, len, "%s%c", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1);
509 snprintf(node, len, "%s%c%d", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1, part);
514 sscanf(name, "vd%31s", emul);
517 for (i = 0 ; i < strlen(emul) ; i++)
518 emul[i] = toupper(emul[i]);
519 snprintf(node, len, "%s%s", BLOCK_MMC_NODE_PREFIX, emul);
523 static int get_scsi_mount_node(char *devnode, char *node, size_t len)
531 snprintf(dev, sizeof(dev), "%s", devnode);
533 if (!strstr(dev, "sd"))
537 name += strlen("sd");
539 for (i = 0 ; i < strlen(name) ; i++)
540 name[i] = toupper(name[i]);
541 snprintf(node, len, "%s%s", BLOCK_SCSI_NODE_PREFIX, name);
546 static char *generate_mount_path(struct block_data *data)
549 char *name, node[64];
552 if (!data || !data->devnode)
555 name = strrchr(data->devnode, '/');
560 switch (data->block_type) {
562 ret = get_mmc_mount_node(name, node, sizeof(node));
565 ret = get_scsi_mount_node(name, node, sizeof(node));
567 case BLOCK_MMC_EXTENDED_INTERNAL_DEV:
568 return strdup(EXTENDED_SD_PATH);
570 _E("Invalid block type (%d)", data->block_type);
576 str = tzplatform_mkpath(TZ_SYS_MEDIA, node);
582 _E("Invalid devnode (%s)", data->devnode ? data->devnode : "NULL");
586 static bool check_primary_partition(const char *devnode)
588 struct block_fs_ops *fs;
591 const char *filesystem = NULL;
601 if (fnmatch(MMC_LINK_PATH, devnode, 0) &&
602 fnmatch(MMC_PATH, devnode, 0) &&
603 fnmatch(SCSI_PATH, devnode, 0))
606 temp = strrchr(devnode, '/');
609 if (fnmatch("/"SCSI_PARTITION_PATH, temp, 0) &&
610 fnmatch("/"MMC_PARTITION_PATH, temp, 0))
613 /* Emulator support only one partition */
617 snprintf(str, sizeof(str), "%s", devnode);
622 for (i = 1; i <= 9; ++i) {
623 snprintf(str2, sizeof(str2), "%s%d", str, i);
624 if (access(str2, R_OK) != 0)
627 probe = blkid_new_probe_from_filename(str2);
630 if (blkid_do_probe(probe) != 0)
633 ret = blkid_probe_lookup_value(probe, "TYPE", &filesystem, &fs_len);
635 blkid_free_probe(probe);
638 DD_LIST_FOREACH(fs_head, elem, fs) {
639 if (!strncmp(fs->name, filesystem, fs_len)) {
644 blkid_free_probe(probe);
650 if (found && !strncmp(devnode, str2, strlen(str2) + 1))
656 /* Whole data in struct block_data should be freed. */
657 static struct block_data *make_block_data(const char *devnode,
659 const char *fs_usage,
661 const char *fs_version,
662 const char *fs_uuid_enc,
663 const char *readonly)
665 struct block_data *data;
667 /* devnode is unique value so it should exist. */
672 _E("Not support extended partition");
674 data = calloc(1, sizeof(struct block_data));
676 _E("calloc() failed");
680 data->devnode = strdup(devnode);
682 data->syspath = strdup(syspath);
684 data->fs_usage = strdup(fs_usage);
686 data->fs_type = strdup(fs_type);
688 data->fs_version = strdup(fs_version);
690 data->fs_uuid_enc = strdup(fs_uuid_enc);
692 data->readonly = atoi(readonly);
693 data->primary = check_primary_partition(devnode);
695 /* TODO should we know block dev type? */
696 if (!fnmatch(MMC_LINK_PATH, devnode, 0))
697 data->block_type = BLOCK_MMC_DEV;
698 else if (!fnmatch(MMC_PATH, devnode, 0))
699 data->block_type = BLOCK_MMC_DEV;
700 else if (!fnmatch(SCSI_PATH, devnode, 0))
701 data->block_type = BLOCK_SCSI_DEV;
703 data->block_type = -1;
705 data->mount_point = generate_mount_path(data);
706 BLOCK_FLAG_CLEAR_ALL(data);
708 /* for 2.4 backward compatibility */
709 // What if storage id 1 is existed? (multi sdcard case)
710 if (data->primary == true && data->block_type == BLOCK_MMC_DEV)
711 data->id = EXT_PRIMARY_SD_FIXID;
713 data->id = block_get_new_id();
718 static void free_block_data(struct block_data *data)
724 free(data->fs_usage);
726 free(data->fs_version);
727 free(data->fs_uuid_enc);
728 free(data->mount_point);
732 static int update_block_data(struct block_data *data,
733 const char *fs_usage,
735 const char *fs_version,
736 const char *fs_uuid_enc,
737 const char *readonly,
738 bool mount_point_updated)
743 free(data->fs_usage);
744 data->fs_usage = NULL;
746 data->fs_usage = strdup(fs_usage);
749 data->fs_type = NULL;
751 data->fs_type = strdup(fs_type);
753 free(data->fs_version);
754 data->fs_version = NULL;
756 data->fs_version = strdup(fs_version);
758 free(data->fs_uuid_enc);
759 data->fs_uuid_enc = NULL;
761 data->fs_uuid_enc = strdup(fs_uuid_enc);
763 /* generate_mount_path function should be invoked
764 * after fs_uuid_enc is updated */
765 if (!mount_point_updated) {
766 free(data->mount_point);
767 data->mount_point = generate_mount_path(data);
770 data->readonly = false;
772 data->readonly = atoi(readonly);
774 BLOCK_FLAG_MOUNT_CLEAR(data);
779 static struct block_device *make_block_device(struct block_data *data)
781 struct block_device *bdev;
786 bdev = calloc(1, sizeof(struct block_device));
791 bdev->thread_id = -1;
792 bdev->removed = false;
793 bdev->on_private_op = REQ_NORMAL;
794 bdev->private_pid = 0;
795 bdev->mount_point_updated = false;
800 // Called by MainThread - Remove DevNode
801 static void free_block_device(struct block_device *bdev)
804 struct operation_queue *op;
810 thread_id = bdev->thread_id;
811 if (thread_id < 0 || thread_id >= THREAD_MAX)
814 pthread_mutex_lock(&(th_manager[thread_id].mutex));
816 th_manager[thread_id].num_dev--;
817 DD_LIST_REMOVE(th_manager[thread_id].block_dev_list, bdev);
818 free_block_data(bdev->data);
820 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
822 th_manager[thread_id].op_len--;
823 DD_LIST_REMOVE(bdev->op_queue, op);
826 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
831 // Called By MainThread - Remove Device
832 static struct block_device *find_block_device(const char *devnode)
834 struct block_device *bdev;
839 len = strlen(devnode) + 1;
840 for (i = 0; i < THREAD_MAX; i++) {
841 pthread_mutex_lock(&(th_manager[i].mutex));
842 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
843 if (bdev->data && !bdev->removed &&
844 !strncmp(bdev->data->devnode, devnode, len)) {
845 pthread_mutex_unlock(&(th_manager[i].mutex));
849 pthread_mutex_unlock(&(th_manager[i].mutex));
855 // Called By MainThread - Mount,Unmount,Format,GetInfo
856 static struct block_device *find_block_device_by_id(int id)
858 struct block_device *bdev;
862 for (i = 0; i < THREAD_MAX; i++) {
863 pthread_mutex_lock(&(th_manager[i].mutex));
864 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
869 if (bdev->data->id == id) {
870 pthread_mutex_unlock(&(th_manager[i].mutex));
874 pthread_mutex_unlock(&(th_manager[i].mutex));
880 static char *get_operation_char(enum block_dev_operation op,
881 char *name, unsigned int len)
883 char *str = "unknown";
889 case BLOCK_DEV_MOUNT:
892 case BLOCK_DEV_UNMOUNT:
895 case BLOCK_DEV_FORMAT:
898 case BLOCK_DEV_INSERT:
901 case BLOCK_DEV_REMOVE:
905 _E("invalid operation (%d)", op);
909 snprintf(name, len, "%s", str);
913 static void create_external_apps_directory(void)
917 ret = call_dbus_method_async(PKGDIR_BUS_NAME, PKGDIR_PATH,
918 PKGDIR_INTERFACE, "CreateExternalDirsForAllPkgs",
919 NULL, NULL, NULL, DBUS_TIMEOUT_USE_DEFAULT, NULL);
921 _E("Fail to create external directory");
924 static int pipe_trigger(enum block_dev_operation op,
925 struct block_device *bdev, int result)
927 struct pipe_data pdata = { op, bdev, result };
931 _D("op : %s, bdev : %p, result : %d",
932 get_operation_char(pdata.op, name, sizeof(name)),
933 pdata.bdev, pdata.result);
935 // Multi thread should not write at the same time
936 pthread_mutex_lock(&pipe_mutex);
937 n = write(pfds[1], &pdata, sizeof(struct pipe_data));
938 pthread_mutex_unlock(&pipe_mutex);
940 return (n != sizeof(struct pipe_data)) ? -EPERM : 0;
943 static bool pipe_cb(int fd, void *data)
945 struct pipe_data pdata = {0,};
951 n = read(fd, &pdata, sizeof(pdata));
952 if (n != sizeof(pdata) || !pdata.bdev) {
953 _E("fail to read struct pipe data");
957 _I("op : %s, bdev : %p, result : %d",
958 get_operation_char(pdata.op, name, sizeof(name)),
959 pdata.bdev, pdata.result);
961 if (pdata.op == BLOCK_DEV_MOUNT && pdata.result < 0) {
962 if (pdata.bdev->data->state == BLOCK_UNMOUNT) {
963 ret = change_mount_point(pdata.bdev, "");
964 /* Modify /run/external-storage/id file */
966 if (pdata.bdev->data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
967 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, true);
969 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, false);
974 if (pdata.op == BLOCK_DEV_MOUNT &&
975 pdata.bdev->data->state == BLOCK_MOUNT &&
976 pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
977 pdata.bdev->data->primary)
978 create_external_apps_directory();
979 if (pdata.op == BLOCK_DEV_UNMOUNT) {
980 /* Remove file for block device /run/xxxxxx/id */
981 if (pdata.bdev->data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
982 remove_file(pdata.bdev->data->id, true);
984 remove_file(pdata.bdev->data->id, false);
987 /* Broadcast to mmc and usb storage module */
988 broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
990 /* Broadcast outside with Block iface */
991 if (pdata.bdev->on_private_op == REQ_NORMAL)
992 signal_device_changed(pdata.bdev, pdata.op);
993 else if (pdata.bdev->on_private_op == REQ_PRIVATE) {
994 if (pdata.op == BLOCK_DEV_UNMOUNT) {
995 pdata.bdev->on_private_op = REQ_NORMAL;
996 _D("Private operation state: %d", pdata.bdev->on_private_op);
999 if (pdata.op == BLOCK_DEV_MOUNT) {
1000 pdata.bdev->on_private_op = REQ_PRIVATE;
1001 _D("Private operation state: %d", pdata.bdev->on_private_op);
1005 if (pdata.op == BLOCK_DEV_REMOVE) {
1006 thread_id = pdata.bdev->thread_id;
1007 if (thread_id < 0 || thread_id >= THREAD_MAX)
1009 free_block_device(pdata.bdev);
1016 static int pipe_init(void)
1020 ret = pipe2(pfds, O_CLOEXEC);
1024 ret = add_fd_read_handler(pfds[0], pipe_cb,
1025 NULL, NULL, &phandler);
1027 _E("Failed to add pipe handler (%d)", ret);
1034 static void pipe_exit(void)
1037 remove_fd_read_handler(&phandler);
1047 static int mmc_check_and_unmount(const char *path)
1055 while (mount_check(path)) {
1059 if (retry > UNMOUNT_RETRY)
1066 static bool check_rw_mount(const char *szPath)
1068 struct statvfs mount_stat;
1070 if (!statvfs(szPath, &mount_stat)) {
1071 if ((mount_stat.f_flag & ST_RDONLY) == ST_RDONLY)
1077 static int retrieve_udev_device(struct block_data *data, bool mount_point_updated)
1080 struct udev_device *dev;
1088 _E("fail to create udev library context");
1092 dev = udev_device_new_from_syspath(udev, data->syspath);
1094 _E("fail to create new udev device");
1099 r = update_block_data(data,
1100 udev_device_get_property_value(dev, "ID_FS_USAGE"),
1101 udev_device_get_property_value(dev, "ID_FS_TYPE"),
1102 udev_device_get_property_value(dev, "ID_FS_VERSION"),
1103 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
1104 udev_device_get_sysattr_value(dev, "ro"),
1105 mount_point_updated);
1107 _E("fail to update block data for %s", data->devnode);
1109 udev_device_unref(dev);
1114 static int block_mount(struct block_data *data)
1116 struct block_fs_ops *fs;
1121 if (!data || !data->devnode || !data->mount_point)
1124 /* check existing mounted */
1125 if (mount_check(data->mount_point))
1128 /* create mount point */
1129 if (access(data->mount_point, R_OK) != 0) {
1130 if (mkdir(data->mount_point, 0755) < 0)
1134 /* check matched file system */
1135 if (!data->fs_usage ||
1136 strncmp(data->fs_usage, FILESYSTEM,
1137 sizeof(FILESYSTEM)) != 0) {
1142 if (!data->fs_type) {
1143 _E("There is no file system");
1144 BLOCK_FLAG_SET(data, FS_EMPTY);
1150 len = strlen(data->fs_type) + 1;
1151 DD_LIST_FOREACH(fs_head, elem, fs) {
1152 if (!strncmp(fs->name, data->fs_type, len))
1157 _E("Not supported file system (%s)", data->fs_type);
1158 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1163 if (data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
1164 r = fs->mount(false, data->devnode, data->mount_point);
1166 r = fs->mount(smack, data->devnode, data->mount_point);
1169 BLOCK_FLAG_SET(data, FS_BROKEN);
1174 r = check_rw_mount(data->mount_point);
1181 rmdir(data->mount_point);
1185 static int mount_start(struct block_device *bdev)
1187 struct block_data *data;
1195 _I("Mount Start : (%s -> %s)",
1196 data->devnode, data->mount_point);
1198 /* mount operation */
1199 r = block_mount(data);
1200 if (r != -EROFS && r < 0) {
1201 _E("fail to mount %s device : %d", data->devnode, r);
1206 data->readonly = true;
1207 BLOCK_FLAG_SET(data, MOUNT_READONLY);
1210 data->state = BLOCK_MOUNT;
1212 if (data->block_type == BLOCK_MMC_DEV) {
1213 /* app2ext_migrate_legacy_all has dbus method call to deviced */
1214 ret = app2ext_migrate_legacy_all();
1216 _E("app2ext failed");
1220 if (r < 0 && r != -EROFS)
1221 data->state = BLOCK_UNMOUNT;
1223 _I("%s result : %s, %d", __func__, data->devnode, r);
1225 if (pipe_trigger(BLOCK_DEV_MOUNT, bdev, r) < 0)
1226 _E("fail to trigger pipe");
1231 static int change_mount_point(struct block_device *bdev,
1232 const char *mount_point)
1234 struct block_data *data;
1240 free(data->mount_point);
1242 /* If the mount path already exists, the path cannot be used */
1244 access(mount_point, F_OK) != 0) {
1245 data->mount_point = strdup(mount_point);
1246 bdev->mount_point_updated = true;
1248 data->mount_point = generate_mount_path(data);
1249 bdev->mount_point_updated = false;
1255 static int mount_block_device(struct block_device *bdev)
1257 struct block_data *data;
1260 if (!bdev || !bdev->data)
1264 if (data->state == BLOCK_MOUNT) {
1265 _I("%s is already mounted", data->devnode);
1269 if (!block_conf[data->block_type].multimount &&
1271 _I("Not support multi mount by config info");
1275 r = mount_start(bdev);
1277 _E("Failed to mount (%s)", data->devnode);
1284 static int block_unmount(struct block_device *bdev,
1285 enum unmount_operation option)
1287 struct block_data *data;
1289 struct timespec time = {0,};
1291 if (!bdev || !bdev->data || !bdev->data->mount_point)
1296 if (bdev->on_private_op == REQ_NORMAL)
1297 signal_device_blocked(bdev);
1299 /* it must called before unmounting mmc */
1300 r = mmc_check_and_unmount(data->mount_point);
1303 if (option == UNMOUNT_NORMAL) {
1304 _I("Failed to unmount with normal option : %d", r);
1308 _I("Execute force unmount!");
1309 /* Force Unmount Scenario */
1314 * should unmount the below vconf key. */
1315 if ((data->block_type == BLOCK_MMC_DEV ||
1316 data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV) &&
1318 /* At first, notify to other app
1319 * who already access sdcard */
1320 _I("Notify to other app who already access sdcard");
1321 vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS,
1322 VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
1326 /* Second, kill app with SIGTERM */
1327 _I("Kill app with SIGTERM");
1328 terminate_process(data->mount_point, false);
1331 /* Last time, kill app with SIGKILL */
1332 _I("Kill app with SIGKILL");
1333 terminate_process(data->mount_point, true);
1336 if (umount2(data->mount_point, MNT_DETACH) != 0) {
1337 _I("Failed to unmount with lazy option : %d",
1344 /* it takes some seconds til other app completely clean up */
1345 time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER;
1346 nanosleep(&time, NULL);
1348 print_open_files(data->mount_point);
1350 r = mmc_check_and_unmount(data->mount_point);
1352 _D("Success to unmount (%s)", data->mount_point);
1358 data->state = BLOCK_UNMOUNT;
1360 if (rmdir(data->mount_point) < 0)
1361 _E("fail to remove %s directory", data->mount_point);
1366 static int unmount_block_device(struct block_device *bdev,
1367 enum unmount_operation option)
1369 struct block_data *data;
1372 if (!bdev || !bdev->data)
1376 if (data->state == BLOCK_UNMOUNT) {
1377 _I("%s is already unmounted", data->devnode);
1378 r = mmc_check_and_unmount(data->mount_point);
1380 _E("The path was existed, but could not delete it(%s)",
1385 _I("Unmount Start : (%s -> %s)",
1386 data->devnode, data->mount_point);
1388 r = block_unmount(bdev, option);
1390 _E("fail to unmount %s device : %d", data->devnode, r);
1394 BLOCK_FLAG_MOUNT_CLEAR(data);
1397 _I("%s result : %s, %d", __func__, data->devnode, r);
1399 if (pipe_trigger(BLOCK_DEV_UNMOUNT, bdev, r) < 0)
1400 _E("fail to trigger pipe");
1405 static int block_format(struct block_data *data,
1406 const char *fs_type, bool mount_point_updated)
1408 const struct block_fs_ops *fs;
1414 if (!data || !data->devnode || !data->mount_point)
1417 if (data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
1423 fstype = data->fs_type;
1429 len = strlen(fstype);
1430 DD_LIST_FOREACH(fs_head, elem, fs) {
1431 if (!strncmp(fs->name, fstype, len))
1436 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1437 _E("not supported file system(%s)", fstype);
1441 _I("format path : %s", data->devnode);
1442 fs->check(data->devnode);
1443 r = fs->format(data->devnode);
1445 _E("fail to format block data for %s", data->devnode);
1449 /* it takes some seconds til kernel set udev property */
1452 /* need to update the partition data.
1453 * It can be changed in doing format. */
1454 retrieve_udev_device(data, mount_point_updated);
1460 static int format_block_device(struct block_device *bdev,
1461 const char *fs_type,
1462 enum unmount_operation option)
1464 struct block_data *data;
1472 _I("Format Start : (%s -> %s)",
1473 data->devnode, data->mount_point);
1475 if (data->state == BLOCK_MOUNT) {
1476 r = block_unmount(bdev, option);
1478 _E("fail to unmount %s device : %d", data->devnode, r);
1483 r = block_format(data, fs_type, bdev->mount_point_updated);
1485 _E("fail to format %s device : %d", data->devnode, r);
1488 _I("%s result : %s, %d", __func__, data->devnode, r);
1490 r = pipe_trigger(BLOCK_DEV_FORMAT, bdev, r);
1492 _E("fail to trigger pipe");
1497 static struct format_data *get_format_data(
1498 const char *fs_type, enum unmount_operation option)
1500 struct format_data *fdata;
1502 fdata = (struct format_data *)malloc(sizeof(struct format_data));
1504 _E("fail to allocate format data");
1509 fdata->fs_type = strdup(fs_type);
1511 fdata->fs_type = NULL;
1512 fdata->option = option;
1517 static void release_format_data(struct format_data *data)
1521 free(data->fs_type);
1526 // Called by BlockThread - Real Mount Op
1527 static int block_mount_device(struct block_device *bdev, void *data)
1536 thread_id = bdev->thread_id;
1537 if (thread_id < 0 || thread_id >= THREAD_MAX)
1539 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1540 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1541 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1543 _E("(%d) does not exist in the device list", bdev->data->devnode);
1547 /* mount automatically */
1548 ret = mount_block_device(bdev);
1550 _E("fail to mount block device for %s", bdev->data->devnode);
1555 // Called by BlockThread - Real Format Op
1556 static int block_format_device(struct block_device *bdev, void *data)
1561 struct format_data *fdata = (struct format_data *)data;
1563 if (!bdev || !fdata) {
1568 thread_id = bdev->thread_id;
1569 if (thread_id < 0 || thread_id >= THREAD_MAX)
1571 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1572 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1573 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1575 _E("(%d) does not exist in the device list", bdev->data->devnode);
1580 ret = format_block_device(bdev, fdata->fs_type, fdata->option);
1582 _E("fail to mount block device for %s", bdev->data->devnode);
1585 release_format_data(fdata);
1590 // Called by BlockThread - Real Unmount Op
1591 static int block_unmount_device(struct block_device *bdev, void *data)
1594 long option = (long)data;
1599 ret = unmount_block_device(bdev, option);
1601 _E("Failed to unmount block device (%s)", bdev->data->devnode);
1608 /* Called by BlockThread - Remove Operation
1609 Direct Call at BlockThread
1610 Previously this function was called by MainThread. However, it will increase complexity.
1611 Need thread lock before to call remove_operation
1613 static void remove_operation(struct block_device *bdev)
1615 struct operation_queue *op;
1622 thread_id = bdev->thread_id;
1623 if (thread_id < 0 || thread_id >= THREAD_MAX)
1626 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
1628 _D("Remove operation (%s, %s)",
1629 get_operation_char(op->op, name, sizeof(name)),
1630 bdev->data->devnode);
1632 DD_LIST_REMOVE(bdev->op_queue, op);
1638 static void block_send_dbus_reply(dbus_method_reply_handle_h reply_handle, int result)
1645 rep = make_dbus_reply_message_simple(reply_handle, result);
1646 reply_dbus_method_result(reply_handle, rep);
1649 // Called by BlockThread
1650 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1652 struct operation_queue *temp;
1665 thread_id = bdev->thread_id;
1666 if (thread_id < 0 || thread_id >= THREAD_MAX)
1669 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1671 DD_LIST_FOREACH(*queue, l, temp) {
1672 if (temp->op == BLOCK_DEV_REMOVE) {
1677 th_manager[thread_id].op_len--;
1678 block_send_dbus_reply((*op)->reply_handle, 0);
1681 remove_operation(bdev);
1682 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1685 // Called by BlockThread
1686 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1688 struct operation_queue *temp;
1691 bool unmounted = false;
1702 thread_id = bdev->thread_id;
1703 if (thread_id < 0 || thread_id >= THREAD_MAX)
1706 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1707 DD_LIST_FOREACH(*queue, l, temp) {
1708 if (temp->op == BLOCK_DEV_UNMOUNT) {
1710 _D("Operation queue has unmount operation");
1714 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1719 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1721 DD_LIST_FOREACH(*queue, l, temp) {
1722 if (temp->op == BLOCK_DEV_UNMOUNT) {
1727 th_manager[thread_id].op_len--;
1728 block_send_dbus_reply((*op)->reply_handle, 0);
1731 remove_operation(bdev);
1732 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1737 // Called by BlockThread
1738 static void trigger_operation(struct block_device *bdev, dd_list *queue, struct operation_queue *op)
1742 char devnode[PATH_MAX];
1744 enum block_dev_operation operation;
1745 bool unmounted = false;
1752 thread_id = bdev->thread_id;
1753 if (thread_id < 0 || thread_id >= THREAD_MAX)
1756 snprintf(devnode, sizeof(devnode), "%s", bdev->data->devnode);
1766 _D("Thread id %d Trigger operation (%s, %s)", thread_id,
1767 get_operation_char(operation, name, sizeof(name)), devnode);
1770 if (operation == BLOCK_DEV_INSERT && bdev->removed) {
1771 check_removed(bdev, &queue, &op);
1773 _D("Trigger operation again (%s, %s)",
1774 get_operation_char(operation, name, sizeof(name)), devnode);
1776 if (operation == BLOCK_DEV_MOUNT) {
1777 unmounted = check_unmount(bdev, &queue, &op);
1780 _D("Trigger operation again (%s, %s)",
1781 get_operation_char(operation, name, sizeof(name)), devnode);
1785 switch (operation) {
1786 case BLOCK_DEV_INSERT:
1788 case BLOCK_DEV_MOUNT:
1789 ret = block_mount_device(bdev, op->data);
1790 _D("Mount (%s) result:(%d)", devnode, ret);
1792 case BLOCK_DEV_FORMAT:
1793 ret = block_format_device(bdev, op->data);
1794 _D("Format (%s) result:(%d)", devnode, ret);
1796 case BLOCK_DEV_UNMOUNT:
1797 ret = block_unmount_device(bdev, op->data);
1798 _D("Unmount (%s) result:(%d)", devnode, ret);
1800 case BLOCK_DEV_REMOVE:
1804 _E("Operation type is invalid (%d)", op->op);
1810 * during checking the queue length */
1811 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1814 th_manager[thread_id].op_len--;
1816 block_send_dbus_reply(op->reply_handle, ret);
1818 queue = bdev->op_queue;
1819 if (queue != NULL) {
1820 queue = DD_LIST_NEXT(queue);
1822 op = DD_LIST_NTH(queue, 0);
1828 remove_operation(bdev);
1830 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1834 if (operation == BLOCK_DEV_INSERT || operation == BLOCK_DEV_REMOVE) {
1835 if (pipe_trigger(operation, bdev, 0) < 0)
1836 _E("fail to trigger pipe");
1843 // Called by BlockThread
1844 static void *block_th_start(void *arg)
1846 struct block_device *temp;
1847 struct manage_thread *th = (struct manage_thread *)arg;
1848 struct operation_queue *op = NULL;
1850 dd_list *queue = NULL;
1855 thread_id = th->thread_id;
1856 if (thread_id < 0 || thread_id >= THREAD_MAX) {
1857 _E("Thread Number: %d", th->thread_id);
1862 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1863 if (th_manager[thread_id].op_len == 0) {
1864 _D("Operation queue of thread is empty");
1865 pthread_cond_wait(&(th_manager[thread_id].cond), &(th_manager[thread_id].mutex));
1866 _D("Wake up %d", thread_id);
1869 DD_LIST_FOREACH(th_manager[thread_id].block_dev_list, elem, temp) {
1870 queue = temp->op_queue;
1872 op = DD_LIST_NTH(queue, 0);
1874 _D("Operation queue for device %s is Empty", temp->data->devnode);
1878 queue = DD_LIST_NEXT(queue);
1886 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1888 if (op && !op->done)
1889 trigger_operation(temp, queue, op);
1894 // This function will be refactored later
1895 // Especially, we don't need to keep th_node_list.
1896 static int find_thread(char *devnode)
1903 int i, len, min, min_num;
1904 int dev_mmc = -1, part = -1, num;
1907 if (!fnmatch("*/"MMC_PARTITION_PATH, devnode, 0)) {
1908 sscanf(devnode, "/dev/mmcblk%dp%d", &dev_mmc, &part);
1915 snprintf(str, len, "/dev/mmcblk%d", dev_mmc);
1916 th_node = strdup(str);
1917 } else if (!fnmatch("*/"SCSI_PARTITION_PATH, devnode, 0)) {
1918 sscanf(devnode, "/dev/sd%c%d", &dev_scsi, &part);
1919 snprintf(str, SCSI_PARTITION_LENGTH, "/dev/sd%c", dev_scsi);
1920 th_node = strdup(str);
1922 th_node = strdup(devnode);
1924 len = strlen(th_node) + 1;
1927 for (i = 0; i < THREAD_MAX; i++) {
1928 DD_LIST_FOREACH(th_manager[i].th_node_list, elem, temp) {
1929 if (!strncmp(temp, th_node, len)) {
1934 if (th_manager[i].num_dev < min_num) {
1935 min_num = th_manager[i].num_dev;
1940 if (min >= 0 && min < THREAD_MAX) {
1941 DD_LIST_APPEND(th_manager[min].th_node_list, th_node);
1945 _E("Finding thread is failed");
1946 DD_LIST_APPEND(th_manager[0].th_node_list, th_node);
1950 /* Only Main thread is permmited */
1951 // Called by MainThread
1952 static int add_operation(struct block_device *bdev,
1953 enum block_dev_operation operation,
1954 dbus_method_reply_handle_h reply_handle, void *data)
1956 struct operation_queue *op;
1966 _I("Add operation (%s, %s)",
1967 get_operation_char(operation, name, sizeof(name)),
1968 bdev->data->devnode);
1970 thread_id = bdev->thread_id;
1971 if (thread_id < 0 || thread_id >= THREAD_MAX) {
1972 _E("Fail to find thread to add");
1976 op = (struct operation_queue *)malloc(sizeof(struct operation_queue));
1978 _E("malloc failed");
1984 op->reply_handle = reply_handle;
1987 * during adding queue and checking the queue length */
1988 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1990 /* Only modified between lock and unlock of mutex */
1993 start_th = th_manager[thread_id].start_th;
1994 DD_LIST_APPEND(bdev->op_queue, op);
1995 th_manager[thread_id].op_len++;
1997 if (th_manager[thread_id].op_len == 1 && !start_th)
1998 pthread_cond_signal(&(th_manager[thread_id].cond));
2000 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2003 /* Need to disble app2ext whenever unmounting mmc */
2004 if (op->op == BLOCK_DEV_UNMOUNT &&
2005 bdev->data->state == BLOCK_MOUNT &&
2006 bdev->data->block_type == BLOCK_MMC_DEV &&
2007 bdev->data->primary)
2008 if (app2ext_disable_all_external_pkgs() < 0)
2009 _E("app2ext_disable_all_external_pkgs() failed");
2013 _D("Start New thread for block device");
2014 th_manager[thread_id].start_th = false;
2015 ret = pthread_create(&(th_manager[thread_id].th), NULL, block_th_start, &th_manager[thread_id]);
2017 _E("fail to create thread for %s", bdev->data->devnode);
2021 pthread_detach(th_manager[thread_id].th);
2027 static bool disk_is_partitioned_by_kernel(struct udev_device *dev)
2030 struct dirent entry;
2032 const char *syspath;
2035 syspath = udev_device_get_syspath(dev);
2039 dp = opendir(syspath);
2041 _E("fail to open %s", syspath);
2045 /* TODO compare devname and d_name */
2046 while (readdir_r(dp, &entry, &dir) == 0 && dir != NULL) {
2047 if (!fnmatch(MMC_PARTITION_PATH, dir->d_name, 0) ||
2048 !fnmatch(SCSI_PARTITION_PATH, dir->d_name, 0)) {
2060 static bool check_partition(struct udev_device *dev)
2062 const char *devtype;
2063 const char *part_table_type;
2064 const char *fs_usage;
2067 /* only consider disk type, never partitions */
2068 devtype = udev_device_get_devtype(dev);
2072 if (strncmp(devtype, BLOCK_DEVTYPE_DISK,
2073 sizeof(BLOCK_DEVTYPE_DISK)) != 0)
2076 part_table_type = udev_device_get_property_value(dev,
2077 "ID_PART_TABLE_TYPE");
2078 if (part_table_type) {
2079 fs_usage = udev_device_get_property_value(dev,
2082 strncmp(fs_usage, FILESYSTEM, sizeof(FILESYSTEM)) == 0) {
2083 if (!disk_is_partitioned_by_kernel(dev))
2090 if (disk_is_partitioned_by_kernel(dev)) {
2099 // Called by MainThread
2100 static int add_block_device(struct udev_device *dev, const char *devnode, bool init)
2102 struct block_data *data;
2103 struct block_device *bdev;
2104 char id_string[PATH_LEN];
2109 partition = check_partition(dev);
2111 /* if there is a partition, skip this request */
2112 _I("%s device has partitions, skip this time", devnode);
2116 data = make_block_data(devnode,
2117 udev_device_get_syspath(dev),
2118 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2119 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2120 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2121 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2122 udev_device_get_sysattr_value(dev, "ro"));
2124 _E("fail to make block data for %s", devnode);
2128 if (!block_conf[data->block_type].multimount && !data->primary) {
2129 _D("Not support multi mount by config info");
2130 free_block_data(data);
2134 bdev = make_block_device(data);
2136 _E("fail to make block device for %s", devnode);
2137 free_block_data(data);
2141 thread_id = find_thread(bdev->data->devnode);
2142 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2143 _E("Fail to find thread to add");
2144 free_block_device(bdev);
2147 bdev->thread_id = thread_id;
2149 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2150 th_manager[thread_id].num_dev++;
2151 DD_LIST_APPEND(th_manager[thread_id].block_dev_list, bdev);
2153 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2155 /* Check this sdcard is already formatted for extended internal sdcard */
2156 if (block_conf[bdev->data->block_type].extendedinternal &&
2157 bdev->data->block_type == BLOCK_MMC_DEV &&
2158 bdev->data->primary) { // sdcard primary partition and extended internal option is on
2159 _I("Check whether sdcard will be used as extended internal storage");
2161 if (!init) { // after booting is done launch popup for setting
2162 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2164 _E("Failed to add operation (insert %s)", devnode);
2165 free_block_device(bdev);
2169 snprintf(id_string, PATH_LEN, "%d", bdev->data->id);
2170 ret = launch_system_app(POPUP_DEFAULT, 4, POPUP_KEY_CONTENT, "sdcardsetup", POPUP_SDCARD_ID, id_string);
2172 _E("Failed to launch popup");
2174 } else { // at booting time
2175 if (!bdev->data->fs_type) {
2176 _E("Unformatted Storage");
2177 free_block_device(bdev);
2181 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2182 bdev->data->block_type = BLOCK_MMC_EXTENDED_INTERNAL_DEV;
2183 ret = change_mount_point(bdev, EXTENDED_SD_PATH);
2186 free_block_device(bdev);
2193 if (!bdev->data->fs_type) {
2194 _E("Unformatted Storage");
2195 free_block_device(bdev);
2200 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2202 _E("Failed to add operation (insert %s)", devnode);
2203 free_block_device(bdev);
2207 /* Create file for block device /run/external-storage/id */
2208 if (bdev->data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
2209 create_file(bdev->data->id, bdev->data->mount_point, true);
2211 create_file(bdev->data->id, bdev->data->mount_point, false);
2212 ret = add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL);
2214 _E("Failed to add operation (mount %s)", devnode);
2220 static int remove_block_device(struct udev_device *dev, const char *devnode)
2222 struct block_device *bdev;
2225 bdev = find_block_device(devnode);
2227 _E("fail to find block data for %s", devnode);
2231 BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
2233 bdev->removed = true;
2234 if (bdev->on_private_op != REQ_NORMAL) {
2235 bdev->on_private_op = REQ_NORMAL;
2236 _D("Private operation state: %d", bdev->on_private_op);
2239 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2241 _E("Failed to add operation (unmount %s)", devnode);
2245 ret = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2247 _E("Failed to add operation (remove %s)", devnode);
2254 static int get_internal_storage_number(void)
2256 struct libmnt_table *t = NULL;
2257 struct libmnt_fs *fs;
2260 int r = 0, dev_temp;
2262 if ((!is_emulator() && (dev_internal >= 0 || dev_internal_scsi != '\0')) ||
2263 (is_emulator() && dev_internal_emul != '\0'))
2266 t = mnt_new_table();
2270 r = mnt_table_parse_mtab(t, NULL);
2276 fs = mnt_table_find_target(t, ROOT_DIR, MNT_ITER_BACKWARD);
2282 temp = mnt_fs_get_srcpath(fs);
2286 name = strrchr(temp, '/');
2290 /* Boot from USB is not handled */
2291 if (!is_emulator()) {
2292 if (!fnmatch(MMC_PATH, temp, 0))
2293 sscanf(name, "mmcblk%d", &dev_internal);
2294 else if (!fnmatch(SCSI_PATH, temp, 0))
2295 sscanf(name, "sd%c", &dev_internal_scsi);
2297 if (!fnmatch(MMC_LINK_PATH, temp, 0))
2298 sscanf(name, "vd%c%d", &dev_internal_emul, &dev_temp);
2300 dev_internal_emul = '\0';
2308 static int check_external_storage(const char* devnode)
2310 char dev_scsi = '\0';
2313 int dev_num = -1, dev_temp;
2318 name = strrchr(devnode, '/');
2322 if (!is_emulator()) {
2323 if (!fnmatch(MMC_PATH, devnode, 0)) {
2324 sscanf(name, "mmcblk%d", &dev_num);
2325 if (dev_internal == dev_num) {
2326 _D("%s is internal storage", devnode);
2329 } else if (!fnmatch(SCSI_PATH, devnode, 0)) {
2330 sscanf(name, "sd%c", &dev_scsi);
2331 if (dev_internal_scsi == dev_scsi) {
2332 _D("%s is internal storage", devnode);
2337 if (!fnmatch(MMC_LINK_PATH, devnode, 0)) {
2338 sscanf(name, "vd%c%d", &emul, &dev_temp);
2339 if (dev_internal_emul == emul) {
2340 _D("%s is internal storage", devnode);
2349 static int check_already_handled(const char* devnode)
2351 struct block_device *bdev;
2352 struct block_data *data;
2356 for (i = 0; i < THREAD_MAX; i++) {
2357 pthread_mutex_lock(&(th_manager[i].mutex));
2358 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2364 if (!strncmp(data->devnode, devnode, strlen(devnode) + 1)) {
2365 pthread_mutex_unlock(&(th_manager[i].mutex));
2369 pthread_mutex_unlock(&(th_manager[i].mutex));
2375 static int block_init_from_udev_enumerate(void)
2378 struct udev_enumerate *enumerate;
2379 struct udev_list_entry *list_entry, *list_sub_entry;
2380 struct udev_device *dev;
2381 const char *syspath;
2382 const char *devnode;
2387 _E("fail to create udev library context");
2391 /* create a list of the devices in the 'usb' subsystem */
2392 enumerate = udev_enumerate_new(udev);
2394 _E("fail to create an enumeration context");
2398 if ((dev_internal < 0 && !is_emulator() && dev_internal_scsi == '\0') ||
2399 (is_emulator() && dev_internal_emul == '\0')) {
2400 r = get_internal_storage_number();
2405 udev_enumerate_add_match_subsystem(enumerate, BLOCK_SUBSYSTEM);
2406 udev_enumerate_add_match_property(enumerate,
2407 UDEV_DEVTYPE, BLOCK_DEVTYPE_DISK);
2408 udev_enumerate_add_match_property(enumerate,
2409 UDEV_DEVTYPE, BLOCK_DEVTYPE_PARTITION);
2410 udev_enumerate_scan_devices(enumerate);
2412 udev_list_entry_foreach(list_entry,
2413 udev_enumerate_get_list_entry(enumerate)) {
2414 syspath = udev_list_entry_get_name(list_entry);
2418 dev = udev_device_new_from_syspath(
2419 udev_enumerate_get_udev(enumerate),
2425 udev_list_entry_foreach(list_sub_entry,
2426 udev_device_get_devlinks_list_entry(dev)) {
2427 const char *devlink = udev_list_entry_get_name(list_sub_entry);
2428 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2435 devnode = udev_device_get_devnode(dev);
2439 if (fnmatch(MMC_PATH, devnode, 0) &&
2440 fnmatch(SCSI_PATH, devnode, 0))
2444 r = check_external_storage(devnode);
2448 r = check_already_handled(devnode);
2450 _I("%s is already handled", devnode);
2454 _I("%s device add", devnode);
2455 add_block_device(dev, devnode, true);
2457 udev_device_unref(dev);
2460 udev_enumerate_unref(enumerate);
2465 // Called by MainThread
2466 static void show_block_device_list(void)
2468 struct block_device *bdev;
2469 struct block_data *data;
2473 for (i = 0; i < THREAD_MAX; i++) {
2474 pthread_mutex_lock(&(th_manager[i].mutex));
2475 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2481 _D("%s:", data->devnode);
2482 _D("\tSyspath: %s", data->syspath);
2483 _D("\tBlock type: %d", data->block_type);
2484 _D("\tFs type: %s", data->fs_type);
2485 _D("\tFs usage: %s", data->fs_usage);
2486 _D("\tFs version: %s", data->fs_version);
2487 _D("\tFs uuid enc: %s", data->fs_uuid_enc);
2488 _D("\tReadonly: %s",
2489 (data->readonly ? "true" : "false"));
2490 _D("\tMount point: %s", data->mount_point);
2491 _D("\tMount state: %s",
2492 (data->state == BLOCK_MOUNT ?
2493 "mount" : "unmount"));
2495 (data->primary ? "true" : "false"));
2496 _D("\tID: %d", data->id);
2498 pthread_mutex_unlock(&(th_manager[i].mutex));
2502 // Called by MainThread
2503 static void remove_whole_block_device(void)
2505 struct block_device *bdev;
2511 for (i = 0; i < THREAD_MAX; i++) {
2513 pthread_mutex_lock(&(th_manager[i].mutex));
2514 DD_LIST_FOREACH_SAFE(th_manager[i].block_dev_list, elem, next, bdev) {
2515 if (bdev->removed == false)
2518 pthread_mutex_unlock(&(th_manager[i].mutex));
2520 if (bdev && bdev->removed == false) {
2521 bdev->removed = true;
2522 r = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_NORMAL);
2524 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
2526 r = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2528 _E("Failed to add operation (remove %s)", bdev->data->devnode);
2535 static void booting_done(const char *sender_name,
2536 const char *object_path, const char *interface_name,
2537 const char *signal_name, DBusMessage *msg,
2540 static int done = 0;
2545 /* if there is the attached device, try to mount */
2546 block_init_from_udev_enumerate();
2547 block_control = true;
2551 static void block_poweroff(const char *sender_name,
2552 const char *object_path, const char *interface_name,
2553 const char *signal_name, DBusMessage *msg,
2556 static int status = 0;
2561 /* unregister mmc uevent control routine */
2562 unregister_udev_uevent_control(&uh);
2563 remove_whole_block_device();
2566 static void uevent_block_handler(struct udev_device *dev)
2568 const char *devnode = NULL;
2570 struct udev_list_entry *list_entry;
2573 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
2574 const char *devlink = udev_list_entry_get_name(list_entry);
2575 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2582 devnode = udev_device_get_devnode(dev);
2586 if (fnmatch(MMC_PATH, devnode, 0) &&
2587 fnmatch(SCSI_PATH, devnode, 0))
2591 r = check_external_storage(devnode);
2595 action = udev_device_get_action(dev);
2599 _I("%s device %s", devnode, action);
2600 if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD))) {
2601 r = check_already_handled(devnode);
2603 _I("%s is already handled", devnode);
2607 add_block_device(dev, devnode, false);
2608 } else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE)))
2609 remove_block_device(dev, devnode);
2612 static DBusMessage *request_mount_block(dbus_method_reply_handle_h reply_handle,
2613 DBusMessage *msg, bool onprivate)
2615 struct block_device *bdev;
2620 if (!reply_handle || !msg)
2623 ret = dbus_message_get_args(msg, NULL,
2624 DBUS_TYPE_INT32, &id,
2625 DBUS_TYPE_STRING, &mount_point,
2630 bdev = find_block_device_by_id(id);
2632 _E("Failed to find (%d) in the device list", id);
2636 if (bdev->on_private_op != REQ_NORMAL) {
2641 if (bdev->data->state == BLOCK_MOUNT) {
2642 _I("%s is already mounted", bdev->data->devnode);
2648 bdev->on_private_op = REQ_PRIVATE;
2649 bdev->private_pid = get_dbus_method_sender_pid(reply_handle);
2650 _D("Private operation state: %d", bdev->on_private_op);
2652 if (bdev->on_private_op != REQ_NORMAL) {
2653 _E("Failed to process mount operation");
2659 /* if requester want to use a specific mount point */
2661 !strncmp(mount_point, EXTENDED_SD_STRING, strlen(EXTENDED_SD_STRING) + 1) != 0) {
2662 if (!block_conf[bdev->data->block_type].extendedinternal ||
2663 !bdev->data->primary) {
2664 _E("Not support extended internal storage");
2668 bdev->data->block_type = BLOCK_MMC_EXTENDED_INTERNAL_DEV;
2669 ret = change_mount_point(bdev, EXTENDED_SD_PATH);
2675 create_file(bdev->data->id, bdev->data->mount_point, true);
2677 } else if (mount_point && strncmp(mount_point, "", 1) != 0) {
2678 ret = change_mount_point(bdev, mount_point);
2684 /* Create /run/external-storage/id file */
2685 create_file(bdev->data->id, bdev->data->mount_point, false);
2687 /* Create file for block device /run/external-storage/id */
2688 create_file(bdev->data->id, bdev->data->mount_point, false);
2691 ret = add_operation(bdev, BLOCK_DEV_MOUNT, reply_handle, NULL);
2693 _E("Failed to add operation (mount %s)", bdev->data->devnode);
2700 return make_dbus_reply_message_simple(reply_handle, ret);
2703 static DBusMessage *request_public_mount_block(dbus_method_reply_handle_h reply_handle,
2706 return request_mount_block(reply_handle, msg, false);
2709 static DBusMessage *request_private_mount_block(dbus_method_reply_handle_h reply_handle,
2712 return request_mount_block(reply_handle, msg, true);
2715 static DBusMessage *request_unmount_block(dbus_method_reply_handle_h reply_handle,
2716 DBusMessage *msg, bool onprivate)
2718 struct block_device *bdev;
2724 if (!reply_handle || !msg)
2727 ret = dbus_message_get_args(msg, NULL,
2728 DBUS_TYPE_INT32, &id,
2729 DBUS_TYPE_INT32, &option,
2734 bdev = find_block_device_by_id(id);
2736 _E("Failed to find (%d) in the device list", id);
2740 if (bdev->data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV) {
2741 _I("Impossible to request unmount extended internal sdcard");
2747 pid = get_dbus_method_sender_pid(reply_handle);
2748 if (bdev->on_private_op == REQ_NORMAL || (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid)) {
2749 _E("Failed to process private unmount operation");
2754 if (bdev->on_private_op != REQ_NORMAL) {
2755 _E("Failed to process unmount operation");
2761 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, reply_handle, (void *)option);
2763 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
2770 return make_dbus_reply_message_simple(reply_handle, ret);
2773 static DBusMessage *request_public_unmount_block(dbus_method_reply_handle_h reply_handle,
2776 return request_unmount_block(reply_handle, msg, false);
2779 static DBusMessage *request_private_unmount_block(dbus_method_reply_handle_h reply_handle,
2782 return request_unmount_block(reply_handle, msg, true);
2785 static DBusMessage *request_format_block(dbus_method_reply_handle_h reply_handle,
2788 struct block_device *bdev;
2789 struct format_data *fdata;
2796 if (!reply_handle || !msg)
2799 ret = dbus_message_get_args(msg, NULL,
2800 DBUS_TYPE_INT32, &id,
2801 DBUS_TYPE_INT32, &option,
2806 bdev = find_block_device_by_id(id);
2808 _E("Failed to find (%d) in the device list", id);
2812 pid = get_dbus_method_sender_pid(reply_handle);
2813 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
2814 _E("Failed to format on private state");
2819 fdata = get_format_data(NULL, option);
2821 _E("Failed to get format data");
2825 prev_state = bdev->data->state;
2826 if (prev_state == BLOCK_MOUNT) {
2827 if (bdev->on_private_op == REQ_PRIVATE) {
2828 bdev->on_private_op = REQ_PRIVATE_FORMAT;
2829 _D("Private operation state: %d", bdev->on_private_op);
2831 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2833 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
2834 release_format_data(fdata);
2839 ret = add_operation(bdev, BLOCK_DEV_FORMAT, reply_handle, (void *)fdata);
2841 _E("Failed to add operation (format %s)", bdev->data->devnode);
2842 release_format_data(fdata);
2845 /* Maintain previous state of mount/unmount */
2846 if (prev_state == BLOCK_MOUNT) {
2847 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
2848 _E("Failed to add operation (mount %s)", bdev->data->devnode);
2856 return make_dbus_reply_message_simple(reply_handle, ret);
2859 static DBusMessage *request_format_block_type(dbus_method_reply_handle_h reply_handle,
2862 struct block_device *bdev;
2863 struct format_data *fdata;
2871 if (!reply_handle || !msg)
2874 ret = dbus_message_get_args(msg, NULL,
2875 DBUS_TYPE_INT32, &id,
2876 DBUS_TYPE_INT32, &option,
2877 DBUS_TYPE_STRING, &type,
2882 bdev = find_block_device_by_id(id);
2884 _E("Failed to find (%d) in the device list", id);
2888 pid = get_dbus_method_sender_pid(reply_handle);
2889 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
2890 _E("Failed to format on private state");
2895 fdata = get_format_data(type, option);
2897 _E("Failed to get format data");
2901 prev_state = bdev->data->state;
2902 if (prev_state == BLOCK_MOUNT) {
2903 if (bdev->on_private_op == REQ_PRIVATE) {
2904 bdev->on_private_op = REQ_PRIVATE_FORMAT;
2905 _D("Private operation state: %d", bdev->on_private_op);
2907 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2909 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
2910 release_format_data(fdata);
2915 ret = add_operation(bdev, BLOCK_DEV_FORMAT, reply_handle, (void *)fdata);
2917 _E("Failed to add operation (format %s)", bdev->data->devnode);
2918 release_format_data(fdata);
2921 /* Maintain previous state of mount/unmount */
2922 if (prev_state == BLOCK_MOUNT) {
2923 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
2924 _E("Failed to add operation (mount %s)", bdev->data->devnode);
2932 return make_dbus_reply_message_simple(reply_handle, ret);
2935 static int add_device_to_iter(struct block_data *data, DBusMessageIter *piter)
2937 char *str_null = "";
2939 if (!data || !piter)
2942 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2943 &(data->block_type));
2944 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2945 data->devnode ? &(data->devnode) : &str_null);
2946 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2947 data->syspath ? &(data->syspath) : &str_null);
2948 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2949 data->fs_usage ? &(data->fs_usage) : &str_null);
2950 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2951 data->fs_type ? &(data->fs_type) : &str_null);
2952 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2953 data->fs_version ? &(data->fs_version) : &str_null);
2954 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2955 data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
2956 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2958 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2959 data->mount_point ? &(data->mount_point) : &str_null);
2960 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2962 dbus_message_iter_append_basic(piter, DBUS_TYPE_BOOLEAN,
2964 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2966 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2973 static int add_device_to_struct_iter(struct block_data *data, DBusMessageIter *iter)
2975 DBusMessageIter piter;
2980 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
2981 add_device_to_iter(data, &piter);
2982 dbus_message_iter_close_container(iter, &piter);
2987 static int add_device_to_iter_2(struct block_data *data, DBusMessageIter *iter)
2989 DBusMessageIter piter;
2990 char *str_null = "";
2995 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
2996 dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
2997 &(data->block_type));
2998 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
2999 data->devnode ? &(data->devnode) : &str_null);
3000 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3001 data->syspath ? &(data->syspath) : &str_null);
3002 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3003 data->fs_usage ? &(data->fs_usage) : &str_null);
3004 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3005 data->fs_type ? &(data->fs_type) : &str_null);
3006 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3007 data->fs_version ? &(data->fs_version) : &str_null);
3008 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3009 data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
3010 dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3012 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3013 data->mount_point ? &(data->mount_point) : &str_null);
3014 dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3016 dbus_message_iter_append_basic(&piter, DBUS_TYPE_BOOLEAN,
3018 dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3020 dbus_message_iter_close_container(iter, &piter);
3025 static DBusMessage *request_get_device_info(dbus_method_reply_handle_h reply_handle,
3028 DBusMessageIter iter;
3030 struct block_device *bdev;
3031 struct block_data *data;
3034 if (!reply_handle || !msg)
3037 reply = make_dbus_reply_message(reply_handle);
3041 ret = dbus_message_get_args(msg, NULL,
3042 DBUS_TYPE_INT32, &id,
3047 bdev = find_block_device_by_id(id);
3054 dbus_message_iter_init_append(reply, &iter);
3055 add_device_to_iter(data, &iter);
3061 static DBusMessage *request_show_device_list(dbus_method_reply_handle_h reply_handle,
3064 show_block_device_list();
3065 return make_dbus_reply_message(reply_handle);
3068 // Called by MainThread
3069 static DBusMessage *request_get_device_list(dbus_method_reply_handle_h reply_handle,
3072 DBusMessageIter iter;
3073 DBusMessageIter aiter;
3075 struct block_device *bdev;
3076 struct block_data *data;
3083 reply = make_dbus_reply_message(reply_handle);
3085 ret = dbus_message_get_args(msg, NULL,
3086 DBUS_TYPE_STRING, &type,
3089 _E("Failed to get args");
3094 _E("Delivered type is NULL");
3098 _D("Block (%s) device list is requested", type);
3100 if (!strncmp(type, BLOCK_TYPE_SCSI, sizeof(BLOCK_TYPE_SCSI)))
3101 block_type = BLOCK_SCSI_DEV;
3102 else if (!strncmp(type, BLOCK_TYPE_MMC, sizeof(BLOCK_TYPE_MMC)))
3103 block_type = BLOCK_MMC_DEV;
3104 else if (!strncmp(type, BLOCK_TYPE_ALL, sizeof(BLOCK_TYPE_ALL)))
3107 _E("Invalid type (%s) is requested", type);
3111 dbus_message_iter_init_append(reply, &iter);
3112 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(issssssisibii)", &aiter);
3114 for (i = 0; i < THREAD_MAX; i++) {
3115 pthread_mutex_lock(&(th_manager[i].mutex));
3116 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3123 switch (block_type) {
3124 case BLOCK_SCSI_DEV:
3126 if (data->block_type != block_type)
3132 add_device_to_struct_iter(data, &aiter);
3134 pthread_mutex_unlock(&(th_manager[i].mutex));
3136 dbus_message_iter_close_container(&iter, &aiter);
3142 // Called by MainThread
3143 static DBusMessage *request_get_device_list_2(dbus_method_reply_handle_h reply_handle,
3146 DBusMessageIter iter;
3147 DBusMessageIter aiter;
3149 struct block_device *bdev;
3150 struct block_data *data;
3157 reply = make_dbus_reply_message(reply_handle);
3159 ret = dbus_message_get_args(msg, NULL,
3160 DBUS_TYPE_STRING, &type,
3163 _E("Failed to get args");
3168 _E("Delivered type is NULL");
3172 _D("Block (%s) device list is requested", type);
3174 if (!strncmp(type, BLOCK_TYPE_SCSI, sizeof(BLOCK_TYPE_SCSI)))
3175 block_type = BLOCK_SCSI_DEV;
3176 else if (!strncmp(type, BLOCK_TYPE_MMC, sizeof(BLOCK_TYPE_MMC)))
3177 block_type = BLOCK_MMC_DEV;
3178 else if (!strncmp(type, BLOCK_TYPE_ALL, sizeof(BLOCK_TYPE_ALL)))
3181 _E("Invalid type (%s) is requested", type);
3185 dbus_message_iter_init_append(reply, &iter);
3186 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(issssssisibi)", &aiter);
3188 for (i = 0; i < THREAD_MAX; i++) {
3189 pthread_mutex_lock(&(th_manager[i].mutex));
3190 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3197 switch (block_type) {
3198 case BLOCK_SCSI_DEV:
3200 if (data->block_type != block_type)
3207 add_device_to_iter_2(data, &aiter);
3209 pthread_mutex_unlock(&(th_manager[i].mutex));
3211 dbus_message_iter_close_container(&iter, &aiter);
3217 static DBusMessage *request_get_mmc_primary(dbus_method_reply_handle_h reply_handle,
3220 DBusMessageIter iter;
3222 struct block_device *bdev;
3223 struct block_data *data, nodata = {0,};
3228 if (!reply_handle || !msg)
3231 reply = make_dbus_reply_message(reply_handle);
3236 for (i = 0; i < THREAD_MAX; i++) {
3237 pthread_mutex_lock(&(th_manager[i].mutex));
3238 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3244 if (data->block_type != BLOCK_MMC_DEV)
3251 pthread_mutex_unlock(&(th_manager[i].mutex));
3256 dbus_message_iter_init_append(reply, &iter);
3258 add_device_to_iter(data, &iter);
3260 nodata.id = -ENODEV;
3261 add_device_to_iter(&nodata, &iter);
3269 Method name Method call format string Reply format string
3270 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3271 { "GetDeviceList", "s", "a(issssssisibii)", request_get_device_list },
3272 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3273 { "Mount", "is", "i", request_public_mount_block },
3274 { "Unmoun, "ii", "i", request_public_unmount_block },
3275 { "Format", "ii", "i", request_format_block },
3276 { "GetDeviceInfo", "i", "(issssssisibii)", request_get_device_info },
3277 { "GetMmcPrimary", NULL, "(issssssisibii)" , request_get_mmc_primary },
3278 { "PrivateMount", "is", "i", request_private_mount_block },
3279 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3282 static const dbus_method_s manager_methods[] = {
3283 { "ShowDeviceList", NULL, request_show_device_list },
3284 { "GetDeviceList" , "s", request_get_device_list },
3285 { "GetDeviceList2", "s", request_get_device_list_2 },
3286 { "Mount", "is", request_public_mount_block },
3287 { "Unmount", "ii", request_public_unmount_block },
3288 { "Format", "ii", request_format_block },
3289 { "FormatwithType", "iis", request_format_block_type },
3290 { "GetDeviceInfo", "i", request_get_device_info },
3291 { "GetMmcPrimary" , NULL, request_get_mmc_primary },
3292 { "PrivateMount", "is", request_private_mount_block },
3293 { "PrivateUnmount", "ii", request_private_unmount_block },
3296 static dbus_interface_s block_interface = {
3297 .name = STORAGED_INTERFACE_BLOCK_MANAGER,
3298 .methods = manager_methods,
3299 .nr_methods = ARRAY_SIZE(manager_methods),
3302 static int load_config(struct parse_result *result, void *user_data)
3306 if (MATCH(result->section, "Block"))
3309 if (MATCH(result->section, "SCSI"))
3310 index = BLOCK_SCSI_DEV;
3311 else if (MATCH(result->section, "MMC"))
3312 index = BLOCK_MMC_DEV;
3316 if (MATCH(result->name, "Multimount"))
3317 block_conf[index].multimount =
3318 (MATCH(result->value, "yes") ? true : false);
3319 if (MATCH(result->name, "ExtendedInternalStorage"))
3320 block_conf[index].extendedinternal =
3321 (MATCH(result->value, "yes") ? true : false);
3323 if (index == BLOCK_MMC_DEV) {
3324 block_conf[index + 1].multimount = block_conf[index].multimount;
3325 block_conf[index + 1].extendedinternal = block_conf[index].extendedinternal;
3332 static int mount_root_path_tmpfs(void)
3337 root = tzplatform_getenv(TZ_SYS_MEDIA);
3341 if (access(root, F_OK) != 0)
3344 if (mount_check(root))
3347 ret = mount("tmpfs", root, "tmpfs", 0, "smackfsroot=System::Shared");
3350 _E("tmpfs mount failed (%d)", ret);
3357 #define mount_root_path_tmpfs() 0
3360 static void block_init(void *data)
3365 dbus_handle_h handle;
3370 ret = config_parse(BLOCK_CONF_FILE, load_config, NULL);
3372 _E("fail to load %s, Use default value", BLOCK_CONF_FILE);
3374 ret = mount_root_path_tmpfs();
3376 _E("Failed to mount tmpfs to root mount path (%d)", ret);
3378 ret = dbus_get_connection(&handle);
3380 _E("Failed to get dbus connection(%d)", ret);
3382 /* register block manager object and interface */
3383 ret = register_dbus_methods(handle,
3384 STORAGED_PATH_BLOCK_MANAGER, &block_interface,
3387 _E("Failed to register block interface and methods (%d)", ret);
3392 _E("fail to init pipe");
3394 /* register mmc uevent control routine */
3395 ret = register_udev_uevent_control(&uh);
3397 _E("fail to register block uevent : %d", ret);
3399 /* System Session is loaded completely */
3400 register_dbus_signal(SYSTEMD_DBUS_PATH,
3401 SYSTEMD_DBUS_IFACE_MANAGER,
3402 SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED,
3403 booting_done, NULL, NULL);
3405 register_dbus_signal(DEVICED_PATH_POWEROFF,
3406 DEVICED_INTERFACE_POWEROFF,
3407 SIGNAL_POWEROFF_STATE,
3408 block_poweroff, NULL, NULL);
3410 for (i = 0; i < THREAD_MAX; i++) {
3411 th_manager[i].num_dev = 0;
3412 th_manager[i].op_len = 0;
3413 th_manager[i].start_th = true;
3414 th_manager[i].thread_id = i;
3415 pthread_mutex_init(&(th_manager[i].mutex), NULL);
3416 pthread_cond_init(&(th_manager[i].cond), NULL);
3419 ret = stat(EXTERNAL_STORAGE_PATH, &buf);
3421 ret = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3423 _E("Failed to make directory: %d", errno);
3424 } else if (!S_ISDIR(buf.st_mode)) {
3425 ret = remove(EXTERNAL_STORAGE_PATH);
3427 _E("Fail to remove %s. errno: %d", EXTERNAL_STORAGE_PATH, errno);
3428 ret = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3430 _E("Failed to make directory: %d", errno);
3432 ret = chmod(EXTERNAL_STORAGE_PATH, 0644);
3434 _E("Fail to change permissions of a file");
3437 ret = stat(EXTENDED_INTERNAL_PATH, &buf);
3439 ret = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3441 _E("Failed to make directory: %d", errno);
3442 } else if (!S_ISDIR(buf.st_mode)) {
3443 ret = remove(EXTENDED_INTERNAL_PATH);
3445 _E("Fail to remove %s. errno: %d", EXTENDED_INTERNAL_PATH, errno);
3446 ret = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3448 _E("Failed to make directory: %d", errno);
3450 ret = chmod(EXTENDED_INTERNAL_PATH, 0644);
3452 _E("Fail to change permissions of a file");
3456 static void block_exit(void *data)
3458 dd_list *elem, *elem_next;
3464 /* unregister notifier for below each event */
3465 unregister_dbus_signal(SYSTEMD_DBUS_PATH,
3466 SYSTEMD_DBUS_IFACE_MANAGER,
3467 SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED,
3470 unregister_dbus_signal(DEVICED_PATH_POWEROFF,
3471 DEVICED_INTERFACE_POWEROFF,
3472 SIGNAL_POWEROFF_STATE, block_poweroff);
3477 /* unregister mmc uevent control routine */
3478 ret = unregister_udev_uevent_control(&uh);
3480 _E("fail to unregister block uevent : %d", ret);
3482 /* remove remaining blocks */
3483 remove_whole_block_device();
3485 for (i = 0; i < THREAD_MAX; i++) {
3486 if (!th_manager[i].start_th)
3487 pthread_cancel(th_manager[i].th);
3488 DD_LIST_FOREACH_SAFE(th_manager[i].th_node_list, elem, elem_next, temp) {
3489 DD_LIST_REMOVE(th_manager[i].th_node_list, temp);
3494 block_control = false;
3497 static int block_start(void *data)
3502 _E("Cannot be started. Booting is not ready");
3506 if (block_control) {
3507 _I("Already started");
3511 /* register mmc uevent control routine */
3512 ret = register_udev_uevent_control(&uh);
3514 _E("fail to register block uevent : %d", ret);
3516 block_init_from_udev_enumerate();
3518 block_control = true;
3524 static int block_stop(void *data)
3527 _E("Cannot be stopped. Booting is not ready");
3531 if (!block_control) {
3532 _I("Already stopped");
3536 /* unregister mmc uevent control routine */
3537 unregister_udev_uevent_control(&uh);
3539 /* remove the existing blocks */
3540 remove_whole_block_device();
3542 block_control = false;
3548 static storaged_module_interface block_module = {
3552 .start = block_start,
3556 __attribute__ ((visibility("default")))storaged_module_interface *
3557 storaged_get_module_interface(void)
3559 return &block_module;