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"
55 * TODO Assume root device is always mmcblk0*.
57 #define MMC_PATH "*/mmcblk[0-9]*"
58 #define MMC_PARTITION_PATH "mmcblk[0-9]p[0-9]"
59 /* Emulator send devlink for sdcard as \*\/sdcard\/\* */
60 #define MMC_LINK_PATH "*/sdcard/*"
61 #define SCSI_PATH "*/sd[a-z]*"
62 #define SCSI_PARTITION_PATH "sd[a-z][0-9]"
63 #define SCSI_PARTITION_LENGTH 9
65 #define FILESYSTEM "filesystem"
67 #define DEV_PREFIX "/dev/"
70 #define UNMOUNT_RETRY 5
71 #define TIMEOUT_MAKE_OBJECT 500 /* milliseconds */
73 #define SIGNAL_POWEROFF_STATE "ChangeState"
75 #define BLOCK_DEVICE_ADDED "DeviceAdded"
76 #define BLOCK_DEVICE_REMOVED "DeviceRemoved"
77 #define BLOCK_DEVICE_BLOCKED "DeviceBlocked"
78 #define BLOCK_DEVICE_CHANGED "DeviceChanged"
79 #define BLOCK_DEVICE_CHANGED_2 "DeviceChanged2"
81 #define BLOCK_TYPE_MMC "mmc"
82 #define BLOCK_TYPE_SCSI "scsi"
83 #define BLOCK_TYPE_ALL "all"
85 #define BLOCK_MMC_NODE_PREFIX "SDCard"
86 #define BLOCK_SCSI_NODE_PREFIX "USBDrive"
88 #define BLOCK_CONF_FILE "/etc/storaged/block.conf"
90 #define EXTERNAL_STORAGE_PATH "/run/external-storage"
91 #define EXTENDED_INTERNAL_PATH "/run/extended-internal-sd"
94 #define EXTENDED_SD_PATH "/opt/media/extendedsd"
95 #define EXTENDED_SD_STRING "ExtendedInternalSD"
97 /* Minimum value of block id */
98 #define BLOCK_ID_MIN 10
99 /* For 2.4 Backward Compatibility */
100 #define EXT_PRIMARY_SD_FIXID 1
102 /* Maximum number of thread */
105 #define PKGDIR_BUS_NAME "org.tizen.pkgdir_tool"
106 #define PKGDIR_PATH "/org/tizen/pkgdir_tool"
107 #define PKGDIR_INTERFACE "org.tizen.pkgdir_tool"
109 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
111 enum block_dev_operation {
119 enum private_operation_state {
125 struct operation_queue {
126 enum block_dev_operation op;
127 dbus_method_reply_handle_h reply_handle;
132 struct block_device {
133 struct block_data *data;
135 int thread_id; /* Current thread ID */
136 bool removed; /* True when device is physically removed but operation is not precessed yet */
137 enum private_operation_state on_private_op;
138 bool mount_point_updated;
143 struct block_device *bdev;
145 enum unmount_operation option;
149 enum block_dev_operation op;
150 struct block_device *bdev;
154 static struct block_conf {
156 bool extendedinternal;
157 } block_conf[BLOCK_MMC_EXTENDED_INTERNAL_DEV + 1];
159 static struct manage_thread {
160 dd_list *th_node_list; /* List of devnode which thread dealt with. Only main thread access */
161 dd_list *block_dev_list; /* Use thread mutex */
163 pthread_mutex_t mutex;
165 int num_dev; /* Number of devices which thread holds. Only main thread access */
166 int op_len; /* Number of operation of thread. Use thread mutex */
167 int thread_id; /* Never changed */
169 } th_manager[THREAD_MAX];
171 static dd_list *fs_head;
172 static dd_list *block_ops_list;
175 static fd_handler_h phandler;
176 static bool block_control = false;
177 static bool block_boot = false;
179 /* Assume there is only one physical internal storage */
180 static int dev_internal = -1;
181 static char dev_internal_scsi = '\0';
182 static char dev_internal_emul = '\0';
184 static int add_operation(struct block_device *bdev,
185 enum block_dev_operation operation,
186 dbus_method_reply_handle_h reply_handle, void *data);
187 static void remove_operation(struct block_device *bdev);
188 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
189 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
190 static int change_mount_point(struct block_device *bdev, const char *mount_point);
192 static void uevent_block_handler(struct udev_device *dev);
193 static struct uevent_handler uh = {
194 .subsystem = BLOCK_SUBSYSTEM,
195 .uevent_func = uevent_block_handler,
198 static void __CONSTRUCTOR__ smack_check(void)
203 fp = fopen("/proc/filesystems", "r");
207 while (fgets(buf, sizeof(buf), fp) != NULL) {
208 if (strstr(buf, "smackfs")) {
217 void add_fs(const struct block_fs_ops *fs)
219 DD_LIST_APPEND(fs_head, (void *)fs);
222 void remove_fs(const struct block_fs_ops *fs)
224 DD_LIST_REMOVE(fs_head, (void *)fs);
227 const struct block_fs_ops *find_fs(enum block_fs_type type)
229 struct block_fs_ops *fs;
232 DD_LIST_FOREACH(fs_head, elem, fs) {
233 if (fs->type == type)
239 void add_block_dev(const struct block_dev_ops *ops)
241 DD_LIST_APPEND(block_ops_list, (void *)ops);
244 void remove_block_dev(const struct block_dev_ops *ops)
246 DD_LIST_REMOVE(block_ops_list, (void *)ops);
249 static void broadcast_block_info(enum block_dev_operation op,
250 struct block_data *data, int result)
252 struct block_dev_ops *ops;
255 DD_LIST_FOREACH(block_ops_list, elem, ops) {
256 if (ops->block_type != data->block_type)
258 // TODO What happend on extended internal storage case?
259 if (op == BLOCK_DEV_MOUNT)
260 ops->mounted(data, result);
261 else if (op == BLOCK_DEV_UNMOUNT)
262 ops->unmounted(data, result);
263 else if (op == BLOCK_DEV_FORMAT)
264 ops->formatted(data, result);
265 else if (op == BLOCK_DEV_INSERT)
267 else if (op == BLOCK_DEV_REMOVE)
272 // Called by MainThread - Insert
273 static int block_get_new_id(void)
275 static int id = BLOCK_ID_MIN;
276 struct block_device *bdev;
281 for (i = 0 ; i < INT_MAX ; i++) {
283 for (j = 0; j < THREAD_MAX; j++) {
284 pthread_mutex_lock(&(th_manager[j].mutex));
285 DD_LIST_FOREACH(th_manager[j].block_dev_list, elem, bdev) {
286 if (bdev->data->id == id) {
291 pthread_mutex_unlock(&(th_manager[j].mutex));
306 static void remove_file(int id, bool extendedsd)
308 char file_name[PATH_LEN];
315 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
317 snprintf(file_name, sizeof(file_name), EXTERNAL_STORAGE_PATH"/%d", id);
319 ret = remove(file_name);
321 _E("Fail to remove %s. errno: %d", file_name, errno);
324 static void create_file(int id, char *mount_point, bool extendedsd)
327 char file_name[PATH_LEN];
333 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
335 snprintf(file_name, PATH_LEN, EXTERNAL_STORAGE_PATH"/%d", id);
337 fp = fopen(file_name, "w+");
339 fprintf(fp, "%s", mount_point);
342 _E("Fail to open %s", file_name);
345 static void signal_device_blocked(struct block_device *bdev)
347 struct block_data *data;
349 char str_block_type[32];
350 char str_readonly[32];
352 char str_primary[32];
358 if (!bdev || !bdev->data)
364 /* Broadcast outside with BlockManager iface */
365 snprintf(str_block_type, sizeof(str_block_type),
366 "%d", data->block_type);
367 arr[0] = str_block_type;
368 arr[1] = (data->devnode ? data->devnode : str_null);
369 arr[2] = (data->syspath ? data->syspath : str_null);
370 arr[3] = (data->fs_usage ? data->fs_usage : str_null);
371 arr[4] = (data->fs_type ? data->fs_type : str_null);
372 arr[5] = (data->fs_version ? data->fs_version : str_null);
373 arr[6] = (data->fs_uuid_enc ? data->fs_uuid_enc : str_null);
374 snprintf(str_readonly, sizeof(str_readonly),
375 "%d", data->readonly);
376 arr[7] = str_readonly;
377 arr[8] = (data->mount_point ? data->mount_point : str_null);
378 snprintf(str_state, sizeof(str_state),
381 snprintf(str_primary, sizeof(str_primary),
382 "%d", data->primary);
383 arr[10] = str_primary;
384 snprintf(str_flags, sizeof(str_flags), "%d", flags);
386 snprintf(str_id, sizeof(str_id), "%d", data->id);
389 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
390 STORAGED_INTERFACE_BLOCK_MANAGER,
391 BLOCK_DEVICE_BLOCKED,
392 "issssssisibii", arr);
395 static void signal_device_changed(struct block_device *bdev,
396 enum block_dev_operation op)
398 struct block_data *data;
400 char str_block_type[32];
401 char str_readonly[32];
403 char str_primary[32];
409 if (!bdev || !bdev->data)
415 case BLOCK_DEV_MOUNT:
416 BLOCK_GET_MOUNT_FLAGS(data, flags);
418 case BLOCK_DEV_UNMOUNT:
419 BLOCK_GET_UNMOUNT_FLAGS(data, flags);
421 case BLOCK_DEV_FORMAT:
422 BLOCK_GET_FORMAT_FLAGS(data, flags);
429 /* Broadcast outside with BlockManager iface */
430 snprintf(str_block_type, sizeof(str_block_type),
431 "%d", data->block_type);
432 arr[0] = str_block_type;
433 arr[1] = (data->devnode ? data->devnode : str_null);
434 arr[2] = (data->syspath ? data->syspath : str_null);
435 arr[3] = (data->fs_usage ? data->fs_usage : str_null);
436 arr[4] = (data->fs_type ? data->fs_type : str_null);
437 arr[5] = (data->fs_version ? data->fs_version : str_null);
438 arr[6] = (data->fs_uuid_enc ? data->fs_uuid_enc : str_null);
439 snprintf(str_readonly, sizeof(str_readonly),
440 "%d", data->readonly);
441 arr[7] = str_readonly;
442 arr[8] = (data->mount_point ? data->mount_point : str_null);
443 snprintf(str_state, sizeof(str_state),
446 snprintf(str_primary, sizeof(str_primary),
447 "%d", data->primary);
448 arr[10] = str_primary;
449 snprintf(str_flags, sizeof(str_flags), "%d", flags);
451 snprintf(str_id, sizeof(str_id), "%d", data->id);
454 if (op == BLOCK_DEV_INSERT)
455 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
456 STORAGED_INTERFACE_BLOCK_MANAGER,
458 "issssssisibii", arr);
459 else if (op == BLOCK_DEV_REMOVE)
460 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
461 STORAGED_INTERFACE_BLOCK_MANAGER,
462 BLOCK_DEVICE_REMOVED,
463 "issssssisibii", arr);
465 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
466 STORAGED_INTERFACE_BLOCK_MANAGER,
467 BLOCK_DEVICE_CHANGED,
468 "issssssisibii", arr);
469 broadcast_dbus_signal(STORAGED_PATH_BLOCK_MANAGER,
470 STORAGED_INTERFACE_BLOCK_MANAGER,
471 BLOCK_DEVICE_CHANGED_2,
472 "issssssisibi", arr);
476 static int get_mmc_mount_node(char *devnode, char *node, size_t len)
478 char *name = devnode;
479 int dev = -1, part = -1;
480 char emul[32] = { 0, };
487 sscanf(name, "mmcblk%dp%d", &dev, &part);
490 snprintf(node, len, "%s%c", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1);
492 snprintf(node, len, "%s%c%d", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1, part);
497 sscanf(name, "vd%31s", emul);
500 for (i = 0 ; i < strlen(emul) ; i++)
501 emul[i] = toupper(emul[i]);
502 snprintf(node, len, "%s%s", BLOCK_MMC_NODE_PREFIX, emul);
506 static int get_scsi_mount_node(char *devnode, char *node, size_t len)
514 snprintf(dev, sizeof(dev), "%s", devnode);
516 if (!strstr(dev, "sd"))
520 name += strlen("sd");
522 for (i = 0 ; i < strlen(name) ; i++)
523 name[i] = toupper(name[i]);
524 snprintf(node, len, "%s%s", BLOCK_SCSI_NODE_PREFIX, name);
529 static char *generate_mount_path(struct block_data *data)
532 char *name, node[64];
535 if (!data || !data->devnode)
538 name = strrchr(data->devnode, '/');
543 switch (data->block_type) {
545 ret = get_mmc_mount_node(name, node, sizeof(node));
548 ret = get_scsi_mount_node(name, node, sizeof(node));
550 case BLOCK_MMC_EXTENDED_INTERNAL_DEV:
551 return strdup(EXTENDED_SD_PATH);
553 _E("Invalid block type (%d)", data->block_type);
559 str = tzplatform_mkpath(TZ_SYS_MEDIA, node);
565 _E("Invalid devnode (%s)", data->devnode ? data->devnode : "NULL");
569 static bool check_primary_partition(const char *devnode)
571 struct block_fs_ops *fs;
574 const char *filesystem = NULL;
584 if (fnmatch(MMC_LINK_PATH, devnode, 0) &&
585 fnmatch(MMC_PATH, devnode, 0) &&
586 fnmatch(SCSI_PATH, devnode, 0))
589 temp = strrchr(devnode, '/');
592 if (fnmatch("/"SCSI_PARTITION_PATH, temp, 0) &&
593 fnmatch("/"MMC_PARTITION_PATH, temp, 0))
596 /* Emulator support only one partition */
600 snprintf(str, sizeof(str), "%s", devnode);
605 for (i = 1; i <= 9; ++i) {
606 snprintf(str2, sizeof(str2), "%s%d", str, i);
607 if (access(str2, R_OK) != 0)
610 probe = blkid_new_probe_from_filename(str2);
613 if (blkid_do_probe(probe) != 0)
616 ret = blkid_probe_lookup_value(probe, "TYPE", &filesystem, &fs_len);
618 blkid_free_probe(probe);
621 DD_LIST_FOREACH(fs_head, elem, fs) {
622 if (!strncmp(fs->name, filesystem, fs_len)) {
627 blkid_free_probe(probe);
633 if (found && !strncmp(devnode, str2, strlen(str2) + 1))
639 /* Whole data in struct block_data should be freed. */
640 static struct block_data *make_block_data(const char *devnode,
642 const char *fs_usage,
644 const char *fs_version,
645 const char *fs_uuid_enc,
646 const char *readonly)
648 struct block_data *data;
650 /* devnode is unique value so it should exist. */
655 _E("Not support extended partition");
659 data = calloc(1, sizeof(struct block_data));
661 _E("calloc() failed");
665 data->devnode = strdup(devnode);
667 data->syspath = strdup(syspath);
669 data->fs_usage = strdup(fs_usage);
671 data->fs_type = strdup(fs_type);
673 data->fs_version = strdup(fs_version);
675 data->fs_uuid_enc = strdup(fs_uuid_enc);
677 data->readonly = atoi(readonly);
678 data->primary = check_primary_partition(devnode);
680 /* TODO should we know block dev type? */
681 if (!fnmatch(MMC_LINK_PATH, devnode, 0))
682 data->block_type = BLOCK_MMC_DEV;
683 else if (!fnmatch(MMC_PATH, devnode, 0))
684 data->block_type = BLOCK_MMC_DEV;
685 else if (!fnmatch(SCSI_PATH, devnode, 0))
686 data->block_type = BLOCK_SCSI_DEV;
688 data->block_type = -1;
690 data->mount_point = generate_mount_path(data);
691 BLOCK_FLAG_CLEAR_ALL(data);
693 /* for 2.4 backward compatibility */
694 if (data->primary == true && data->block_type == BLOCK_MMC_DEV)
695 data->id = EXT_PRIMARY_SD_FIXID;
697 data->id = block_get_new_id();
702 static void free_block_data(struct block_data *data)
708 free(data->fs_usage);
710 free(data->fs_version);
711 free(data->fs_uuid_enc);
712 free(data->mount_point);
716 static int update_block_data(struct block_data *data,
717 const char *fs_usage,
719 const char *fs_version,
720 const char *fs_uuid_enc,
721 const char *readonly,
722 bool mount_point_updated)
727 free(data->fs_usage);
728 data->fs_usage = NULL;
730 data->fs_usage = strdup(fs_usage);
733 data->fs_type = NULL;
735 data->fs_type = strdup(fs_type);
737 free(data->fs_version);
738 data->fs_version = NULL;
740 data->fs_version = strdup(fs_version);
742 free(data->fs_uuid_enc);
743 data->fs_uuid_enc = NULL;
745 data->fs_uuid_enc = strdup(fs_uuid_enc);
747 /* generate_mount_path function should be invoked
748 * after fs_uuid_enc is updated */
749 if (!mount_point_updated) {
750 free(data->mount_point);
751 data->mount_point = generate_mount_path(data);
754 data->readonly = false;
756 data->readonly = atoi(readonly);
758 BLOCK_FLAG_MOUNT_CLEAR(data);
763 static struct block_device *make_block_device(struct block_data *data)
765 struct block_device *bdev;
770 bdev = calloc(1, sizeof(struct block_device));
775 bdev->thread_id = -1;
776 bdev->removed = false;
777 bdev->on_private_op = REQ_NORMAL;
778 bdev->private_pid = 0;
779 bdev->mount_point_updated = false;
784 // Called by MainThread - Remove DevNode
785 static void free_block_device(struct block_device *bdev)
788 struct operation_queue *op;
794 thread_id = bdev->thread_id;
795 if (thread_id < 0 || thread_id >= THREAD_MAX)
798 pthread_mutex_lock(&(th_manager[thread_id].mutex));
800 th_manager[thread_id].num_dev--;
801 DD_LIST_REMOVE(th_manager[thread_id].block_dev_list, bdev);
802 free_block_data(bdev->data);
804 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
806 th_manager[thread_id].op_len--;
807 DD_LIST_REMOVE(bdev->op_queue, op);
810 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
815 // Called By MainThread - Remove Device
816 static struct block_device *find_block_device(const char *devnode)
818 struct block_device *bdev;
823 len = strlen(devnode) + 1;
824 for (i = 0; i < THREAD_MAX; i++) {
825 pthread_mutex_lock(&(th_manager[i].mutex));
826 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
827 if (bdev->data && !bdev->removed &&
828 !strncmp(bdev->data->devnode, devnode, len)) {
829 pthread_mutex_unlock(&(th_manager[i].mutex));
833 pthread_mutex_unlock(&(th_manager[i].mutex));
839 // Called By MainThread - Mount,Unmount,Format,GetInfo
840 static struct block_device *find_block_device_by_id(int id)
842 struct block_device *bdev;
846 for (i = 0; i < THREAD_MAX; i++) {
847 pthread_mutex_lock(&(th_manager[i].mutex));
848 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
853 if (bdev->data->id == id) {
854 pthread_mutex_unlock(&(th_manager[i].mutex));
858 pthread_mutex_unlock(&(th_manager[i].mutex));
864 static char *get_operation_char(enum block_dev_operation op,
865 char *name, unsigned int len)
867 char *str = "unknown";
873 case BLOCK_DEV_MOUNT:
876 case BLOCK_DEV_UNMOUNT:
879 case BLOCK_DEV_FORMAT:
882 case BLOCK_DEV_INSERT:
885 case BLOCK_DEV_REMOVE:
889 _E("invalid operation (%d)", op);
893 snprintf(name, len, "%s", str);
897 static void create_external_apps_directory(void)
901 ret = call_dbus_method_async(PKGDIR_BUS_NAME, PKGDIR_PATH,
902 PKGDIR_INTERFACE, "CreateExternalDirsForAllPkgs",
903 NULL, NULL, NULL, DBUS_TIMEOUT_USE_DEFAULT, NULL);
905 _E("Fail to create external directory");
908 static int pipe_trigger(enum block_dev_operation op,
909 struct block_device *bdev, int result)
911 struct pipe_data pdata = { op, bdev, result };
915 _D("op : %s, bdev : %p, result : %d",
916 get_operation_char(pdata.op, name, sizeof(name)),
917 pdata.bdev, pdata.result);
919 n = write(pfds[1], &pdata, sizeof(struct pipe_data));
921 return (n != sizeof(struct pipe_data)) ? -EPERM : 0;
924 static bool pipe_cb(int fd, void *data)
926 struct pipe_data pdata = {0,};
932 n = read(fd, &pdata, sizeof(pdata));
933 if (n != sizeof(pdata) || !pdata.bdev) {
934 _E("fail to read struct pipe data");
938 _I("op : %s, bdev : %p, result : %d",
939 get_operation_char(pdata.op, name, sizeof(name)),
940 pdata.bdev, pdata.result);
942 if (pdata.op == BLOCK_DEV_MOUNT && pdata.result < 0) {
943 if (pdata.bdev->data->state == BLOCK_UNMOUNT) {
944 ret = change_mount_point(pdata.bdev, "");
945 /* Modify /run/external-storage/id file */
947 if (pdata.bdev->data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
948 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, true);
950 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, false);
955 if (pdata.op == BLOCK_DEV_MOUNT &&
956 pdata.bdev->data->state == BLOCK_MOUNT &&
957 pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
958 pdata.bdev->data->primary)
959 create_external_apps_directory();
960 if (pdata.op == BLOCK_DEV_UNMOUNT) {
961 /* Remove file for block device /run/xxxxxx/id */
962 if (pdata.bdev->data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV)
963 remove_file(pdata.bdev->data->id, true);
965 remove_file(pdata.bdev->data->id, false);
968 /* Broadcast to mmc and usb storage module */
969 broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
971 /* Broadcast outside with Block iface */
972 if (pdata.bdev->on_private_op == REQ_NORMAL)
973 signal_device_changed(pdata.bdev, pdata.op);
974 else if (pdata.bdev->on_private_op == REQ_PRIVATE) {
975 if (pdata.op == BLOCK_DEV_UNMOUNT) {
976 pdata.bdev->on_private_op = REQ_NORMAL;
977 _D("Private operation state: %d", pdata.bdev->on_private_op);
980 if (pdata.op == BLOCK_DEV_MOUNT) {
981 pdata.bdev->on_private_op = REQ_PRIVATE;
982 _D("Private operation state: %d", pdata.bdev->on_private_op);
986 if (pdata.op == BLOCK_DEV_REMOVE) {
987 thread_id = pdata.bdev->thread_id;
988 if (thread_id < 0 || thread_id >= THREAD_MAX)
990 free_block_device(pdata.bdev);
997 static int pipe_init(void)
1001 ret = pipe2(pfds, O_CLOEXEC);
1005 ret = add_fd_read_handler(pfds[0], pipe_cb,
1006 NULL, NULL, &phandler);
1008 _E("Failed to add pipe handler (%d)", ret);
1015 static void pipe_exit(void)
1018 remove_fd_read_handler(&phandler);
1028 static int mmc_check_and_unmount(const char *path)
1036 while (mount_check(path)) {
1040 if (retry > UNMOUNT_RETRY)
1047 static bool check_rw_mount(const char *szPath)
1049 struct statvfs mount_stat;
1051 if (!statvfs(szPath, &mount_stat)) {
1052 if ((mount_stat.f_flag & ST_RDONLY) == ST_RDONLY)
1058 static int retrieve_udev_device(struct block_data *data, bool mount_point_updated)
1061 struct udev_device *dev;
1069 _E("fail to create udev library context");
1073 dev = udev_device_new_from_syspath(udev, data->syspath);
1075 _E("fail to create new udev device");
1080 r = update_block_data(data,
1081 udev_device_get_property_value(dev, "ID_FS_USAGE"),
1082 udev_device_get_property_value(dev, "ID_FS_TYPE"),
1083 udev_device_get_property_value(dev, "ID_FS_VERSION"),
1084 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
1085 udev_device_get_sysattr_value(dev, "ro"),
1086 mount_point_updated);
1088 _E("fail to update block data for %s", data->devnode);
1090 udev_device_unref(dev);
1095 static int block_mount(struct block_data *data)
1097 struct block_fs_ops *fs;
1102 if (!data || !data->devnode || !data->mount_point)
1105 /* check existing mounted */
1106 if (mount_check(data->mount_point))
1109 /* create mount point */
1110 if (access(data->mount_point, R_OK) != 0) {
1111 if (mkdir(data->mount_point, 0755) < 0)
1115 /* check matched file system */
1116 if (!data->fs_usage ||
1117 strncmp(data->fs_usage, FILESYSTEM,
1118 sizeof(FILESYSTEM)) != 0) {
1123 if (!data->fs_type) {
1124 _E("There is no file system");
1125 BLOCK_FLAG_SET(data, FS_EMPTY);
1131 len = strlen(data->fs_type) + 1;
1132 DD_LIST_FOREACH(fs_head, elem, fs) {
1133 if (!strncmp(fs->name, data->fs_type, len))
1138 _E("Not supported file system (%s)", data->fs_type);
1139 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1144 r = fs->mount(smack, data->devnode, data->mount_point);
1147 BLOCK_FLAG_SET(data, FS_BROKEN);
1152 r = check_rw_mount(data->mount_point);
1159 rmdir(data->mount_point);
1163 static int mount_start(struct block_device *bdev)
1165 struct block_data *data;
1173 _I("Mount Start : (%s -> %s)",
1174 data->devnode, data->mount_point);
1176 /* mount operation */
1177 r = block_mount(data);
1178 if (r != -EROFS && r < 0) {
1179 _E("fail to mount %s device : %d", data->devnode, r);
1184 data->readonly = true;
1185 BLOCK_FLAG_SET(data, MOUNT_READONLY);
1188 data->state = BLOCK_MOUNT;
1190 if (data->block_type == BLOCK_MMC_DEV) {
1191 /* app2ext_migrate_legacy_all has dbus method call to deviced */
1192 ret = app2ext_migrate_legacy_all();
1194 _E("app2ext failed");
1198 if (r < 0 && r != -EROFS)
1199 data->state = BLOCK_UNMOUNT;
1201 _I("%s result : %s, %d", __func__, data->devnode, r);
1203 if (pipe_trigger(BLOCK_DEV_MOUNT, bdev, r) < 0)
1204 _E("fail to trigger pipe");
1209 static int change_mount_point(struct block_device *bdev,
1210 const char *mount_point)
1212 struct block_data *data;
1218 free(data->mount_point);
1220 /* If the mount path already exists, the path cannot be used */
1222 access(mount_point, F_OK) != 0) {
1223 data->mount_point = strdup(mount_point);
1224 bdev->mount_point_updated = true;
1226 data->mount_point = generate_mount_path(data);
1227 bdev->mount_point_updated = false;
1233 static int mount_block_device(struct block_device *bdev)
1235 struct block_data *data;
1238 if (!bdev || !bdev->data)
1242 if (data->state == BLOCK_MOUNT) {
1243 _I("%s is already mounted", data->devnode);
1247 if (!block_conf[data->block_type].multimount &&
1249 _I("Not support multi mount by config info");
1253 r = mount_start(bdev);
1255 _E("Failed to mount (%s)", data->devnode);
1262 static int block_unmount(struct block_device *bdev,
1263 enum unmount_operation option)
1265 struct block_data *data;
1267 struct timespec time = {0,};
1269 if (!bdev || !bdev->data || !bdev->data->mount_point)
1274 if (bdev->on_private_op == REQ_NORMAL)
1275 signal_device_blocked(bdev);
1277 /* it must called before unmounting mmc */
1278 r = mmc_check_and_unmount(data->mount_point);
1281 if (option == UNMOUNT_NORMAL) {
1282 _I("Failed to unmount with normal option : %d", r);
1286 _I("Execute force unmount!");
1287 /* Force Unmount Scenario */
1292 * should unmount the below vconf key. */
1293 if ((data->block_type == BLOCK_MMC_DEV ||
1294 data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV) &&
1296 /* At first, notify to other app
1297 * who already access sdcard */
1298 _I("Notify to other app who already access sdcard");
1299 vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS,
1300 VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
1304 /* Second, kill app with SIGTERM */
1305 _I("Kill app with SIGTERM");
1306 terminate_process(data->mount_point, false);
1309 /* Last time, kill app with SIGKILL */
1310 _I("Kill app with SIGKILL");
1311 terminate_process(data->mount_point, true);
1314 if (umount2(data->mount_point, MNT_DETACH) != 0) {
1315 _I("Failed to unmount with lazy option : %d",
1322 /* it takes some seconds til other app completely clean up */
1323 time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER;
1324 nanosleep(&time, NULL);
1326 print_open_files(data->mount_point);
1328 r = mmc_check_and_unmount(data->mount_point);
1330 _D("Success to unmount (%s)", data->mount_point);
1336 data->state = BLOCK_UNMOUNT;
1338 if (rmdir(data->mount_point) < 0)
1339 _E("fail to remove %s directory", data->mount_point);
1344 static int unmount_block_device(struct block_device *bdev,
1345 enum unmount_operation option)
1347 struct block_data *data;
1350 if (!bdev || !bdev->data)
1354 if (data->state == BLOCK_UNMOUNT) {
1355 _I("%s is already unmounted", data->devnode);
1356 r = mmc_check_and_unmount(data->mount_point);
1358 _E("The path was existed, but could not delete it(%s)",
1363 _I("Unmount Start : (%s -> %s)",
1364 data->devnode, data->mount_point);
1366 r = block_unmount(bdev, option);
1368 _E("fail to unmount %s device : %d", data->devnode, r);
1372 BLOCK_FLAG_MOUNT_CLEAR(data);
1375 _I("%s result : %s, %d", __func__, data->devnode, r);
1377 if (pipe_trigger(BLOCK_DEV_UNMOUNT, bdev, r) < 0)
1378 _E("fail to trigger pipe");
1383 static int block_format(struct block_data *data,
1384 const char *fs_type, bool mount_point_updated)
1386 const struct block_fs_ops *fs;
1391 if (!data || !data->devnode || !data->mount_point)
1395 fs_type = data->fs_type;
1398 len = strlen(fs_type);
1399 DD_LIST_FOREACH(fs_head, elem, fs) {
1400 if (!strncmp(fs->name, fs_type, len))
1405 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1406 _E("not supported file system(%s)", fs_type);
1410 _I("format path : %s", data->devnode);
1411 fs->check(data->devnode);
1412 r = fs->format(data->devnode);
1414 _E("fail to format block data for %s", data->devnode);
1418 /* need to update the partition data.
1419 * It can be changed in doing format. */
1420 retrieve_udev_device(data, mount_point_updated);
1426 static int format_block_device(struct block_device *bdev,
1427 const char *fs_type,
1428 enum unmount_operation option)
1430 struct block_data *data;
1438 _I("Format Start : (%s -> %s)",
1439 data->devnode, data->mount_point);
1441 if (data->state == BLOCK_MOUNT) {
1442 r = block_unmount(bdev, option);
1444 _E("fail to unmount %s device : %d", data->devnode, r);
1449 r = block_format(data, fs_type, bdev->mount_point_updated);
1451 _E("fail to format %s device : %d", data->devnode, r);
1454 _I("%s result : %s, %d", __func__, data->devnode, r);
1456 r = pipe_trigger(BLOCK_DEV_FORMAT, bdev, r);
1458 _E("fail to trigger pipe");
1463 static struct format_data *get_format_data(
1464 const char *fs_type, enum unmount_operation option)
1466 struct format_data *fdata;
1468 fdata = (struct format_data *)malloc(sizeof(struct format_data));
1470 _E("fail to allocate format data");
1475 fdata->fs_type = strdup(fs_type);
1477 fdata->fs_type = NULL;
1478 fdata->option = option;
1483 static void release_format_data(struct format_data *data)
1486 free(data->fs_type);
1491 // Called by BlockThread - Real Mount Op
1492 static int block_mount_device(struct block_device *bdev, void *data)
1501 thread_id = bdev->thread_id;
1502 if (thread_id < 0 || thread_id >= THREAD_MAX)
1504 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1505 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1506 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1508 _E("(%d) does not exist in the device list", bdev->data->devnode);
1512 /* mount automatically */
1513 ret = mount_block_device(bdev);
1515 _E("fail to mount block device for %s", bdev->data->devnode);
1520 // Called by BlockThread - Real Format Op
1521 static int block_format_device(struct block_device *bdev, void *data)
1526 struct format_data *fdata = (struct format_data *)data;
1528 if (!bdev || !fdata) {
1533 thread_id = bdev->thread_id;
1534 if (thread_id < 0 || thread_id >= THREAD_MAX)
1536 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1537 l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1538 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1540 _E("(%d) does not exist in the device list", bdev->data->devnode);
1545 ret = format_block_device(bdev, fdata->fs_type, fdata->option);
1547 _E("fail to mount block device for %s", bdev->data->devnode);
1550 release_format_data(fdata);
1555 // Called by BlockThread - Real Unmount Op
1556 static int block_unmount_device(struct block_device *bdev, void *data)
1559 long option = (long)data;
1564 ret = unmount_block_device(bdev, option);
1566 _E("Failed to unmount block device (%s)", bdev->data->devnode);
1573 /* Called by BlockThread - Remove Operation
1574 Direct Call at BlockThread
1575 Previously this function was called by MainThread. However, it will increase complexity.
1576 Need thread lock before to call remove_operation
1578 static void remove_operation(struct block_device *bdev)
1580 struct operation_queue *op;
1587 thread_id = bdev->thread_id;
1588 if (thread_id < 0 || thread_id >= THREAD_MAX)
1591 DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
1593 _D("Remove operation (%s, %s)",
1594 get_operation_char(op->op, name, sizeof(name)),
1595 bdev->data->devnode);
1597 DD_LIST_REMOVE(bdev->op_queue, op);
1603 static void block_send_dbus_reply(dbus_method_reply_handle_h reply_handle, int result)
1610 rep = make_dbus_reply_message_simple(reply_handle, result);
1611 reply_dbus_method_result(reply_handle, rep);
1614 // Called by BlockThread
1615 static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1617 struct operation_queue *temp;
1630 thread_id = bdev->thread_id;
1631 if (thread_id < 0 || thread_id >= THREAD_MAX)
1634 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1636 DD_LIST_FOREACH(*queue, l, temp) {
1637 if (temp->op == BLOCK_DEV_REMOVE) {
1642 th_manager[thread_id].op_len--;
1643 block_send_dbus_reply((*op)->reply_handle, 0);
1646 remove_operation(bdev);
1647 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1650 // Called by BlockThread
1651 static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
1653 struct operation_queue *temp;
1656 bool unmounted = false;
1667 thread_id = bdev->thread_id;
1668 if (thread_id < 0 || thread_id >= THREAD_MAX)
1671 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1672 DD_LIST_FOREACH(*queue, l, temp) {
1673 if (temp->op == BLOCK_DEV_UNMOUNT) {
1675 _D("Operation queue has unmount operation");
1679 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1684 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1686 DD_LIST_FOREACH(*queue, l, temp) {
1687 if (temp->op == BLOCK_DEV_UNMOUNT) {
1692 th_manager[thread_id].op_len--;
1693 block_send_dbus_reply((*op)->reply_handle, 0);
1696 remove_operation(bdev);
1697 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1702 // Called by BlockThread
1703 static void trigger_operation(struct block_device *bdev, dd_list *queue, struct operation_queue *op)
1707 char devnode[PATH_MAX];
1709 enum block_dev_operation operation;
1710 bool unmounted = false;
1717 thread_id = bdev->thread_id;
1718 if (thread_id < 0 || thread_id >= THREAD_MAX)
1721 snprintf(devnode, sizeof(devnode), "%s", bdev->data->devnode);
1731 _D("Thread id %d Trigger operation (%s, %s)", thread_id,
1732 get_operation_char(operation, name, sizeof(name)), devnode);
1735 if (operation == BLOCK_DEV_INSERT && bdev->removed) {
1736 check_removed(bdev, &queue, &op);
1738 _D("Trigger operation again (%s, %s)",
1739 get_operation_char(operation, name, sizeof(name)), devnode);
1741 if (operation == BLOCK_DEV_MOUNT) {
1742 unmounted = check_unmount(bdev, &queue, &op);
1745 _D("Trigger operation again (%s, %s)",
1746 get_operation_char(operation, name, sizeof(name)), devnode);
1750 switch (operation) {
1751 case BLOCK_DEV_INSERT:
1753 case BLOCK_DEV_MOUNT:
1754 ret = block_mount_device(bdev, op->data);
1755 _D("Mount (%s) result:(%d)", devnode, ret);
1757 case BLOCK_DEV_FORMAT:
1758 ret = block_format_device(bdev, op->data);
1759 _D("Format (%s) result:(%d)", devnode, ret);
1761 case BLOCK_DEV_UNMOUNT:
1762 ret = block_unmount_device(bdev, op->data);
1763 _D("Unmount (%s) result:(%d)", devnode, ret);
1765 case BLOCK_DEV_REMOVE:
1769 _E("Operation type is invalid (%d)", op->op);
1775 * during checking the queue length */
1776 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1779 th_manager[thread_id].op_len--;
1781 block_send_dbus_reply(op->reply_handle, ret);
1783 queue = bdev->op_queue;
1784 if (queue != NULL) {
1785 queue = DD_LIST_NEXT(queue);
1787 op = DD_LIST_NTH(queue, 0);
1793 remove_operation(bdev);
1795 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1799 if (operation == BLOCK_DEV_INSERT || operation == BLOCK_DEV_REMOVE) {
1800 if (pipe_trigger(operation, bdev, 0) < 0)
1801 _E("fail to trigger pipe");
1808 // Called by BlockThread
1809 static void *block_th_start(void *arg)
1811 struct block_device *temp;
1812 struct manage_thread *th = (struct manage_thread *)arg;
1813 struct operation_queue *op = NULL;
1815 dd_list *queue = NULL;
1820 thread_id = th->thread_id;
1821 if (thread_id < 0 || thread_id >= THREAD_MAX) {
1822 _E("Thread Number: %d", th->thread_id);
1827 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1828 if (th_manager[thread_id].op_len == 0) {
1829 _D("Operation queue of thread is empty");
1830 pthread_cond_wait(&(th_manager[thread_id].cond), &(th_manager[thread_id].mutex));
1831 _D("Wake up %d", thread_id);
1834 DD_LIST_FOREACH(th_manager[thread_id].block_dev_list, elem, temp) {
1835 queue = temp->op_queue;
1837 op = DD_LIST_NTH(queue, 0);
1839 _D("Operation queue for device %s is Empty", temp->data->devnode);
1843 queue = DD_LIST_NEXT(queue);
1851 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1853 if (op && !op->done)
1854 trigger_operation(temp, queue, op);
1859 // This function will be refactored later
1860 // Especially, we don't need to keep th_node_list.
1861 static int find_thread(char *devnode)
1868 int i, len, min, min_num;
1869 int dev_mmc = -1, part = -1, num;
1872 if (!fnmatch("*/"MMC_PARTITION_PATH, devnode, 0)) {
1873 sscanf(devnode, "/dev/mmcblk%dp%d", &dev_mmc, &part);
1880 snprintf(str, len, "/dev/mmcblk%d", dev_mmc);
1881 th_node = strdup(str);
1882 } else if (!fnmatch("*/"SCSI_PARTITION_PATH, devnode, 0)) {
1883 sscanf(devnode, "/dev/sd%c%d", &dev_scsi, &part);
1884 snprintf(str, SCSI_PARTITION_LENGTH, "/dev/sd%c", dev_scsi);
1885 th_node = strdup(str);
1889 len = strlen(th_node) + 1;
1892 for (i = 0; i < THREAD_MAX; i++) {
1893 DD_LIST_FOREACH(th_manager[i].th_node_list, elem, temp) {
1894 if (!strncmp(temp, th_node, len))
1897 if (th_manager[i].num_dev < min_num) {
1898 min_num = th_manager[i].num_dev;
1903 if (min >= 0 && min < THREAD_MAX) {
1904 DD_LIST_APPEND(th_manager[min].th_node_list, th_node);
1908 _E("Finding thread is failed");
1909 DD_LIST_APPEND(th_manager[0].th_node_list, th_node);
1913 /* Only Main thread is permmited */
1914 // Called by MainThread
1915 static int add_operation(struct block_device *bdev,
1916 enum block_dev_operation operation,
1917 dbus_method_reply_handle_h reply_handle, void *data)
1919 struct operation_queue *op;
1929 _I("Add operation (%s, %s)",
1930 get_operation_char(operation, name, sizeof(name)),
1931 bdev->data->devnode);
1933 thread_id = bdev->thread_id;
1934 if (thread_id < 0 || thread_id >= THREAD_MAX) {
1935 _E("Fail to find thread to add");
1939 op = (struct operation_queue *)malloc(sizeof(struct operation_queue));
1941 _E("malloc failed");
1947 op->reply_handle = reply_handle;
1950 * during adding queue and checking the queue length */
1951 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1953 /* Only modified between lock and unlock of mutex */
1956 start_th = th_manager[thread_id].start_th;
1957 DD_LIST_APPEND(bdev->op_queue, op);
1958 th_manager[thread_id].op_len++;
1960 if (th_manager[thread_id].op_len == 1 && !start_th)
1961 pthread_cond_signal(&(th_manager[thread_id].cond));
1963 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1966 /* Need to disble app2ext whenever unmounting mmc */
1967 if (op->op == BLOCK_DEV_UNMOUNT &&
1968 bdev->data->state == BLOCK_MOUNT &&
1969 bdev->data->block_type == BLOCK_MMC_DEV &&
1970 bdev->data->primary)
1971 if (app2ext_disable_all_external_pkgs() < 0)
1972 _E("app2ext_disable_all_external_pkgs() failed");
1976 _D("Start New thread for block device");
1977 th_manager[thread_id].start_th = false;
1978 ret = pthread_create(&(th_manager[thread_id].th), NULL, block_th_start, &th_manager[thread_id]);
1980 _E("fail to create thread for %s", bdev->data->devnode);
1984 pthread_detach(th_manager[thread_id].th);
1990 static bool disk_is_partitioned_by_kernel(struct udev_device *dev)
1993 struct dirent entry;
1995 const char *syspath;
1998 syspath = udev_device_get_syspath(dev);
2002 dp = opendir(syspath);
2004 _E("fail to open %s", syspath);
2008 /* TODO compare devname and d_name */
2009 while (readdir_r(dp, &entry, &dir) == 0 && dir != NULL) {
2010 if (!fnmatch(MMC_PARTITION_PATH, dir->d_name, 0) ||
2011 !fnmatch(SCSI_PARTITION_PATH, dir->d_name, 0)) {
2023 static bool check_partition(struct udev_device *dev)
2025 const char *devtype;
2026 const char *part_table_type;
2027 const char *fs_usage;
2030 /* only consider disk type, never partitions */
2031 devtype = udev_device_get_devtype(dev);
2035 if (strncmp(devtype, BLOCK_DEVTYPE_DISK,
2036 sizeof(BLOCK_DEVTYPE_DISK)) != 0)
2039 part_table_type = udev_device_get_property_value(dev,
2040 "ID_PART_TABLE_TYPE");
2041 if (part_table_type) {
2042 fs_usage = udev_device_get_property_value(dev,
2045 strncmp(fs_usage, FILESYSTEM, sizeof(FILESYSTEM)) == 0) {
2046 if (!disk_is_partitioned_by_kernel(dev))
2053 if (disk_is_partitioned_by_kernel(dev)) {
2062 // Called by MainThread
2063 static int add_block_device(struct udev_device *dev, const char *devnode)
2065 struct block_data *data;
2066 struct block_device *bdev;
2071 partition = check_partition(dev);
2073 /* if there is a partition, skip this request */
2074 _I("%s device has partitions, skip this time", devnode);
2078 data = make_block_data(devnode,
2079 udev_device_get_syspath(dev),
2080 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2081 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2082 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2083 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2084 udev_device_get_sysattr_value(dev, "ro"));
2086 _E("fail to make block data for %s", devnode);
2090 if (!block_conf[data->block_type].multimount && !data->primary) {
2091 _D("Not support multi mount by config info");
2095 bdev = make_block_device(data);
2097 _E("fail to make block device for %s", devnode);
2098 free_block_data(data);
2102 thread_id = find_thread(bdev->data->devnode);
2103 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2104 _E("Fail to find thread to add");
2105 free_block_device(bdev);
2108 bdev->thread_id = thread_id;
2110 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2111 th_manager[thread_id].num_dev++;
2112 DD_LIST_APPEND(th_manager[thread_id].block_dev_list, bdev);
2114 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2116 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2118 _E("Failed to add operation (insert %s)", devnode);
2119 free_block_device(bdev);
2123 // TODO Check this sdcard is already formatted for extended internal sdcard
2124 if (block_conf[bdev->data->block_type].extendedinternal &&
2125 bdev->data->block_type == BLOCK_MMC_DEV &&
2126 bdev->data->primary) {
2127 _I("Check whether sdcard will be used as extended internal storage");
2131 ret = add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL);
2133 _E("Failed to add operation (mount %s)", devnode);
2139 static int remove_block_device(struct udev_device *dev, const char *devnode)
2141 struct block_device *bdev;
2144 bdev = find_block_device(devnode);
2146 _E("fail to find block data for %s", devnode);
2150 BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
2152 bdev->removed = true;
2153 if (bdev->on_private_op != REQ_NORMAL) {
2154 bdev->on_private_op = REQ_NORMAL;
2155 _D("Private operation state: %d", bdev->on_private_op);
2158 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2160 _E("Failed to add operation (unmount %s)", devnode);
2164 ret = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2166 _E("Failed to add operation (remove %s)", devnode);
2173 static int get_internal_storage_number(void)
2175 struct libmnt_table *t = NULL;
2176 struct libmnt_fs *fs;
2179 int r = 0, dev_temp;
2181 if ((!is_emulator() && (dev_internal >= 0 || dev_internal_scsi != '\0')) ||
2182 (is_emulator() && dev_internal_emul != '\0'))
2185 t = mnt_new_table();
2189 r = mnt_table_parse_mtab(t, NULL);
2195 fs = mnt_table_find_target(t, ROOT_DIR, MNT_ITER_BACKWARD);
2201 temp = mnt_fs_get_srcpath(fs);
2205 name = strrchr(temp, '/');
2209 /* Boot from USB is not handled */
2210 if (!is_emulator()) {
2211 if (!fnmatch(MMC_PATH, temp, 0))
2212 sscanf(name, "mmcblk%d", &dev_internal);
2213 else if (!fnmatch(SCSI_PATH, temp, 0))
2214 sscanf(name, "sd%c", &dev_internal_scsi);
2216 if (!fnmatch(MMC_LINK_PATH, temp, 0))
2217 sscanf(name, "vd%c%d", &dev_internal_emul, &dev_temp);
2219 dev_internal_emul = '\0';
2227 static int check_external_storage(const char* devnode)
2229 char dev_scsi = '\0';
2232 int dev_num = -1, dev_temp;
2237 name = strrchr(devnode, '/');
2241 if (!is_emulator()) {
2242 if (!fnmatch(MMC_PATH, devnode, 0)) {
2243 sscanf(name, "mmcblk%d", &dev_num);
2244 if (dev_internal == dev_num) {
2245 _D("%s is internal storage", devnode);
2248 } else if (!fnmatch(SCSI_PATH, devnode, 0)) {
2249 sscanf(name, "sd%c", &dev_scsi);
2250 if (dev_internal_scsi == dev_scsi) {
2251 _D("%s is internal storage", devnode);
2256 if (!fnmatch(MMC_LINK_PATH, devnode, 0)) {
2257 sscanf(name, "vd%c%d", &emul, &dev_temp);
2258 if (dev_internal_emul == emul) {
2259 _D("%s is internal storage", devnode);
2268 static int check_already_handled(const char* devnode)
2270 struct block_device *bdev;
2271 struct block_data *data;
2275 for (i = 0; i < THREAD_MAX; i++) {
2276 pthread_mutex_lock(&(th_manager[i].mutex));
2277 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2283 if (!strncmp(data->devnode, devnode, strlen(devnode) + 1)) {
2284 pthread_mutex_unlock(&(th_manager[i].mutex));
2288 pthread_mutex_unlock(&(th_manager[i].mutex));
2294 static int block_init_from_udev_enumerate(void)
2297 struct udev_enumerate *enumerate;
2298 struct udev_list_entry *list_entry, *list_sub_entry;
2299 struct udev_device *dev;
2300 const char *syspath;
2301 const char *devnode;
2306 _E("fail to create udev library context");
2310 /* create a list of the devices in the 'usb' subsystem */
2311 enumerate = udev_enumerate_new(udev);
2313 _E("fail to create an enumeration context");
2317 if ((dev_internal < 0 && !is_emulator() && dev_internal_scsi == '\0') ||
2318 (is_emulator() && dev_internal_emul == '\0')) {
2319 r = get_internal_storage_number();
2324 udev_enumerate_add_match_subsystem(enumerate, BLOCK_SUBSYSTEM);
2325 udev_enumerate_add_match_property(enumerate,
2326 UDEV_DEVTYPE, BLOCK_DEVTYPE_DISK);
2327 udev_enumerate_add_match_property(enumerate,
2328 UDEV_DEVTYPE, BLOCK_DEVTYPE_PARTITION);
2329 udev_enumerate_scan_devices(enumerate);
2331 udev_list_entry_foreach(list_entry,
2332 udev_enumerate_get_list_entry(enumerate)) {
2333 syspath = udev_list_entry_get_name(list_entry);
2337 dev = udev_device_new_from_syspath(
2338 udev_enumerate_get_udev(enumerate),
2344 udev_list_entry_foreach(list_sub_entry,
2345 udev_device_get_devlinks_list_entry(dev)) {
2346 const char *devlink = udev_list_entry_get_name(list_sub_entry);
2347 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2354 devnode = udev_device_get_devnode(dev);
2358 if (fnmatch(MMC_PATH, devnode, 0) &&
2359 fnmatch(SCSI_PATH, devnode, 0))
2363 r = check_external_storage(devnode);
2367 r = check_already_handled(devnode);
2369 _I("%s is already handled", devnode);
2373 _I("%s device add", devnode);
2374 add_block_device(dev, devnode);
2376 udev_device_unref(dev);
2379 udev_enumerate_unref(enumerate);
2384 // Called by MainThread
2385 static void show_block_device_list(void)
2387 struct block_device *bdev;
2388 struct block_data *data;
2392 for (i = 0; i < THREAD_MAX; i++) {
2393 pthread_mutex_lock(&(th_manager[i].mutex));
2394 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2400 _D("%s:", data->devnode);
2401 _D("\tSyspath: %s", data->syspath);
2402 _D("\tBlock type: %d", data->block_type);
2403 _D("\tFs type: %s", data->fs_type);
2404 _D("\tFs usage: %s", data->fs_usage);
2405 _D("\tFs version: %s", data->fs_version);
2406 _D("\tFs uuid enc: %s", data->fs_uuid_enc);
2407 _D("\tReadonly: %s",
2408 (data->readonly ? "true" : "false"));
2409 _D("\tMount point: %s", data->mount_point);
2410 _D("\tMount state: %s",
2411 (data->state == BLOCK_MOUNT ?
2412 "mount" : "unmount"));
2414 (data->primary ? "true" : "false"));
2415 _D("\tID: %d", data->id);
2417 pthread_mutex_unlock(&(th_manager[i].mutex));
2421 // Called by MainThread
2422 static void remove_whole_block_device(void)
2424 struct block_device *bdev;
2430 for (i = 0; i < THREAD_MAX; i++) {
2432 pthread_mutex_lock(&(th_manager[i].mutex));
2433 DD_LIST_FOREACH_SAFE(th_manager[i].block_dev_list, elem, next, bdev) {
2434 if (bdev->removed == false)
2437 pthread_mutex_unlock(&(th_manager[i].mutex));
2439 if (bdev && bdev->removed == false) {
2440 bdev->removed = true;
2441 r = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_NORMAL);
2443 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
2445 r = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2447 _E("Failed to add operation (remove %s)", bdev->data->devnode);
2454 static void booting_done(const char *sender_name,
2455 const char *object_path, const char *interface_name,
2456 const char *signal_name, DBusMessage *msg,
2459 static int done = 0;
2464 /* if there is the attached device, try to mount */
2465 block_init_from_udev_enumerate();
2466 block_control = true;
2470 static void block_poweroff(const char *sender_name,
2471 const char *object_path, const char *interface_name,
2472 const char *signal_name, DBusMessage *msg,
2475 static int status = 0;
2480 /* unregister mmc uevent control routine */
2481 unregister_udev_uevent_control(&uh);
2482 remove_whole_block_device();
2485 static void uevent_block_handler(struct udev_device *dev)
2487 const char *devnode = NULL;
2489 struct udev_list_entry *list_entry;
2492 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
2493 const char *devlink = udev_list_entry_get_name(list_entry);
2494 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2501 devnode = udev_device_get_devnode(dev);
2505 if (fnmatch(MMC_PATH, devnode, 0) &&
2506 fnmatch(SCSI_PATH, devnode, 0))
2510 r = check_external_storage(devnode);
2514 action = udev_device_get_action(dev);
2518 _I("%s device %s", devnode, action);
2519 if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD))) {
2520 r = check_already_handled(devnode);
2522 _I("%s is already handled", devnode);
2526 add_block_device(dev, devnode);
2527 } else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE)))
2528 remove_block_device(dev, devnode);
2531 static DBusMessage *request_mount_block(dbus_method_reply_handle_h reply_handle,
2532 DBusMessage *msg, bool onprivate)
2534 struct block_device *bdev;
2539 if (!reply_handle || !msg)
2542 ret = dbus_message_get_args(msg, NULL,
2543 DBUS_TYPE_INT32, &id,
2544 DBUS_TYPE_STRING, &mount_point,
2549 bdev = find_block_device_by_id(id);
2551 _E("Failed to find (%d) in the device list", id);
2555 if (bdev->on_private_op != REQ_NORMAL) {
2560 if (bdev->data->state == BLOCK_MOUNT) {
2561 _I("%s is already mounted", bdev->data->devnode);
2567 bdev->on_private_op = REQ_PRIVATE;
2568 bdev->private_pid = get_dbus_method_sender_pid(reply_handle);
2569 _D("Private operation state: %d", bdev->on_private_op);
2571 if (bdev->on_private_op != REQ_NORMAL) {
2572 _E("Failed to process mount operation");
2578 /* if requester want to use a specific mount point */
2580 !strncmp(mount_point, EXTENDED_SD_STRING, strlen(EXTENDED_SD_STRING) + 1) != 0) {
2581 if (!block_conf[bdev->data->block_type].extendedinternal ||
2582 !bdev->data->primary) {
2583 _E("Not support extended internal storage");
2587 bdev->data->block_type = BLOCK_MMC_EXTENDED_INTERNAL_DEV;
2588 ret = change_mount_point(bdev, EXTENDED_SD_PATH);
2594 create_file(bdev->data->id, bdev->data->mount_point, true);
2596 } else if (mount_point && strncmp(mount_point, "", 1) != 0) {
2597 ret = change_mount_point(bdev, mount_point);
2603 /* Create /run/external-storage/id file */
2604 create_file(bdev->data->id, bdev->data->mount_point, false);
2606 /* Create file for block device /run/external-storage/id */
2607 create_file(bdev->data->id, bdev->data->mount_point, false);
2610 ret = add_operation(bdev, BLOCK_DEV_MOUNT, reply_handle, NULL);
2612 _E("Failed to add operation (mount %s)", bdev->data->devnode);
2619 return make_dbus_reply_message_simple(reply_handle, ret);
2622 static DBusMessage *request_public_mount_block(dbus_method_reply_handle_h reply_handle,
2625 return request_mount_block(reply_handle, msg, false);
2628 static DBusMessage *request_private_mount_block(dbus_method_reply_handle_h reply_handle,
2631 return request_mount_block(reply_handle, msg, true);
2634 static DBusMessage *request_unmount_block(dbus_method_reply_handle_h reply_handle,
2635 DBusMessage *msg, bool onprivate)
2637 struct block_device *bdev;
2643 if (!reply_handle || !msg)
2646 ret = dbus_message_get_args(msg, NULL,
2647 DBUS_TYPE_INT32, &id,
2648 DBUS_TYPE_INT32, &option,
2653 bdev = find_block_device_by_id(id);
2655 _E("Failed to find (%d) in the device list", id);
2659 if (bdev->data->block_type == BLOCK_MMC_EXTENDED_INTERNAL_DEV) {
2660 _I("Impossible to request unmount extended internal sdcard");
2666 pid = get_dbus_method_sender_pid(reply_handle);
2667 if (bdev->on_private_op == REQ_NORMAL || (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid)) {
2668 _E("Failed to process private unmount operation");
2673 if (bdev->on_private_op != REQ_NORMAL) {
2674 _E("Failed to process unmount operation");
2680 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, reply_handle, (void *)option);
2682 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
2689 return make_dbus_reply_message_simple(reply_handle, ret);
2692 static DBusMessage *request_public_unmount_block(dbus_method_reply_handle_h reply_handle,
2695 return request_unmount_block(reply_handle, msg, false);
2698 static DBusMessage *request_private_unmount_block(dbus_method_reply_handle_h reply_handle,
2701 return request_unmount_block(reply_handle, msg, true);
2704 static DBusMessage *request_format_block(dbus_method_reply_handle_h reply_handle,
2707 struct block_device *bdev;
2708 struct format_data *fdata;
2715 if (!reply_handle || !msg)
2718 ret = dbus_message_get_args(msg, NULL,
2719 DBUS_TYPE_INT32, &id,
2720 DBUS_TYPE_INT32, &option,
2725 bdev = find_block_device_by_id(id);
2727 _E("Failed to find (%d) in the device list", id);
2731 pid = get_dbus_method_sender_pid(reply_handle);
2732 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
2733 _E("Failed to format on private state");
2738 fdata = get_format_data(NULL, option);
2740 _E("Failed to get format data");
2744 prev_state = bdev->data->state;
2745 if (prev_state == BLOCK_MOUNT) {
2746 if (bdev->on_private_op == REQ_PRIVATE) {
2747 bdev->on_private_op = REQ_PRIVATE_FORMAT;
2748 _D("Private operation state: %d", bdev->on_private_op);
2750 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2752 _E("Failed to add operation (unmount %s)", bdev->data->devnode);
2753 release_format_data(fdata);
2758 ret = add_operation(bdev, BLOCK_DEV_FORMAT, reply_handle, (void *)fdata);
2760 _E("Failed to add operation (format %s)", bdev->data->devnode);
2761 release_format_data(fdata);
2764 /* Maintain previous state of mount/unmount */
2765 if (prev_state == BLOCK_MOUNT) {
2766 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
2767 _E("Failed to add operation (mount %s)", bdev->data->devnode);
2775 return make_dbus_reply_message_simple(reply_handle, ret);
2778 static int add_device_to_iter(struct block_data *data, DBusMessageIter *piter)
2780 char *str_null = "";
2782 if (!data || !piter)
2785 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2786 &(data->block_type));
2787 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2788 data->devnode ? &(data->devnode) : &str_null);
2789 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2790 data->syspath ? &(data->syspath) : &str_null);
2791 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2792 data->fs_usage ? &(data->fs_usage) : &str_null);
2793 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2794 data->fs_type ? &(data->fs_type) : &str_null);
2795 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2796 data->fs_version ? &(data->fs_version) : &str_null);
2797 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2798 data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
2799 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2801 dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
2802 data->mount_point ? &(data->mount_point) : &str_null);
2803 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2805 dbus_message_iter_append_basic(piter, DBUS_TYPE_BOOLEAN,
2807 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2809 dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
2816 static int add_device_to_struct_iter(struct block_data *data, DBusMessageIter *iter)
2818 DBusMessageIter piter;
2823 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
2824 add_device_to_iter(data, &piter);
2825 dbus_message_iter_close_container(iter, &piter);
2830 static int add_device_to_iter_2(struct block_data *data, DBusMessageIter *iter)
2832 DBusMessageIter piter;
2833 char *str_null = "";
2838 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
2839 dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
2840 &(data->block_type));
2841 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
2842 data->devnode ? &(data->devnode) : &str_null);
2843 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
2844 data->syspath ? &(data->syspath) : &str_null);
2845 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
2846 data->fs_usage ? &(data->fs_usage) : &str_null);
2847 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
2848 data->fs_type ? &(data->fs_type) : &str_null);
2849 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
2850 data->fs_version ? &(data->fs_version) : &str_null);
2851 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
2852 data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
2853 dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
2855 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
2856 data->mount_point ? &(data->mount_point) : &str_null);
2857 dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
2859 dbus_message_iter_append_basic(&piter, DBUS_TYPE_BOOLEAN,
2861 dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
2863 dbus_message_iter_close_container(iter, &piter);
2868 static DBusMessage *request_get_device_info(dbus_method_reply_handle_h reply_handle,
2871 DBusMessageIter iter;
2873 struct block_device *bdev;
2874 struct block_data *data;
2877 if (!reply_handle || !msg)
2880 reply = make_dbus_reply_message(reply_handle);
2884 ret = dbus_message_get_args(msg, NULL,
2885 DBUS_TYPE_INT32, &id,
2890 bdev = find_block_device_by_id(id);
2897 dbus_message_iter_init_append(reply, &iter);
2898 add_device_to_iter(data, &iter);
2904 static DBusMessage *request_show_device_list(dbus_method_reply_handle_h reply_handle,
2907 show_block_device_list();
2908 return make_dbus_reply_message(reply_handle);
2911 // Called by MainThread
2912 static DBusMessage *request_get_device_list(dbus_method_reply_handle_h reply_handle,
2915 DBusMessageIter iter;
2916 DBusMessageIter aiter;
2918 struct block_device *bdev;
2919 struct block_data *data;
2926 reply = make_dbus_reply_message(reply_handle);
2928 ret = dbus_message_get_args(msg, NULL,
2929 DBUS_TYPE_STRING, &type,
2932 _E("Failed to get args");
2937 _E("Delivered type is NULL");
2941 _D("Block (%s) device list is requested", type);
2943 if (!strncmp(type, BLOCK_TYPE_SCSI, sizeof(BLOCK_TYPE_SCSI)))
2944 block_type = BLOCK_SCSI_DEV;
2945 else if (!strncmp(type, BLOCK_TYPE_MMC, sizeof(BLOCK_TYPE_MMC)))
2946 block_type = BLOCK_MMC_DEV;
2947 else if (!strncmp(type, BLOCK_TYPE_ALL, sizeof(BLOCK_TYPE_ALL)))
2950 _E("Invalid type (%s) is requested", type);
2954 dbus_message_iter_init_append(reply, &iter);
2955 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(issssssisibii)", &aiter);
2957 for (i = 0; i < THREAD_MAX; i++) {
2958 pthread_mutex_lock(&(th_manager[i].mutex));
2959 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2966 switch (block_type) {
2967 case BLOCK_SCSI_DEV:
2969 if (data->block_type != block_type)
2975 add_device_to_struct_iter(data, &aiter);
2977 pthread_mutex_unlock(&(th_manager[i].mutex));
2979 dbus_message_iter_close_container(&iter, &aiter);
2985 // Called by MainThread
2986 static DBusMessage *request_get_device_list_2(dbus_method_reply_handle_h reply_handle,
2989 DBusMessageIter iter;
2990 DBusMessageIter aiter;
2992 struct block_device *bdev;
2993 struct block_data *data;
3000 reply = make_dbus_reply_message(reply_handle);
3002 ret = dbus_message_get_args(msg, NULL,
3003 DBUS_TYPE_STRING, &type,
3006 _E("Failed to get args");
3011 _E("Delivered type is NULL");
3015 _D("Block (%s) device list is requested", type);
3017 if (!strncmp(type, BLOCK_TYPE_SCSI, sizeof(BLOCK_TYPE_SCSI)))
3018 block_type = BLOCK_SCSI_DEV;
3019 else if (!strncmp(type, BLOCK_TYPE_MMC, sizeof(BLOCK_TYPE_MMC)))
3020 block_type = BLOCK_MMC_DEV;
3021 else if (!strncmp(type, BLOCK_TYPE_ALL, sizeof(BLOCK_TYPE_ALL)))
3024 _E("Invalid type (%s) is requested", type);
3028 dbus_message_iter_init_append(reply, &iter);
3029 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(issssssisibi)", &aiter);
3031 for (i = 0; i < THREAD_MAX; i++) {
3032 pthread_mutex_lock(&(th_manager[i].mutex));
3033 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3040 switch (block_type) {
3041 case BLOCK_SCSI_DEV:
3043 if (data->block_type != block_type)
3050 add_device_to_iter_2(data, &aiter);
3052 pthread_mutex_unlock(&(th_manager[i].mutex));
3054 dbus_message_iter_close_container(&iter, &aiter);
3060 static DBusMessage *request_get_mmc_primary(dbus_method_reply_handle_h reply_handle,
3063 DBusMessageIter iter;
3065 struct block_device *bdev;
3066 struct block_data *data, nodata = {0,};
3071 if (!reply_handle || !msg)
3074 reply = make_dbus_reply_message(reply_handle);
3079 for (i = 0; i < THREAD_MAX; i++) {
3080 pthread_mutex_lock(&(th_manager[i].mutex));
3081 DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3087 if (data->block_type != BLOCK_MMC_DEV)
3094 pthread_mutex_unlock(&(th_manager[i].mutex));
3099 dbus_message_iter_init_append(reply, &iter);
3101 add_device_to_iter(data, &iter);
3103 nodata.id = -ENODEV;
3104 add_device_to_iter(&nodata, &iter);
3112 Method name Method call format string Reply format string
3113 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3114 { "GetDeviceList" , "s", "a(issssssisibii)", request_get_device_list },
3115 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3116 { "Mount", "is", "i", request_public_mount_block },
3117 { "Unmount", "ii", "i", request_public_unmount_block },
3118 { "Format", "ii", "i", request_format_block },
3119 { "GetDeviceInfo", "i", "(issssssisibii)", request_get_device_info },
3120 { "GetMmcPrimary" , NULL, "(issssssisibii)" , request_get_mmc_primary },
3121 { "PrivateMount", "is", "i", request_private_mount_block },
3122 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3125 static const dbus_method_s manager_methods[] = {
3126 { "ShowDeviceList", NULL, request_show_device_list },
3127 { "GetDeviceList" , "s", request_get_device_list },
3128 { "GetDeviceList2", "s", request_get_device_list_2 },
3129 { "Mount", "is", request_public_mount_block },
3130 { "Unmount", "ii", request_public_unmount_block },
3131 { "Format", "ii", request_format_block },
3132 { "GetDeviceInfo", "i", request_get_device_info },
3133 { "GetMmcPrimary" , NULL, request_get_mmc_primary },
3134 { "PrivateMount", "is", request_private_mount_block },
3135 { "PrivateUnmount", "ii", request_private_unmount_block },
3138 static dbus_interface_s block_interface = {
3139 .name = STORAGED_INTERFACE_BLOCK_MANAGER,
3140 .methods = manager_methods,
3141 .nr_methods = ARRAY_SIZE(manager_methods),
3144 static int load_config(struct parse_result *result, void *user_data)
3148 if (MATCH(result->section, "Block"))
3151 if (MATCH(result->section, "SCSI"))
3152 index = BLOCK_SCSI_DEV;
3153 else if (MATCH(result->section, "MMC"))
3154 index = BLOCK_MMC_DEV;
3158 if (MATCH(result->name, "Multimount"))
3159 block_conf[index].multimount =
3160 (MATCH(result->value, "yes") ? true : false);
3161 if (MATCH(result->name, "ExtendedInternalStorage"))
3162 block_conf[index].extendedinternal =
3163 (MATCH(result->value, "yes") ? true : false);
3165 if (index == BLOCK_MMC_DEV) {
3166 block_conf[index + 1].multimount = block_conf[index].multimount;
3167 block_conf[index + 1].extendedinternal = block_conf[index].extendedinternal;
3174 static int mount_root_path_tmpfs(void)
3179 root = tzplatform_getenv(TZ_SYS_MEDIA);
3183 if (access(root, F_OK) != 0)
3186 if (mount_check(root))
3189 ret = mount("tmpfs", root, "tmpfs", 0, "smackfsroot=System::Shared");
3192 _E("tmpfs mount failed (%d)", ret);
3199 #define mount_root_path_tmpfs() 0
3202 static void block_init(void *data)
3207 dbus_handle_h handle;
3212 ret = config_parse(BLOCK_CONF_FILE, load_config, NULL);
3214 _E("fail to load %s, Use default value", BLOCK_CONF_FILE);
3216 ret = mount_root_path_tmpfs();
3218 _E("Failed to mount tmpfs to root mount path (%d)", ret);
3220 ret = dbus_get_connection(&handle);
3222 _E("Failed to get dbus connection(%d)", ret);
3224 /* register block manager object and interface */
3225 ret = register_dbus_methods(handle,
3226 STORAGED_PATH_BLOCK_MANAGER, &block_interface,
3229 _E("Failed to register block interface and methods (%d)", ret);
3234 _E("fail to init pipe");
3236 /* register mmc uevent control routine */
3237 ret = register_udev_uevent_control(&uh);
3239 _E("fail to register block uevent : %d", ret);
3241 /* System Session is loaded completely */
3242 register_dbus_signal(SYSTEMD_DBUS_PATH,
3243 SYSTEMD_DBUS_IFACE_MANAGER,
3244 SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED,
3245 booting_done, NULL, NULL);
3247 register_dbus_signal(DEVICED_PATH_POWEROFF,
3248 DEVICED_INTERFACE_POWEROFF,
3249 SIGNAL_POWEROFF_STATE,
3250 block_poweroff, NULL, NULL);
3252 for (i = 0; i < THREAD_MAX; i++) {
3253 th_manager[i].num_dev = 0;
3254 th_manager[i].op_len = 0;
3255 th_manager[i].start_th = true;
3256 th_manager[i].thread_id = i;
3257 pthread_mutex_init(&(th_manager[i].mutex), NULL);
3258 pthread_cond_init(&(th_manager[i].cond), NULL);
3261 ret = stat(EXTERNAL_STORAGE_PATH, &buf);
3263 ret = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3265 _E("Failed to make directory: %d", errno);
3266 } else if (!S_ISDIR(buf.st_mode)) {
3267 ret = remove(EXTERNAL_STORAGE_PATH);
3269 _E("Fail to remove %s. errno: %d", EXTERNAL_STORAGE_PATH, errno);
3270 ret = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3272 _E("Failed to make directory: %d", errno);
3274 ret = chmod(EXTERNAL_STORAGE_PATH, 644);
3276 _E("Fail to change permissions of a file");
3279 ret = stat(EXTENDED_INTERNAL_PATH, &buf);
3281 ret = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3283 _E("Failed to make directory: %d", errno);
3284 } else if (!S_ISDIR(buf.st_mode)) {
3285 ret = remove(EXTENDED_INTERNAL_PATH);
3287 _E("Fail to remove %s. errno: %d", EXTENDED_INTERNAL_PATH, errno);
3288 ret = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3290 _E("Failed to make directory: %d", errno);
3292 ret = chmod(EXTENDED_INTERNAL_PATH, 644);
3294 _E("Fail to change permissions of a file");
3298 static void block_exit(void *data)
3304 /* unregister notifier for below each event */
3305 unregister_dbus_signal(SYSTEMD_DBUS_PATH,
3306 SYSTEMD_DBUS_IFACE_MANAGER,
3307 SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED,
3310 unregister_dbus_signal(DEVICED_PATH_POWEROFF,
3311 DEVICED_INTERFACE_POWEROFF,
3312 SIGNAL_POWEROFF_STATE, block_poweroff);
3317 /* unregister mmc uevent control routine */
3318 ret = unregister_udev_uevent_control(&uh);
3320 _E("fail to unregister block uevent : %d", ret);
3322 /* remove remaining blocks */
3323 remove_whole_block_device();
3325 for (i = 0; i < THREAD_MAX; i++) {
3326 if (!th_manager[i].start_th)
3327 pthread_cancel(th_manager[i].th);
3330 block_control = false;
3333 static int block_start(void *data)
3338 _E("Cannot be started. Booting is not ready");
3342 if (block_control) {
3343 _I("Already started");
3347 /* register mmc uevent control routine */
3348 ret = register_udev_uevent_control(&uh);
3350 _E("fail to register block uevent : %d", ret);
3352 block_init_from_udev_enumerate();
3354 block_control = true;
3360 static int block_stop(void *data)
3363 _E("Cannot be stopped. Booting is not ready");
3367 if (!block_control) {
3368 _I("Already stopped");
3372 /* unregister mmc uevent control routine */
3373 unregister_udev_uevent_control(&uh);
3375 /* remove the existing blocks */
3376 remove_whole_block_device();
3378 block_control = false;
3384 static storaged_module_interface block_module = {
3388 .start = block_start,
3392 __attribute__ ((visibility("default")))storaged_module_interface *
3393 storaged_get_module_interface(void)
3395 return &block_module;