Fix resource leak - mnt_new_table/mnt_free_table
[platform/core/system/storaged.git] / src / block / block.c
1 /*
2  * storaged
3  *
4  * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19 #define _GNU_SOURCE
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <sys/mount.h>
28 #include <sys/statvfs.h>
29 #include <fnmatch.h>
30 #include <errno.h>
31 #include <dirent.h>
32 #include <sys/statfs.h>
33 #include <stdbool.h>
34 #include <pthread.h>
35 #include <time.h>
36 #include <assert.h>
37 #include <vconf.h>
38 #include <ctype.h>
39 #include <tzplatform_config.h>
40 #include <app2ext_interface.h>
41 #include <libmount.h>
42 #include <blkid/blkid.h>
43 #include <glib.h>
44 #include <glib/gstdio.h>
45 #include <gio/gio.h>
46 #include <libsyscommon/libgdbus.h>
47 #include <libsyscommon/ini-parser.h>
48 #include <libsyscommon/list.h>
49 #ifdef EXTENDED_STORAGE
50 #include <ode/luks.h>
51 #endif
52
53 #include "log.h"
54 #include "module-intf.h"
55 #include "udev.h"
56 #include "block.h"
57 #include "fd_handler.h"
58 #include "utils.h"
59 #include "apps.h"
60 #include "storaged_common.h"
61
62 /**
63  * TODO  Assume root device is always mmcblk0*.
64  */
65 #define MMC_PATH                "*/mmcblk[0-9]*"
66 #define MMC_PARTITION_PATH      "mmcblk[0-9]p[0-9]"
67 /* Emulator send devlink for sdcard as \*\/sdcard\/\* */
68 #define MMC_LINK_PATH           "*/sdcard/*"
69 #define SCSI_PATH               "*/sd[a-z]*"
70 #define SCSI_PARTITION_PATH     "sd[a-z][0-9]"
71 #define SCSI_PARTITION_LENGTH   9
72 #define EXTENDEDSD_NODE_PATH    "/dev/mapper/extendedsd"
73
74 #define FILESYSTEM_NAME         "filesystem"
75
76 #define DEV_PREFIX              "/dev/"
77 #define ROOT_DIR                "/"
78
79 #define UNMOUNT_RETRY           5
80 #define TIMEOUT_MAKE_OBJECT     500 /* milliseconds */
81
82 #define SIGNAL_POWEROFF_STATE   "ChangeState"
83 #define METHOD_ADD_POWEROFF_WAIT        "AddPowerOffWait"
84 #define METHOD_REMOVE_POWEROFF_WAIT     "RemovePowerOffWait"
85
86 #define BLOCK_DEVICE_ADDED      "DeviceAdded"
87 #define BLOCK_DEVICE_REMOVED    "DeviceRemoved"
88 #define BLOCK_DEVICE_BLOCKED    "DeviceBlocked"
89 #define BLOCK_DEVICE_CHANGED    "DeviceChanged"
90
91 #define BLOCK_TYPE_MMC          "mmc"
92 #define BLOCK_TYPE_SCSI         "scsi"
93 #define BLOCK_TYPE_ALL          "all"
94
95 #define BLOCK_MMC_NODE_PREFIX   "SDCard"
96 #define BLOCK_SCSI_NODE_PREFIX  "USBDrive"
97
98 #define BLOCK_CONF_FILE         "/etc/storaged/block.conf"
99
100 #define EXTERNAL_STORAGE_PATH   "/run/storaged/external-storage"
101 #define EXTENDED_INTERNAL_PATH  "/run/storaged/extended-internal-sd"
102 #define PATH_LEN                55
103
104 #define EXTENDEDSD_MOUNT_PATH   "/opt/extendedsd"
105
106 #define VFAT_NAME               "vfat"
107 #define EXFAT_NAME              "exfat"
108 #define EXT4_NAME               "ext4"
109 #define LUKS_NAME               "crypto_LUKS"
110 #define EXTENDEDSD_NAME "extendedsd"
111
112 /* Minimum value of block id */
113 #define BLOCK_ID_MIN            10
114 /* For 2.4 Backward Compatibility */
115 #define EXT_PRIMARY_SD_FIXID    1
116
117 /* Maximum number of thread */
118 #define THREAD_MAX              5
119
120 #define SPEEDCHECK_SIZE         16
121 #define SPEEDCHECK_CRITERION    4 /* MB/s */
122
123 #define PKGDIR_BUS_NAME         "org.tizen.pkgdir_tool"
124 #define PKGDIR_PATH             "/org/tizen/pkgdir_tool"
125 #define PKGDIR_INTERFACE        "org.tizen.pkgdir_tool"
126
127 #define POPUP_KEY_CONTENT       "_SYSPOPUP_CONTENT_"
128 #define VIEWTYPE_KEY            "viewtype"
129 #define DEVPATH_KEY             "dev_path"
130 #define MAPPING_NODE_KEY        "mapping_node"
131 #define INSERT_SD_CARD          "INSERT_SD_CARD"
132
133 #define MMC_POPUP_NOTI          "SDcardNoti"
134 #define MMC_INSERTED            "inserted"
135 #define MMC_REMOVED             "removed"
136
137 #define ARRAY_SIZE(name)        (sizeof(name)/sizeof(name[0]))
138
139 #define FILE_NAME_LEN_MAX       255
140
141 enum block_dev_operation {
142         BLOCK_DEV_MOUNT,
143         BLOCK_DEV_UNMOUNT,
144         BLOCK_DEV_FORMAT,
145         BLOCK_DEV_INSERT,
146         BLOCK_DEV_REMOVE,
147         BLOCK_LUKS_CLOSE,
148 };
149
150 enum private_operation_state {
151         REQ_NORMAL,
152         REQ_PRIVATE,
153         REQ_PRIVATE_FORMAT,
154 };
155
156 struct operation_queue {
157         enum block_dev_operation op;
158         GDBusMethodInvocation *invocation;
159         void *data;
160         bool done;
161 };
162
163 struct block_device {
164         struct block_data *data;
165         GList *op_queue;
166         int thread_id;          /* Current thread ID */
167         bool removed;           /* True when device is physically removed but operation is not precessed yet */
168         enum private_operation_state on_private_op;
169         bool mount_point_updated;
170         pid_t private_pid;
171 };
172
173 struct format_data {
174         struct block_device *bdev;
175         char *fs_type;
176         enum unmount_operation option;
177 };
178
179 struct pipe_data {
180         enum block_dev_operation op;
181         struct block_device *bdev;
182         int result;
183 };
184
185 static struct block_conf {
186         bool multimount;
187         bool extendedinternal;
188 } block_conf[BLOCK_EXTENDEDSD_DEV + 1];
189
190 static struct manage_thread {
191         GList *th_node_list;    /* List of devnode which thread dealt with. Only main thread access */
192         GList *block_dev_list; /* Use thread mutex */
193         pthread_t th;
194         pthread_mutex_t mutex;
195         pthread_cond_t cond;
196         int num_dev;            /* Number of devices which thread holds. Only main thread access */
197         int op_len;             /* Number of operation of thread. Use thread mutex */
198         int thread_id;          /* Never changed */
199         bool start_th;
200 } th_manager[THREAD_MAX];
201
202 char mmc_default_path[][FILE_NAME_LEN_MAX + 1] = {
203         {"Images"},
204         {"Videos"},
205         {"Sounds"},
206         {"Downloads"},
207 };
208
209 #define DIR_NUM ((int)(sizeof(mmc_default_path)/sizeof(mmc_default_path[0])))
210
211 static GList *fs_head;
212 static GList *block_ops_list;
213 static bool smack;
214 static int pfds[2];
215 static fd_handler_h phandler;
216 static bool block_control = false;
217 static bool block_boot = false;
218 static pthread_mutex_t pipe_mutex = PTHREAD_MUTEX_INITIALIZER;
219 static bool add_poweroff_wait = false;
220
221 /* Assume there is only one physical internal storage */
222 static int dev_internal = -1;
223 static char dev_internal_scsi = '\0';
224 static char dev_internal_emul = '\0';
225
226 static int block_start(void *data);
227 static int block_stop(void *data);
228
229 static int add_operation(struct block_device *bdev,
230                 enum block_dev_operation operation,
231                 GDBusMethodInvocation *invocation, void *data);
232 static void remove_operation(struct block_device *bdev);
233 static void check_removed(struct block_device *bdev, GList **queue, struct operation_queue **op);
234 static bool check_unmount(struct block_device *bdev, GList **queue, struct operation_queue **op);
235 static int change_mount_point(struct block_device *bdev, const char *mount_point);
236 static void terminate_threads(void);
237
238 #define nullstr(x) (x ? x : "")
239 static GVariant *block_data_to_gvariant(struct block_data *data, int flags);
240
241 #define block_send_dbus_reply(invocation, result) if (invocation) {g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", result)); }
242
243 static void uevent_block_handler(struct udev_device *dev);
244 static struct uevent_handler uh = {
245         .subsystem = BLOCK_SUBSYSTEM,
246         .uevent_func = uevent_block_handler,
247 };
248
249 static void __CONSTRUCTOR__ smack_check(void)
250 {
251         FILE *fp;
252         char buf[128];
253
254         fp = fopen("/proc/filesystems", "r");
255         if (!fp)
256                 return;
257
258         while (fgets(buf, sizeof(buf), fp) != NULL) {
259                 if (strstr(buf, "smackfs")) {
260                         smack = true;
261                         break;
262                 }
263         }
264
265         fclose(fp);
266 }
267
268 void add_fs(const struct block_fs_ops *fs)
269 {
270         SYS_G_LIST_APPEND(fs_head, (void *)fs);
271 }
272
273 void remove_fs(const struct block_fs_ops *fs)
274 {
275         SYS_G_LIST_REMOVE(fs_head, (void *)fs);
276 }
277
278 const struct block_fs_ops *find_fs(enum block_fs_type type)
279 {
280         struct block_fs_ops *fs;
281         GList *elem;
282
283         SYS_G_LIST_FOREACH(fs_head, elem, fs) {
284                 if (fs->type == type)
285                         return fs;
286         }
287         return NULL;
288 }
289
290 void add_block_dev(const struct block_dev_ops *ops)
291 {
292         SYS_G_LIST_APPEND(block_ops_list, (void *)ops);
293 }
294
295 void remove_block_dev(const struct block_dev_ops *ops)
296 {
297         SYS_G_LIST_REMOVE(block_ops_list, (void *)ops);
298 }
299
300 static void broadcast_block_info(enum block_dev_operation op,
301                 struct block_data *data, int result)
302 {
303         struct block_dev_ops *ops;
304         GList *elem;
305
306         if (data->primary != true)
307                 return;
308
309         SYS_G_LIST_FOREACH(block_ops_list, elem, ops) {
310                 int data_block_type = (data->block_type == BLOCK_EXTENDEDSD_DEV)
311                                       ? BLOCK_MMC_DEV : data->block_type;
312
313                 if (ops->block_type != data_block_type)
314                         continue;
315                 // TODO What happend on extended internal storage case?
316                 if (op == BLOCK_DEV_MOUNT) {
317                         ops->mounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
318                 } else if (op == BLOCK_DEV_UNMOUNT) {
319                         ops->unmounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
320                 } else if (op == BLOCK_DEV_FORMAT) {
321                         ops->formatted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
322                 } else if (op == BLOCK_DEV_INSERT)
323                         ops->inserted(data);
324                 else if (op == BLOCK_DEV_REMOVE)
325                         ops->removed(data);
326         }
327 }
328
329 // Called by MainThread - Insert
330 static int block_get_new_id(void)
331 {
332         static int id = BLOCK_ID_MIN;
333         struct block_device *bdev;
334         GList *elem;
335         bool found;
336         int i, j;
337
338         for (i = 0 ; i < INT_MAX ; i++) {
339                 found = false;
340                 for (j = 0; j < THREAD_MAX; j++) {
341                         pthread_mutex_lock(&(th_manager[j].mutex));
342                         SYS_G_LIST_FOREACH(th_manager[j].block_dev_list, elem, bdev) {
343                                 if (bdev->data->id == id) {
344                                         found = true;
345                                         break;
346                                 }
347                         }
348                         pthread_mutex_unlock(&(th_manager[j].mutex));
349                         if (found)
350                                 break;
351                 }
352
353                 if (!found)
354                         return id++;
355
356                 if (++id == INT_MAX)
357                         id = BLOCK_ID_MIN;
358         }
359
360         return -ENOENT;
361 }
362
363 static void remove_file(int id, bool extendedsd)
364 {
365         char file_name[PATH_LEN];
366         int ret_val;
367
368         if (id < 0)
369                 return;
370
371         if (extendedsd)
372                 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
373         else
374                 snprintf(file_name, sizeof(file_name), EXTERNAL_STORAGE_PATH"/%d", id);
375
376         ret_val = remove(file_name);
377         if (ret_val < 0)
378                 _E("Failed to remove '%s': %d", file_name, errno);
379 }
380
381 static void create_file(int id, char *mount_point, bool extendedsd)
382 {
383         FILE *fp;
384         char file_name[PATH_LEN];
385
386         if (id < 0)
387                 return;
388
389         if (extendedsd)
390                 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
391         else
392                 snprintf(file_name, PATH_LEN, EXTERNAL_STORAGE_PATH"/%d", id);
393
394         fp = fopen(file_name, "w+");
395         if (fp) {
396                 fprintf(fp, "%s", mount_point);
397                 fclose(fp);
398         } else
399                 _E("Failed to open '%s'.", file_name);
400 }
401
402 static void broadcast_device_blocked(struct block_device *bdev)
403 {
404         struct block_data *data;
405         int ret_dbus;
406
407         if (!bdev || !bdev->data)
408                 return;
409
410         data = bdev->data;
411
412         ret_dbus = gdbus_signal_emit(NULL,
413                         STORAGED_PATH_BLOCK_MANAGER,
414                         STORAGED_INTERFACE_BLOCK_MANAGER,
415                         BLOCK_DEVICE_BLOCKED,
416                         block_data_to_gvariant(data, 0));
417         if (ret_dbus < 0)
418                 _E("Failed to send dbus signal");
419 }
420
421 static void broadcast_device_changed(struct block_device *bdev,
422                 enum block_dev_operation op)
423 {
424         struct block_data *data;
425         GVariant *param = NULL;
426         const char *signal_name = NULL;
427         int flags = 0;
428         int ret_dbus;
429
430         if (!bdev || !bdev->data) {
431                 _E("Failed to broadcast device changed signal. op(%d)", op);
432                 return;
433         }
434
435         data = bdev->data;
436
437         /* set flags and signal name */
438         switch (op) {
439         case BLOCK_DEV_MOUNT:
440                 BLOCK_GET_MOUNT_FLAGS(data, flags);
441                 signal_name = BLOCK_DEVICE_CHANGED;
442                 break;
443         case BLOCK_DEV_UNMOUNT:
444                 BLOCK_GET_UNMOUNT_FLAGS(data, flags);
445                 signal_name = BLOCK_DEVICE_CHANGED;
446                 break;
447         case BLOCK_DEV_FORMAT:
448                 BLOCK_GET_FORMAT_FLAGS(data, flags);
449                 signal_name = BLOCK_DEVICE_CHANGED;
450                 break;
451         case BLOCK_DEV_INSERT:
452                 flags = 0;
453                 signal_name = BLOCK_DEVICE_ADDED;
454                 break;
455         case BLOCK_DEV_REMOVE:
456                 flags = 0;
457                 signal_name = BLOCK_DEVICE_REMOVED;
458                 break;
459         default:
460                 /* unknown op */
461                 _E("Failed to broadcast device changed signal. op(%d)", op);
462                 return;
463         }
464
465         /* Broadcast outside with BlockManager iface */
466         param = block_data_to_gvariant(data, flags);
467
468         ret_dbus = gdbus_signal_emit(NULL,
469                                 STORAGED_PATH_BLOCK_MANAGER,
470                                 STORAGED_INTERFACE_BLOCK_MANAGER,
471                                 signal_name,
472                                 param);
473         if (ret_dbus < 0)
474                 _E("Failed to broadcast device changed signal. op(%d)", op);
475 }
476
477 static int get_mmc_mount_node(char *devnode, char *node, size_t len)
478 {
479         char *name = devnode;
480         int dev = -1, part = -1;
481         char emul[32] = { 0, };
482         int i;
483
484         if (!name)
485                 return -EINVAL;
486
487         /* Check Target */
488         sscanf(name, "mmcblk%dp%d", &dev, &part);
489         if (dev >= 0) {
490                 if (part < 0)
491                         snprintf(node, len, "%s%c", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1);
492                 else
493                         snprintf(node, len, "%s%c%d", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1, part);
494                 return 0;
495         }
496
497         /* Check Emulator */
498         sscanf(name, "vd%31s", emul);
499         if (emul[0] == '\0')
500                 return -EINVAL;
501         for (i = 0 ; i < strlen(emul) ; i++)
502                 emul[i] = toupper(emul[i]);
503         snprintf(node, len, "%s%s", BLOCK_MMC_NODE_PREFIX, emul);
504         return 0;
505 }
506
507 static int get_scsi_mount_node(char *devnode, char *node, size_t len)
508 {
509         char dev[64], *name;
510         int i;
511
512         if (!devnode)
513                 return -EINVAL;
514
515         snprintf(dev, sizeof(dev), "%s", devnode);
516
517         if (!strstr(dev, "sd"))
518                 return -EINVAL;
519
520         name = dev;
521         name += strlen("sd");
522
523         for (i = 0 ; i < strlen(name) ; i++)
524                 name[i] = toupper(name[i]);
525         snprintf(node, len, "%s%s", BLOCK_SCSI_NODE_PREFIX, name);
526
527         return 0;
528 }
529
530 static char *generate_mount_path(struct block_data *data)
531 {
532         const char *str;
533         char *name, node[64];
534         int ret_val;
535
536         if (!data || !data->devnode || !data->fs_usage || (strcmp(data->fs_usage, FILESYSTEM_NAME) && strncmp(data->fs_usage, "crypto", strlen("crypto"))))
537                 return NULL;
538
539         name = strrchr(data->devnode, '/');
540         if (!name)
541                 goto out;
542         name++;
543
544         switch (data->block_type) {
545         case BLOCK_MMC_DEV:
546                 ret_val = get_mmc_mount_node(name, node, sizeof(node));
547                 break;
548         case BLOCK_SCSI_DEV:
549                 ret_val = get_scsi_mount_node(name, node, sizeof(node));
550                 break;
551         case BLOCK_EXTENDEDSD_DEV:
552                 return strdup(EXTENDEDSD_MOUNT_PATH);
553         default:
554                 _E("Invalid block type(%d).", data->block_type);
555                 return NULL;
556         }
557         if (ret_val < 0)
558                 goto out;
559
560         str = tzplatform_mkpath(TZ_SYS_MEDIA, node);
561         if (!str)
562                 return NULL;
563         return strdup(str);
564
565 out:
566         _E("Invalid devnode(%s).", data->devnode ? data->devnode : "NULL");
567         return NULL;
568 }
569
570 static bool check_primary_partition(const char *devnode)
571 {
572         struct block_fs_ops *fs;
573         blkid_probe probe;
574         GList *elem;
575         const char *filesystem = NULL;
576         char *temp;
577         char str[PATH_MAX];
578         char str2[PATH_MAX];
579         size_t fs_len;
580         int len;
581         int ret_val;
582         int i;
583         bool found = false;
584
585         if (fnmatch(MMC_LINK_PATH, devnode, 0) &&
586                 fnmatch(MMC_PATH, devnode, 0) &&
587                 fnmatch(SCSI_PATH, devnode, 0) &&
588                 fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
589                 return false;
590
591         temp = strrchr(devnode, '/');
592         if (!temp)
593                 return false;
594         if (fnmatch("/"SCSI_PARTITION_PATH, temp, 0) &&
595                 fnmatch("/"MMC_PARTITION_PATH, temp, 0))
596                 return true;
597
598         /* Emulator support only one partition */
599         if (is_emulator())
600                 return true;
601
602         snprintf(str, sizeof(str), "%s", devnode);
603
604         len = strlen(str);
605         str[len - 1] = '\0';
606
607         for (i = 1; i <= 9; ++i) {
608                 if ((ret_val = snprintf(str2, sizeof(str2), "%s%d", str, i)) > sizeof(str2) - 1) {
609                         _E("Filename is longer than buffer. Need %d size of buffer.", ret_val + 1);
610                         continue;
611                 }
612
613                 if (access(str2, R_OK) != 0)
614                         continue;
615
616                 probe = blkid_new_probe_from_filename(str2);
617                 if (!probe)
618                         continue;
619                 if (blkid_do_probe(probe) != 0)
620                         continue;
621
622                 ret_val = blkid_probe_lookup_value(probe, "TYPE", &filesystem, &fs_len);
623                 if (ret_val < 0) {
624                         blkid_free_probe(probe);
625                         continue;
626                 }
627                 SYS_G_LIST_FOREACH(fs_head, elem, fs) {
628                         if (!strncmp(fs->name, filesystem, fs_len)) {
629                                 found = true;
630                                 break;
631                         }
632                 }
633                 blkid_free_probe(probe);
634                 if (!found)
635                         continue;
636                 break;
637         }
638
639         if (found && !strncmp(devnode, str2, strlen(str2) + 1))
640                 return true;
641
642         return false;
643 }
644
645 /* Whole data in struct block_data should be freed. */
646 static struct block_data *make_block_data(const char *devnode,
647                 const char *syspath,
648                 const char *fs_usage,
649                 const char *fs_type,
650                 const char *fs_version,
651                 const char *fs_uuid_enc,
652                 const char *readonly)
653 {
654         struct block_data *data;
655
656         /* devnode is unique value so it should exist. */
657         if (!devnode)
658                 return NULL;
659
660         if (!fs_type)
661                 _I("Unknown fs type.");
662
663         data = calloc(1, sizeof(struct block_data));
664         if (!data) {
665                 _E("Failed to calloc().");
666                 return NULL;
667         }
668
669         data->devnode = strdup(devnode);
670         if (syspath)
671                 data->syspath = strdup(syspath);
672         if (fs_usage)
673                 data->fs_usage = strdup(fs_usage);
674         if (fs_type)
675                 data->fs_type = strdup(fs_type);
676         if (fs_version)
677                 data->fs_version = strdup(fs_version);
678         if (fs_uuid_enc)
679                 data->fs_uuid_enc = strdup(fs_uuid_enc);
680         if (readonly)
681                 data->readonly = atoi(readonly);
682         data->primary = check_primary_partition(devnode);
683
684         /* TODO should we know block dev type? */
685         if (!fnmatch(MMC_LINK_PATH, devnode, 0))
686                 data->block_type = BLOCK_MMC_DEV;
687         else if (!fnmatch(MMC_PATH, devnode, 0))
688                 data->block_type = BLOCK_MMC_DEV;
689         else if (!fnmatch(SCSI_PATH, devnode, 0))
690                 data->block_type = BLOCK_SCSI_DEV;
691         else if (!fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
692                 data->block_type = BLOCK_EXTENDEDSD_DEV;
693         else
694                 data->block_type = -1;
695
696         data->mount_point = generate_mount_path(data);
697         BLOCK_FLAG_CLEAR_ALL(data);
698
699         /* for 2.4 backward compatibility */
700         // What if storage id 1 is existed? (multi sdcard case)
701         if (data->primary == true && data->block_type == BLOCK_MMC_DEV &&
702             data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME))
703                 data->id = EXT_PRIMARY_SD_FIXID;
704         else
705                 data->id = block_get_new_id();
706
707         return data;
708 }
709
710 static void free_block_data(struct block_data *data)
711 {
712         if (!data)
713                 return;
714         free(data->devnode);
715         free(data->syspath);
716         free(data->fs_usage);
717         free(data->fs_type);
718         free(data->fs_version);
719         free(data->fs_uuid_enc);
720         free(data->mount_point);
721         free(data);
722 }
723
724 static int update_block_data(struct block_data *data,
725                 const char *fs_usage,
726                 const char *fs_type,
727                 const char *fs_version,
728                 const char *fs_uuid_enc,
729                 const char *readonly,
730                 bool mount_point_updated)
731 {
732         if (!data)
733                 return -EINVAL;
734
735         free(data->fs_usage);
736         data->fs_usage = NULL;
737         if (fs_usage)
738                 data->fs_usage = strdup(fs_usage);
739
740         free(data->fs_type);
741         data->fs_type = NULL;
742         if (fs_type)
743                 data->fs_type = strdup(fs_type);
744
745         free(data->fs_version);
746         data->fs_version = NULL;
747         if (fs_version)
748                 data->fs_version = strdup(fs_version);
749
750         free(data->fs_uuid_enc);
751         data->fs_uuid_enc = NULL;
752         if (fs_uuid_enc)
753                 data->fs_uuid_enc = strdup(fs_uuid_enc);
754
755         /* generate_mount_path function should be invoked
756          * after fs_uuid_enc is updated */
757         if (!mount_point_updated) {
758                 free(data->mount_point);
759                 data->mount_point = generate_mount_path(data);
760         }
761
762         data->readonly = false;
763         if (readonly)
764                 data->readonly = atoi(readonly);
765
766         BLOCK_FLAG_MOUNT_CLEAR(data);
767
768         return 0;
769 }
770
771 static struct block_device *make_block_device(struct block_data *data)
772 {
773         struct block_device *bdev;
774
775         if (!data)
776                 return NULL;
777
778         bdev = calloc(1, sizeof(struct block_device));
779         if (!bdev)
780                 return NULL;
781
782         bdev->data = data;
783         bdev->thread_id = -1;
784         bdev->removed = false;
785         bdev->on_private_op = REQ_NORMAL;
786         bdev->private_pid = 0;
787         bdev->mount_point_updated = false;
788
789         return bdev;
790 }
791
792 // Called by MainThread - Remove DevNode
793 static void free_block_device(struct block_device *bdev)
794 {
795         GList *l, *next;
796         struct operation_queue *op;
797         int thread_id;
798
799         if (!bdev)
800                 return;
801
802         thread_id = bdev->thread_id;
803         if (thread_id < 0 || thread_id >= THREAD_MAX)
804                 return;
805
806         pthread_mutex_lock(&(th_manager[thread_id].mutex));
807
808         th_manager[thread_id].num_dev--;
809         SYS_G_LIST_REMOVE(th_manager[thread_id].block_dev_list, bdev);
810         free_block_data(bdev->data);
811
812         SYS_G_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
813                 if (!op->done)
814                         th_manager[thread_id].op_len--;
815                 SYS_G_LIST_REMOVE(bdev->op_queue, op);
816                 free(op);
817         }
818         pthread_mutex_unlock(&(th_manager[thread_id].mutex));
819
820         free(bdev);
821 }
822
823 // Called By MainThread - Remove Device
824 static struct block_device *find_block_device(const char *devnode)
825 {
826         struct block_device *bdev;
827         GList *elem;
828         int len;
829         int i;
830
831         len = strlen(devnode) + 1;
832         for (i = 0; i < THREAD_MAX; i++) {
833                 pthread_mutex_lock(&(th_manager[i].mutex));
834                 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
835                         if (bdev->data && !bdev->removed &&
836                             !strncmp(bdev->data->devnode, devnode, len)) {
837                                 pthread_mutex_unlock(&(th_manager[i].mutex));
838                                 return bdev;
839                         }
840                 }
841                 pthread_mutex_unlock(&(th_manager[i].mutex));
842         }
843
844         return NULL;
845 }
846
847 // Called By MainThread - Remove Device
848 static struct block_device *find_block_device_path(const char *mount_point)
849 {
850         struct block_device *bdev;
851         GList *elem;
852         int len;
853         int i;
854
855         len = strlen(mount_point) + 1;
856         for (i = 0; i < THREAD_MAX; i++) {
857                 pthread_mutex_lock(&(th_manager[i].mutex));
858                 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
859                         if (bdev->data && !bdev->removed &&
860                            (bdev->data->mount_point != NULL && !strncmp(bdev->data->mount_point, mount_point, len))) {
861                                 pthread_mutex_unlock(&(th_manager[i].mutex));
862                                 return bdev;
863                         }
864                 }
865                 pthread_mutex_unlock(&(th_manager[i].mutex));
866         }
867
868         return NULL;
869 }
870
871 // Called By MainThread - Mount,Unmount,Format,GetInfo
872 static struct block_device *find_block_device_by_id(int id)
873 {
874         struct block_device *bdev;
875         GList *elem;
876         int i;
877
878         for (i = 0; i < THREAD_MAX; i++) {
879                 pthread_mutex_lock(&(th_manager[i].mutex));
880                 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
881                         if (!bdev->data)
882                                 continue;
883                         if (bdev->removed)
884                                 continue;
885                         if (bdev->data->id == id) {
886                                 pthread_mutex_unlock(&(th_manager[i].mutex));
887                                 return bdev;
888                         }
889                 }
890                 pthread_mutex_unlock(&(th_manager[i].mutex));
891         }
892
893         return NULL;
894 }
895
896 static const char *get_operation_char(enum block_dev_operation op)
897 {
898         switch (op) {
899         case BLOCK_DEV_MOUNT:
900                 return "MOUNT";
901
902         case BLOCK_DEV_UNMOUNT:
903                 return "UNMOUNT";
904
905         case BLOCK_DEV_FORMAT:
906                 return "FORMAT";
907
908         case BLOCK_DEV_INSERT:
909                 return "INSERT";
910
911         case BLOCK_DEV_REMOVE:
912                 return "REMOVE";
913
914         case BLOCK_LUKS_CLOSE:
915                 return "LUKS CLOSE";
916         }
917
918         _E("Invalid operation(%d).", op);
919         return "unknown";
920 }
921
922 void mmc_make_default_path(const char *mount_path)
923 {
924         int i = 0;
925         int ret_val = 0;
926         char mmc_path[FILE_NAME_LEN_MAX + 1] = {0, };
927
928         for (i = 0; i < DIR_NUM; ++i) {
929                 if ((ret_val = snprintf(mmc_path, sizeof(mmc_path), "%s/%s", mount_path, mmc_default_path[i])) > sizeof(mmc_path) - 1) {
930                         _E("Path is longer than buffer. Need %d size of buffer.", ret_val + 1);
931                         continue;
932                 }
933
934                 if (!g_file_test(mmc_path, G_FILE_TEST_IS_DIR)) {
935                         _D("Path(%s) did not exist.", mmc_path);
936                         ret_val = mkdir(mmc_path, 0777);
937                         if (ret_val != 0)
938                                 _E("Failed to mkdir: %d", errno);
939
940                         /*this fuction for emulator*/
941                         /*at the first time, the directroies are made permission 755*/
942                         ret_val = chmod(mmc_path, 0777);
943                         if (ret_val != 0)
944                                 _E("Failed to chmod: %d", errno);
945
946                         ret_val = chown(mmc_path, 0, 10001);
947                         if (ret_val != 0)
948                                 _E("Failed to chown: %d", errno);
949                 }
950         }
951 }
952
953 static void create_external_apps_directory(void)
954 {
955         int ret_dbus;
956
957         ret_dbus = gdbus_call_async(PKGDIR_BUS_NAME, PKGDIR_PATH,
958                         PKGDIR_INTERFACE, "CreateExternalDirsForAllPkgs", NULL);
959         if (ret_dbus)
960                 _E("Failed to create external directory.");
961 }
962
963 static int pipe_trigger(enum block_dev_operation op,
964                 struct block_device *bdev, int result)
965 {
966         struct pipe_data pdata = { op, bdev, result };
967         int n;
968
969         _D("op=%s bdev=%p result=%d",
970                         get_operation_char(pdata.op),
971                         pdata.bdev, pdata.result);
972
973         // Multi thread should not write at the same time
974         pthread_mutex_lock(&pipe_mutex);
975         n = write(pfds[1], &pdata, sizeof(struct pipe_data));
976         pthread_mutex_unlock(&pipe_mutex);
977
978         return (n != sizeof(struct pipe_data)) ? -EPERM : 0;
979 }
980
981 static bool pipe_cb(int fd, void *data)
982 {
983         struct pipe_data pdata = {0,};
984         int n;
985         int thread_id;
986         int ret_val;
987
988         n = read(fd, &pdata, sizeof(pdata));
989         if (n != sizeof(pdata) || !pdata.bdev) {
990                 _E("Failed to read struct pipe data.");
991                 goto out;
992         }
993
994         _I("op=%s bdev=%p result=%d",
995                         get_operation_char(pdata.op),
996                         pdata.bdev, pdata.result);
997
998         if (pdata.op == BLOCK_LUKS_CLOSE)
999                 goto out;
1000
1001         if (pdata.op == BLOCK_DEV_MOUNT && pdata.result < 0) {
1002                 if (pdata.bdev->data->state == BLOCK_UNMOUNT) {
1003                         ret_val = change_mount_point(pdata.bdev, "");
1004                         /* Modify /run/external-storage/id file */
1005                         if (ret_val == 0) {
1006                                 if (pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV)
1007                                         create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, true);
1008                                 else
1009                                         create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, false);
1010                         }
1011                 }
1012                 goto out;
1013         }
1014
1015         if (pdata.op == BLOCK_DEV_MOUNT && (pdata.result == 0)) {
1016                 /* Create file for block device /run/external-storage/id */
1017                 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
1018         }
1019
1020         if (pdata.op == BLOCK_DEV_MOUNT &&
1021                 pdata.bdev->data->state == BLOCK_MOUNT &&
1022                 pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
1023                 pdata.bdev->data->primary) {
1024                 create_external_apps_directory();
1025                 mmc_make_default_path(pdata.bdev->data->mount_point);
1026
1027                 ret_val = gdbus_call_sync_with_reply_int(POPUP_BUS_NAME,
1028                         POPUP_PATH_NOTI,
1029                         POPUP_INTERFACE_NOTI,
1030                         MMC_POPUP_NOTI,
1031                         g_variant_new("(s)", MMC_INSERTED),
1032                         NULL);
1033                 if (ret_val != 0)
1034                         _E("Failed to popup: %d", ret_val);
1035         }
1036
1037         if (pdata.op == BLOCK_DEV_UNMOUNT) {
1038                 /* Remove file for block device /run/xxxxxx/id */
1039                 remove_file(pdata.bdev->data->id, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
1040
1041                 if (pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
1042                         pdata.bdev->data->primary &&
1043                         BLOCK_IS_FLAG_SET(pdata.bdev->data, UNMOUNT_UNSAFE)) {
1044
1045                         ret_val = gdbus_call_sync_with_reply_int(POPUP_BUS_NAME,
1046                                 POPUP_PATH_NOTI,
1047                                 POPUP_INTERFACE_NOTI,
1048                                 MMC_POPUP_NOTI,
1049                                 g_variant_new("(s)", MMC_REMOVED),
1050                                 NULL);
1051                         if (ret_val != 0)
1052                                 _E("Failed to popup: %d", ret_val);
1053                 }
1054         }
1055
1056         /* Broadcast to mmc and usb storage module */
1057         broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
1058
1059         /* Broadcast outside with Block iface */
1060         if (pdata.bdev->on_private_op == REQ_NORMAL)
1061                 broadcast_device_changed(pdata.bdev, pdata.op);
1062         else if (pdata.bdev->on_private_op == REQ_PRIVATE) {
1063                 if (pdata.op == BLOCK_DEV_UNMOUNT) {
1064                         pdata.bdev->on_private_op = REQ_NORMAL;
1065                         _D("Private operation state(%d).", pdata.bdev->on_private_op);
1066                 }
1067         } else {
1068                 if (pdata.op == BLOCK_DEV_MOUNT) {
1069                         pdata.bdev->on_private_op = REQ_PRIVATE;
1070                         _D("Private operation state(%d).", pdata.bdev->on_private_op);
1071                 }
1072         }
1073
1074         if (pdata.op == BLOCK_DEV_REMOVE) {
1075                 thread_id = pdata.bdev->thread_id;
1076                 if (thread_id < 0 || thread_id >= THREAD_MAX)
1077                         return true;
1078                 free_block_device(pdata.bdev);
1079         }
1080
1081 out:
1082         return true;
1083 }
1084
1085 static int pipe_init(void)
1086 {
1087         int ret_val;
1088
1089         ret_val = pipe2(pfds, O_CLOEXEC);
1090         if (ret_val == -1)
1091                 return -errno;
1092
1093         ret_val = add_fd_read_handler(pfds[0], pipe_cb,
1094                         NULL, NULL, &phandler);
1095         if (ret_val < 0) {
1096                 _E("Failed to add pipe handler: %d", ret_val);
1097                 return ret_val;
1098         }
1099
1100         return 0;
1101 }
1102
1103 static void pipe_exit(void)
1104 {
1105         if (phandler) {
1106                 remove_fd_read_handler(&phandler);
1107                 phandler = NULL;
1108         }
1109
1110         if (pfds[0])
1111                 close(pfds[0]);
1112         if (pfds[1])
1113                 close(pfds[1]);
1114 }
1115
1116 static int mmc_check_and_unmount(const char *path)
1117 {
1118         int ret = 0;
1119         int retry = 0;
1120
1121         if (!path)
1122                 return 0;
1123
1124         while (mount_check(path)) {
1125                 ret = umount(path);
1126                 if (ret < 0) {
1127                         retry++;
1128                         if (retry > UNMOUNT_RETRY)
1129                                 return -errno;
1130                 }
1131         }
1132         return ret;
1133 }
1134
1135 static bool check_rw_mount(const char *szPath)
1136 {
1137         struct statvfs mount_stat;
1138
1139         if (!statvfs(szPath, &mount_stat)) {
1140                 if ((mount_stat.f_flag & ST_RDONLY) == ST_RDONLY)
1141                         return false;
1142         }
1143         return true;
1144 }
1145
1146 static int retrieve_udev_device(struct block_data *data, bool mount_point_updated)
1147 {
1148         struct udev *udev;
1149         struct udev_device *dev;
1150         const char *fs_type;
1151         const char *fs_usage;
1152         int r;
1153         int wait;
1154
1155         if (!data)
1156                 return -EINVAL;
1157
1158         for (wait = 0; wait < 10; wait++) {
1159                 udev = udev_new();
1160                 if (!udev) {
1161                         _E("Failed to create udev library context.");
1162                         return -EPERM;
1163                 }
1164
1165                 dev = udev_device_new_from_syspath(udev, data->syspath);
1166                 if (!dev) {
1167                         _E("Failed to create new udev device.");
1168                         udev_unref(udev);
1169                         return -EPERM;
1170                 }
1171
1172                 fs_type = udev_device_get_property_value(dev, "ID_FS_TYPE");
1173                 fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE");
1174                 /* fs_usage for crpto_LUKS is crypto */
1175                 if (!fs_type || (strncmp(fs_type, VFAT_NAME, strlen(VFAT_NAME)) && strncmp(fs_type, EXT4_NAME, strlen(EXT4_NAME))))
1176                         sleep(1);
1177                 else if (!fs_usage || strncmp(FILESYSTEM_NAME, fs_usage, strlen(FILESYSTEM_NAME)))
1178                         sleep(1);
1179                 else
1180                         break;
1181
1182                 udev_device_unref(dev);
1183                 udev_unref(udev);
1184         }
1185
1186         r = update_block_data(data,
1187                         udev_device_get_property_value(dev, "ID_FS_USAGE"),
1188                         udev_device_get_property_value(dev, "ID_FS_TYPE"),
1189                         udev_device_get_property_value(dev, "ID_FS_VERSION"),
1190                         udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
1191                         udev_device_get_sysattr_value(dev, "ro"),
1192                         mount_point_updated);
1193         if (r < 0)
1194                 _E("Failed to update block data for %s.", data->devnode);
1195
1196         udev_device_unref(dev);
1197         udev_unref(udev);
1198         return r;
1199 }
1200
1201 static int block_mount(struct block_data *data)
1202 {
1203         struct block_fs_ops *fs;
1204         GList *elem;
1205         int r;
1206         int len;
1207
1208         if (!data || !data->devnode || !data->mount_point)
1209                 return -EINVAL;
1210
1211         /* check existing mounted */
1212         if (mount_check(data->mount_point))
1213                 return -EEXIST;
1214
1215         /* create mount point */
1216         if (access(data->mount_point, R_OK) != 0) {
1217                 if (mkdir(data->mount_point, 0755) < 0)
1218                         return -errno;
1219         }
1220
1221         /* check matched file system */
1222         if (!data->fs_usage ||
1223             strncmp(data->fs_usage, FILESYSTEM_NAME,
1224                     sizeof(FILESYSTEM_NAME)) != 0) {
1225                 r = -ENODEV;
1226                 goto out;
1227         }
1228
1229         if (!data->fs_type) {
1230                 _E("There is no file system.");
1231                 BLOCK_FLAG_SET(data, FS_EMPTY);
1232                 r = -ENODATA;
1233                 goto out;
1234         }
1235
1236         fs = NULL;
1237         len = strlen(data->fs_type) + 1;
1238         SYS_G_LIST_FOREACH(fs_head, elem, fs) {
1239                 if (!strncmp(fs->name, data->fs_type, len))
1240                         break;
1241         }
1242
1243         if (!fs) {
1244                 _E("Not supported file system(%s).", data->fs_type);
1245                 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1246                 r = -ENOTSUP;
1247                 goto out;
1248         }
1249
1250         if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1251                 r = fs->mount(false, data->devnode, data->mount_point);
1252         else
1253                 r = fs->mount(smack, data->devnode, data->mount_point);
1254
1255         if (r == -EIO)
1256                 BLOCK_FLAG_SET(data, FS_BROKEN);
1257
1258         if (r < 0)
1259                 goto out;
1260
1261         r = check_rw_mount(data->mount_point);
1262         if (!r)
1263                 return -EROFS;
1264
1265         return 0;
1266
1267 out:
1268         rmdir(data->mount_point);
1269         return r;
1270 }
1271
1272 static int mount_start(struct block_device *bdev)
1273 {
1274         struct block_data *data;
1275         int ret_val;
1276         int r;
1277
1278         assert(bdev);
1279         assert(bdev->data);
1280
1281         data = bdev->data;
1282         _I("Mount Start (%s -> %s).",
1283                         data->devnode, data->mount_point);
1284
1285         /* mount operation */
1286         r = block_mount(data);
1287         if (r != -EROFS && r < 0) {
1288                 _E("Failed to mount device(%s): %d", data->devnode, r);
1289                 goto out;
1290         }
1291
1292         if (r == -EROFS) {
1293                 data->readonly = true;
1294                 BLOCK_FLAG_SET(data, MOUNT_READONLY);
1295         }
1296
1297         data->state = BLOCK_MOUNT;
1298
1299         if (data->block_type == BLOCK_MMC_DEV) {
1300                 /* app2ext_migrate_legacy_all has dbus method call to deviced */
1301                 ret_val = app2ext_migrate_legacy_all();
1302                 if (ret_val < 0)
1303                         _E("Failed to app2ext.");
1304         }
1305
1306 out:
1307         if (r < 0 && r != -EROFS)
1308                 data->state = BLOCK_UNMOUNT;
1309
1310         _I("%s result=%s: %d", __func__, data->devnode, r);
1311
1312         if (pipe_trigger(BLOCK_DEV_MOUNT, bdev, r) < 0)
1313                 _E("Failed to trigger pipe.");
1314
1315         return r;
1316 }
1317
1318 static int change_mount_point(struct block_device *bdev,
1319                 const char *mount_point)
1320 {
1321         struct block_data *data;
1322
1323         if (!bdev)
1324                 return -EINVAL;
1325
1326         data = bdev->data;
1327         free(data->mount_point);
1328
1329         /* If the mount path already exists, the path cannot be used */
1330         if (mount_point &&
1331                 access(mount_point, F_OK) != 0) {
1332                 data->mount_point = strdup(mount_point);
1333                 bdev->mount_point_updated = true;
1334         } else {
1335                 data->mount_point = generate_mount_path(data);
1336                 bdev->mount_point_updated = false;
1337         }
1338
1339         return 0;
1340 }
1341
1342 static int mount_block_device(struct block_device *bdev)
1343 {
1344         struct block_data *data;
1345         int r;
1346
1347         if (!bdev || !bdev->data)
1348                 return -EINVAL;
1349
1350         data = bdev->data;
1351         if (data->state == BLOCK_MOUNT) {
1352                 _I("%s is already mounted.", data->devnode);
1353                 return 0;
1354         }
1355
1356         if (!block_conf[data->block_type].multimount &&
1357             !data->primary) {
1358                 _I("Not support multi mount by config info.");
1359                 return 0;
1360         }
1361
1362         r = mount_start(bdev);
1363         if (r < 0) {
1364                 _E("Failed to mount %s.", data->devnode);
1365                 return r;
1366         }
1367
1368         return 0;
1369 }
1370
1371 static int block_unmount(struct block_device *bdev,
1372                 enum unmount_operation option)
1373 {
1374         struct block_data *data;
1375         int r, retry = 0;
1376
1377         if (!bdev || !bdev->data || !bdev->data->mount_point)
1378                 return -EINVAL;
1379
1380         data = bdev->data;
1381
1382         if (bdev->on_private_op == REQ_NORMAL)
1383                 broadcast_device_blocked(bdev);
1384
1385         /* it must called before unmounting mmc */
1386         r = mmc_check_and_unmount(data->mount_point);
1387         if (!r)
1388                 goto out;
1389         if (option == UNMOUNT_NORMAL) {
1390                 _I("Failed to unmount with normal option: %d", r);
1391                 return r;
1392         }
1393
1394         _I("Execute force unmount.");
1395         /* Force Unmount Scenario */
1396
1397         /* Mobile specific:
1398          * should unmount the below vconf key. */
1399         if ((data->block_type == BLOCK_MMC_DEV ||
1400                 data->block_type == BLOCK_EXTENDEDSD_DEV) &&
1401                 data->primary) {
1402                 /* At first, notify to other app who already access sdcard */
1403                 _I("Notify to other app who already access sdcard.");
1404                 vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS,
1405                                 VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
1406
1407                 /* Wait for 700 msec to release open files */
1408                 usleep(700 * 1000);
1409         }
1410
1411         sync();
1412
1413         if (umount2(data->mount_point, MNT_DETACH) != 0) {
1414                 _I("Failed to unmount with lazy option: %m");
1415                 return -errno;
1416         }
1417
1418         while (retry++ < UNMOUNT_RETRY) {
1419                 _I("Kill app with SIGTERM.");
1420                 terminate_process(data->devnode, false);
1421                 usleep(500 * 1000);
1422
1423                 if (!is_in_use_partition(data->devnode))
1424                         break;
1425
1426                 _I("Kill app with SIGKILL.");
1427                 terminate_process(data->devnode, true);
1428                 usleep(500 * 1000);
1429
1430                 if (!is_in_use_partition(data->devnode))
1431                         break;
1432         }
1433
1434         sync();
1435
1436 out:
1437         data->state = BLOCK_UNMOUNT;
1438
1439         if (rmdir(data->mount_point) < 0)
1440                 _E("Failed to remove '%s' directory.", data->mount_point);
1441
1442         return r;
1443 }
1444
1445 static int unmount_block_device(struct block_device *bdev,
1446                 enum unmount_operation option)
1447 {
1448         struct block_data *data;
1449         int r;
1450
1451         if (!bdev || !bdev->data)
1452                 return -EINVAL;
1453
1454         data = bdev->data;
1455         if (data->state == BLOCK_UNMOUNT) {
1456                 _I("%s is already unmounted.", data->devnode);
1457                 r = mmc_check_and_unmount(data->mount_point);
1458                 if (r < 0)
1459                         _E("The path was existed, but could not delete it(%s).",
1460                                         data->mount_point);
1461                 return 0;
1462         }
1463
1464         _I("Unmount Start. '%s' -> '%s'.",
1465                         data->devnode, data->mount_point);
1466
1467         r = block_unmount(bdev, option);
1468         if (r < 0) {
1469                 _E("Failed to unmount %s device: %d", data->devnode, r);
1470                 goto out;
1471         }
1472
1473         BLOCK_FLAG_MOUNT_CLEAR(data);
1474
1475 out:
1476         _I("%s result=%s: %d", __func__, data->devnode, r);
1477
1478         if (pipe_trigger(BLOCK_DEV_UNMOUNT, bdev, r) < 0)
1479                 _E("Failed to trigger pipe.");
1480
1481         return r;
1482 }
1483
1484 static int block_format(struct block_data *data,
1485                 const char *fs_type, bool mount_point_updated)
1486 {
1487         const struct block_fs_ops *fs;
1488         GList *elem;
1489         const char *fstype;
1490         int len;
1491         int r;
1492
1493         if (!data || !data->devnode || !data->mount_point)
1494                 return -EINVAL;
1495
1496         if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1497                 fstype = EXT4_NAME;
1498         else {
1499                 if (!fs_type) {
1500                         if (!data->fs_type)
1501                                 return -ENOTSUP;
1502                         fstype = data->fs_type;
1503                 } else
1504                         fstype = fs_type;
1505         }
1506         if (!strcmp(fstype, EXFAT_NAME))
1507                 fstype = VFAT_NAME;
1508
1509         fs = NULL;
1510         len = strlen(fstype);
1511         SYS_G_LIST_FOREACH(fs_head, elem, fs) {
1512                 if (!strncmp(fs->name, fstype, len))
1513                         break;
1514         }
1515
1516         if (!fs || !fs->format) {
1517                 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1518                 _E("Not supported file system(%s).", fstype);
1519                 return -ENOTSUP;
1520         }
1521
1522         _I("Format path=%s", data->devnode);
1523         r = fs->format(data->devnode);
1524         if (r < 0) {
1525                 _E("Failed to format block data for %s.", data->devnode);
1526                 goto out;
1527         }
1528
1529         /* need to update the partition data.
1530          * It can be changed in doing format. */
1531         retrieve_udev_device(data, mount_point_updated);
1532 out:
1533         return r;
1534 }
1535
1536 static int format_block_device(struct block_device *bdev,
1537                 const char *fs_type,
1538                 enum unmount_operation option)
1539 {
1540         struct block_data *data;
1541         int r;
1542
1543         assert(bdev);
1544         assert(bdev->data);
1545
1546         data = bdev->data;
1547
1548         _I("Format Start. '%s' -> '%s'.",
1549                         data->devnode, data->mount_point);
1550
1551         if (data->state == BLOCK_MOUNT) {
1552                 r = block_unmount(bdev, option);
1553                 if (r < 0) {
1554                         _E("Failed to unmount %s device: %d", data->devnode, r);
1555                         goto out;
1556                 }
1557         }
1558
1559         r = block_format(data, fs_type, bdev->mount_point_updated);
1560         if (r < 0)
1561                 _E("Failed to format %s device: %d", data->devnode, r);
1562
1563 out:
1564         _I("%s result=%s: %d", __func__, data->devnode, r);
1565
1566         r = pipe_trigger(BLOCK_DEV_FORMAT, bdev, r);
1567         if (r < 0)
1568                 _E("Failed to trigger pipe.");
1569
1570         return r;
1571 }
1572
1573 static struct format_data *get_format_data(
1574                 const char *fs_type, enum unmount_operation option)
1575 {
1576         struct format_data *fdata;
1577
1578         fdata = (struct format_data *)malloc(sizeof(struct format_data));
1579         if (!fdata) {
1580                 _E("Failed to allocate format data.");
1581                 return NULL;
1582         }
1583
1584         if (fs_type)
1585                 fdata->fs_type = strdup(fs_type);
1586         else
1587                 fdata->fs_type = NULL;
1588         fdata->option = option;
1589
1590         return fdata;
1591 }
1592
1593 static void release_format_data(struct format_data *data)
1594 {
1595         if (data) {
1596                 if (data->fs_type)
1597                         free(data->fs_type);
1598                 free(data);
1599         }
1600 }
1601
1602 // Called by BlockThread - Real Mount Op
1603 static int block_mount_device(struct block_device *bdev, void *data)
1604 {
1605         GList *l;
1606         int ret;
1607         int thread_id;
1608
1609         if (!bdev)
1610                 return -EINVAL;
1611
1612         thread_id = bdev->thread_id;
1613         if (thread_id < 0 || thread_id >= THREAD_MAX)
1614                 return -EINVAL;
1615         pthread_mutex_lock(&(th_manager[thread_id].mutex));
1616         l = SYS_G_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1617         pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1618         if (!l) {
1619                 _E("'%s' does not exist in the device list.", bdev->data->devnode);
1620                 return -ENOENT;
1621         }
1622
1623         /* mount automatically */
1624         ret = mount_block_device(bdev);
1625         if (ret < 0)
1626                 _E("Failed to mount block device for %s.", bdev->data->devnode);
1627
1628         return ret;
1629 }
1630
1631 // Called by BlockThread - Real Format Op
1632 static int block_format_device(struct block_device *bdev, void *data)
1633 {
1634         GList *l;
1635         int ret;
1636         int thread_id;
1637         struct format_data *fdata = (struct format_data *)data;
1638
1639         if (!bdev || !fdata) {
1640                 ret = -EINVAL;
1641                 goto out;
1642         }
1643
1644         thread_id = bdev->thread_id;
1645         if (thread_id < 0 || thread_id >= THREAD_MAX)
1646                 return -EINVAL;
1647         pthread_mutex_lock(&(th_manager[thread_id].mutex));
1648         l = SYS_G_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1649         pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1650         if (!l) {
1651                 _E("'%s' does not exist in the device list.", bdev->data->devnode);
1652                 ret = -ENOENT;
1653                 goto out;
1654         }
1655
1656         ret = format_block_device(bdev, fdata->fs_type, fdata->option);
1657         if (ret < 0)
1658                 _E("Failed to format block device for %s.", bdev->data->devnode);
1659
1660 out:
1661         release_format_data(fdata);
1662
1663         return ret;
1664 }
1665
1666 // Called by BlockThread - Real Unmount Op
1667 static int block_unmount_device(struct block_device *bdev, void *data)
1668 {
1669         int ret;
1670         long option = (long)data;
1671
1672         if (!bdev)
1673                 return -EINVAL;
1674
1675         ret = unmount_block_device(bdev, option);
1676         if (ret < 0) {
1677                 _E("Failed to unmount block device(%s).", bdev->data->devnode);
1678                 return ret;
1679         }
1680
1681         return 0;
1682 }
1683
1684 /* Called by BlockThread - Remove Operation
1685    Direct Call at BlockThread
1686    Previously this function was called by MainThread. However, it will increase complexity.
1687    Need thread lock before to call remove_operation
1688 */
1689 static void remove_operation(struct block_device *bdev)
1690 {
1691         struct operation_queue *op;
1692         GList *l, *next;
1693         int thread_id;
1694
1695         assert(bdev);
1696
1697         thread_id = bdev->thread_id;
1698         if (thread_id < 0 || thread_id >= THREAD_MAX)
1699                 return;
1700
1701         SYS_G_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
1702                 if (op->done) {
1703                         _D("Remove operation(%s, %s).",
1704                                         get_operation_char(op->op),
1705                                         bdev->data->devnode);
1706
1707                         SYS_G_LIST_REMOVE(bdev->op_queue, op);
1708                         free(op);
1709                 }
1710         }
1711 }
1712
1713 // Called by BlockThread
1714 static void check_removed(struct block_device *bdev, GList **queue, struct operation_queue **op)
1715 {
1716         struct operation_queue *temp;
1717         GList *l;
1718         int thread_id;
1719
1720         if (!bdev)
1721                 return;
1722
1723         if (!queue)
1724                 return;
1725
1726         if (!op)
1727                 return;
1728
1729         thread_id = bdev->thread_id;
1730         if (thread_id < 0 || thread_id >= THREAD_MAX)
1731                 return;
1732
1733         pthread_mutex_lock(&(th_manager[thread_id].mutex));
1734
1735         SYS_G_LIST_FOREACH(*queue, l, temp) {
1736                 if (temp->op == BLOCK_DEV_REMOVE) {
1737                         *op = temp;
1738                         break;
1739                 }
1740                 temp->done = true;
1741                 th_manager[thread_id].op_len--;
1742                 block_send_dbus_reply((*op)->invocation, 0);
1743         }
1744
1745         remove_operation(bdev);
1746         pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1747 }
1748
1749 // Called by BlockThread
1750 static bool check_unmount(struct block_device *bdev, GList **queue, struct operation_queue **op)
1751 {
1752         struct operation_queue *temp;
1753         GList *l;
1754         int thread_id;
1755         bool unmounted = false;
1756
1757         if (!bdev)
1758                 return false;
1759
1760         if (!queue)
1761                 return false;
1762
1763         if (!op)
1764                 return false;
1765
1766         thread_id = bdev->thread_id;
1767         if (thread_id < 0 || thread_id >= THREAD_MAX)
1768                 return false;
1769
1770         pthread_mutex_lock(&(th_manager[thread_id].mutex));
1771         SYS_G_LIST_FOREACH(*queue, l, temp) {
1772                 if (temp->op == BLOCK_DEV_UNMOUNT) {
1773                         unmounted = true;
1774                         _D("Operation queue has unmount operation.");
1775                         break;
1776                 }
1777         }
1778         pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1779
1780         if (!unmounted)
1781                 return unmounted;
1782
1783         pthread_mutex_lock(&(th_manager[thread_id].mutex));
1784
1785         SYS_G_LIST_FOREACH(*queue, l, temp) {
1786                 if (temp->op == BLOCK_DEV_UNMOUNT) {
1787                         *op = temp;
1788                         break;
1789                 }
1790                 temp->done = true;
1791                 th_manager[thread_id].op_len--;
1792                 block_send_dbus_reply((*op)->invocation, 0);
1793         }
1794
1795         remove_operation(bdev);
1796         pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1797
1798         return unmounted;
1799 }
1800
1801 // Called by BlockThread
1802 static void trigger_operation(struct block_device *bdev, GList *queue, struct operation_queue *op)
1803 {
1804         int ret_val = 0;
1805         int thread_id;
1806         char devnode[PATH_MAX];
1807         enum block_dev_operation operation;
1808         bool unmounted = false;
1809
1810         assert(bdev);
1811
1812         if (!queue)
1813                 return;
1814
1815         thread_id = bdev->thread_id;
1816         if (thread_id < 0 || thread_id >= THREAD_MAX)
1817                 return;
1818
1819         snprintf(devnode, sizeof(devnode), "%s", bdev->data->devnode);
1820
1821         do {
1822                 if (!op)
1823                         return;
1824                 if (op->done)
1825                         return;
1826
1827                 operation = op->op;
1828
1829                 _D("Thread id(%d) Trigger operation(%s, %s)", thread_id,
1830                         get_operation_char(operation), devnode);
1831
1832                 unmounted = false;
1833                 if (operation == BLOCK_DEV_INSERT && bdev->removed) {
1834                         check_removed(bdev, &queue, &op);
1835                         operation = op->op;
1836                         _D("Trigger operation again(%s, %s).",
1837                                 get_operation_char(operation), devnode);
1838                 }
1839                 if (operation == BLOCK_DEV_MOUNT) {
1840                         unmounted = check_unmount(bdev, &queue, &op);
1841                         if (unmounted) {
1842                                 operation = op->op;
1843                                 _D("Trigger operation again(%s, %s).",
1844                                         get_operation_char(operation), devnode);
1845                         }
1846                 }
1847
1848                 switch (operation) {
1849                 case BLOCK_DEV_INSERT:
1850                         break;
1851                 case BLOCK_DEV_MOUNT:
1852                         ret_val = block_mount_device(bdev, op->data);
1853                         _D("Mount '%s': %d", devnode, ret_val);
1854                         break;
1855                 case BLOCK_DEV_FORMAT:
1856                         ret_val = block_format_device(bdev, op->data);
1857                         _D("Format '%s': %d", devnode, ret_val);
1858                         break;
1859                 case BLOCK_DEV_UNMOUNT:
1860                         ret_val = block_unmount_device(bdev, op->data);
1861                         _D("Unmount '%s': %d", devnode, ret_val);
1862                         break;
1863                 case BLOCK_DEV_REMOVE:
1864                         /* Do nothing */
1865                         break;
1866                 case BLOCK_LUKS_CLOSE:
1867 #ifdef EXTENDED_STORAGE
1868                         ret_val = ode_luks_close_sync(EXTENDEDSD_NAME);
1869                         if (ret_val < 0)
1870                                 _E("Failed on ode_luks_close(%s).", EXTENDEDSD_NAME);
1871 #endif
1872                         break;
1873                 default:
1874                         _E("Operation type(%d) is invalid.", op->op);
1875                         ret_val = -EINVAL;
1876                         break;
1877                 }
1878
1879                 /* LOCK
1880                  * during checking the queue length */
1881                 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1882
1883                 op->done = true;
1884                 th_manager[thread_id].op_len--;
1885
1886                 block_send_dbus_reply(op->invocation, ret_val);
1887
1888                 queue = bdev->op_queue;
1889                 if (queue != NULL) {
1890                         queue = SYS_G_LIST_NEXT(queue);
1891                         if (queue != NULL)
1892                                 op = SYS_G_LIST_NTH(queue, 0);
1893                         else
1894                                 op = NULL;
1895                 } else
1896                         op = NULL;
1897
1898                 remove_operation(bdev);
1899
1900                 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1901                 /* UNLOCK */
1902
1903                 if (operation == BLOCK_DEV_INSERT || operation == BLOCK_DEV_REMOVE || operation == BLOCK_LUKS_CLOSE) {
1904                         if (pipe_trigger(operation, bdev, 0) < 0)
1905                                 _E("Failed to trigger pipe.");
1906                 }
1907
1908         } while (true);
1909
1910 }
1911
1912 // Called by BlockThread
1913 static void *block_th_start(void *arg)
1914 {
1915         struct block_device *temp;
1916         struct manage_thread *th = (struct manage_thread *)arg;
1917         struct operation_queue *op = NULL;
1918         GList *elem;
1919         GList *queue = NULL;
1920         int thread_id;
1921
1922         assert(th);
1923
1924         thread_id = th->thread_id;
1925         if (thread_id < 0 || thread_id >= THREAD_MAX) {
1926                 _E("Thread Number=%d.", th->thread_id);
1927                 return NULL;
1928         }
1929
1930         do {
1931                 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1932                 if (th_manager[thread_id].op_len == 0) {
1933                         _D("Operation queue of thread is empty.");
1934                         pthread_cond_wait(&(th_manager[thread_id].cond), &(th_manager[thread_id].mutex));
1935                         _D("Wake up thread=%d.", thread_id);
1936                 }
1937
1938                 SYS_G_LIST_FOREACH(th_manager[thread_id].block_dev_list, elem, temp) {
1939                         queue = temp->op_queue;
1940                         do {
1941                                 op = SYS_G_LIST_NTH(queue, 0);
1942                                 if (!op) {
1943                                         _D("Operation queue for device %s is Empty.", temp->data->devnode);
1944                                         break;
1945                                 }
1946                                 if (op->done) {
1947                                         queue = SYS_G_LIST_NEXT(queue);
1948                                         continue;
1949                                 }
1950                                 break;
1951                         } while (true);
1952                         if (op)
1953                                 break;
1954                 }
1955                 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1956
1957                 if (op && !op->done)
1958                         trigger_operation(temp, queue, op);
1959
1960         } while (true);
1961 }
1962
1963 // This function will be refactored later
1964 // Especially, we don't need to keep th_node_list.
1965 static int find_thread(char *devnode)
1966 {
1967         GList *elem;
1968         char str[PATH_MAX];
1969         char *th_node;
1970         char *temp;
1971         char dev_scsi;
1972         int i, len, min, min_num;
1973         int dev_mmc = -1, part = -1, num;
1974
1975         len = 0;
1976         if (!fnmatch("*/"MMC_PARTITION_PATH, devnode, 0)) {
1977                 sscanf(devnode, "/dev/mmcblk%dp%d", &dev_mmc, &part);
1978                 num = dev_mmc;
1979                 while (num > 0) {
1980                         num = num / 10;
1981                         len++;
1982                 }
1983                 len = len + 12;
1984                 snprintf(str, len, "/dev/mmcblk%d", dev_mmc);
1985                 th_node = strdup(str);
1986         } else if (!fnmatch("*/"SCSI_PARTITION_PATH, devnode, 0)) {
1987                 sscanf(devnode, "/dev/sd%c%d", &dev_scsi, &part);
1988                 snprintf(str, SCSI_PARTITION_LENGTH, "/dev/sd%c", dev_scsi);
1989                 th_node = strdup(str);
1990         } else
1991                 th_node = strdup(devnode);
1992
1993         len = strlen(th_node) + 1;
1994         min_num = 1000;
1995         min = -1;
1996         for (i = 0; i < THREAD_MAX; i++) {
1997                 SYS_G_LIST_FOREACH(th_manager[i].th_node_list, elem, temp) {
1998                         if (!strncmp(temp, th_node, len)) {
1999                                 free(th_node);
2000                                 return i;
2001                         }
2002                 }
2003                 if (th_manager[i].num_dev < min_num) {
2004                         min_num = th_manager[i].num_dev;
2005                         min = i;
2006                 }
2007         }
2008
2009         if (min >= 0 && min < THREAD_MAX) {
2010                 SYS_G_LIST_APPEND(th_manager[min].th_node_list, th_node);
2011                 return min;
2012         }
2013
2014         _E("Failed to find thread.");
2015         SYS_G_LIST_APPEND(th_manager[0].th_node_list, th_node);
2016         return 0;
2017 }
2018
2019 /* Only Main thread is permmited */
2020 // Called by MainThread
2021 static int add_operation(struct block_device *bdev,
2022                 enum block_dev_operation operation,
2023                 GDBusMethodInvocation *invocation, void *data)
2024 {
2025         struct operation_queue *op;
2026         int ret_val;
2027         int thread_id;
2028         bool start_th;
2029
2030         if (!bdev)
2031                 return -EINVAL;
2032
2033
2034         _I("Add operation(%s, %s).",
2035                         get_operation_char(operation),
2036                         bdev->data->devnode);
2037
2038         thread_id = bdev->thread_id;
2039         if (thread_id < 0 || thread_id >= THREAD_MAX) {
2040                 _E("Failed to find thread to add.");
2041                 return -EPERM;
2042         }
2043
2044         op = (struct operation_queue *)malloc(sizeof(struct operation_queue));
2045         if (!op) {
2046                 _E("Failed to malloc.");
2047                 return -ENOMEM;
2048         }
2049
2050         op->op = operation;
2051         op->data = data;
2052         op->invocation = invocation;
2053
2054         /* Need to disble app2ext whenever unmounting mmc */
2055         /* app2ext_disable_all_external_pkgs inside a critical section need to be avoided. */
2056         if (operation == BLOCK_DEV_UNMOUNT &&
2057                 bdev->data->state == BLOCK_MOUNT &&
2058                 bdev->data->block_type == BLOCK_MMC_DEV &&
2059                 bdev->data->primary)
2060                 if (app2ext_disable_all_external_pkgs() < 0)
2061                         _E("Failed to app2ext_disable_all_external_pkgs().");
2062
2063         /* LOCK
2064          * during adding queue and checking the queue length */
2065         pthread_mutex_lock(&(th_manager[thread_id].mutex));
2066
2067         /* Only modified between lock and unlock of mutex */
2068         op->done = false;
2069
2070         start_th = th_manager[thread_id].start_th;
2071         SYS_G_LIST_APPEND(bdev->op_queue, op);
2072         th_manager[thread_id].op_len++;
2073
2074         if (th_manager[thread_id].op_len == 1 && start_th)
2075                 pthread_cond_signal(&(th_manager[thread_id].cond));
2076
2077         pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2078         /* UNLOCK */
2079
2080         if (!start_th) {
2081                 _D("Start new thread for block device.");
2082                 th_manager[thread_id].start_th = true;
2083                 ret_val = pthread_create(&(th_manager[thread_id].th), NULL, block_th_start, &th_manager[thread_id]);
2084                 if (ret_val != 0) {
2085                         _E("Failed to create thread for %s.", bdev->data->devnode);
2086                         return -EPERM;
2087                 }
2088
2089                 pthread_detach(th_manager[thread_id].th);
2090         }
2091
2092         return 0;
2093 }
2094
2095 static bool disk_is_partitioned_by_kernel(struct udev_device *dev)
2096 {
2097         DIR *dp;
2098         struct dirent entry;
2099         struct dirent *dir;
2100         const char *syspath;
2101         bool ret = false;
2102
2103         syspath = udev_device_get_syspath(dev);
2104         if (!syspath)
2105                 goto out;
2106
2107         dp = opendir(syspath);
2108         if (!dp) {
2109                 _E("Failed to open '%s'.", syspath);
2110                 goto out;
2111         }
2112
2113         /* TODO compare devname and d_name */
2114         while (readdir_r(dp, &entry, &dir) == 0 && dir != NULL) {
2115                 if (!fnmatch(MMC_PARTITION_PATH, dir->d_name, 0) ||
2116                     !fnmatch(SCSI_PARTITION_PATH, dir->d_name, 0)) {
2117                         ret = true;
2118                         break;
2119                 }
2120         }
2121
2122         closedir(dp);
2123
2124 out:
2125         return ret;
2126 }
2127
2128 static bool check_partition(struct udev_device *dev)
2129 {
2130         const char *devtype;
2131         const char *part_table_type;
2132         const char *fs_usage;
2133         bool ret = false;
2134
2135         /* only consider disk type, never partitions */
2136         devtype = udev_device_get_devtype(dev);
2137         if (!devtype)
2138                 goto out;
2139
2140         if (strncmp(devtype, BLOCK_DEVTYPE_DISK,
2141                                 sizeof(BLOCK_DEVTYPE_DISK)) != 0)
2142                 goto out;
2143
2144         part_table_type = udev_device_get_property_value(dev,
2145                         "ID_PART_TABLE_TYPE");
2146         if (part_table_type) {
2147                 fs_usage = udev_device_get_property_value(dev,
2148                                 "ID_FS_USAGE");
2149                 if (fs_usage &&
2150                     strncmp(fs_usage, FILESYSTEM_NAME, sizeof(FILESYSTEM_NAME)) == 0) {
2151                         if (!disk_is_partitioned_by_kernel(dev))
2152                                         goto out;
2153                 }
2154                 ret = true;
2155                 goto out;
2156         }
2157
2158         if (disk_is_partitioned_by_kernel(dev)) {
2159                 ret = true;
2160                 goto out;
2161         }
2162
2163 out:
2164         return ret;
2165 }
2166
2167 // Called by MainThread
2168 static int add_block_device(struct udev_device *dev, const char *devnode, bool mapper)
2169 {
2170         struct block_data *data;
2171         struct block_device *bdev;
2172         //char id_string[PATH_LEN];
2173         bool partition;
2174         int ret;
2175         int thread_id;
2176         bool need_format = false;
2177
2178         partition = check_partition(dev);
2179         if (partition) {
2180                 /* if there is a partition, skip this request */
2181                 _I("%s device has partitions, skip this time.", devnode);
2182                 return 0;
2183         }
2184
2185         if (mapper && !udev_device_get_property_value(dev, "ID_FS_TYPE")) {
2186                 char syspath[128] = {0};
2187                 char *r;
2188
2189                 r = rindex(udev_device_get_syspath(dev), '/');
2190                 if (!r) return -ENODEV;
2191
2192                 snprintf(syspath, sizeof(syspath), "/sys/block%s", r);
2193
2194                 data = make_block_data(devnode,
2195                                 syspath,
2196                                 FILESYSTEM_NAME,
2197                                 EXT4_NAME,
2198                                 "1.0",
2199                                 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2200                                 udev_device_get_sysattr_value(dev, "ro"));
2201                 need_format = true;
2202         } else {
2203                 data = make_block_data(devnode,
2204                                 udev_device_get_syspath(dev),
2205                                 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2206                                 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2207                                 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2208                                 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2209                                 udev_device_get_sysattr_value(dev, "ro"));
2210         }
2211
2212         if (!data) {
2213                 _E("Failed to make block data for %s.", devnode);
2214                 return -EPERM;
2215         }
2216
2217         if (!block_conf[data->block_type].multimount && !data->primary &&
2218             data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME)) {
2219                 _D("Not support multi mount by config info.");
2220                 free_block_data(data);
2221                 return -EPERM;
2222         }
2223
2224         if (!block_control) {
2225                 if (!mapper && strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2226                         _D("Block module is disabled.");
2227                         free_block_data(data);
2228                         return -EPERM;
2229                 }
2230
2231         }
2232
2233         bdev = make_block_device(data);
2234         if (!bdev) {
2235                 _E("Failed to make block device for %s.", devnode);
2236                 free_block_data(data);
2237                 return -EPERM;
2238         }
2239
2240         thread_id = find_thread(bdev->data->devnode);
2241         if (thread_id < 0 || thread_id >= THREAD_MAX) {
2242                 _E("Failed to find thread to add.");
2243                 free_block_device(bdev);
2244                 return -EPERM;
2245         }
2246         bdev->thread_id = thread_id;
2247
2248         pthread_mutex_lock(&(th_manager[thread_id].mutex));
2249         th_manager[thread_id].num_dev++;
2250         SYS_G_LIST_APPEND(th_manager[thread_id].block_dev_list, bdev);
2251         pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2252
2253         if (need_format) {
2254                 struct format_data *fdata;
2255
2256                 fdata = get_format_data(NULL, UNMOUNT_FORCE);
2257                 if (!fdata) {
2258                         _E("Failed to get format data.");
2259                         return -ENOMEM;
2260                 }
2261
2262                 ret = add_operation(bdev, BLOCK_DEV_FORMAT, NULL, (void *)fdata);
2263                 if (ret < 0) {
2264                         _E("Failed to add operation(format, %s).", bdev->data->devnode);
2265                         release_format_data(fdata);
2266                 }
2267         }
2268
2269         if (!bdev->data->fs_type) {
2270                 _E("Unformatted Storage.");
2271                 free_block_device(bdev);
2272                 return -EPERM;
2273         } else if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2274 //              bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2275                 bdev->data->primary = true;
2276                 _D("Need to unlock encrypted sdcard.");
2277                 // ---- ODE UI launch ----
2278                 ret = launch_system_app(POPUP_DEFAULT
2279                                       , 8
2280                                       , POPUP_KEY_CONTENT
2281                                       , "unlockextendedsd"
2282                                       , VIEWTYPE_KEY
2283                                       , INSERT_SD_CARD
2284                                       , DEVPATH_KEY
2285                                       , bdev->data->devnode
2286                                       , MAPPING_NODE_KEY
2287                                       , EXTENDEDSD_NAME);
2288                 if (ret < 0)
2289                         _E("Failed to launch popup.");
2290
2291                 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2292                 if (ret < 0) {
2293                         _E("Failed to add operation(insert, %s).", devnode);
2294                         free_block_device(bdev);
2295                         return ret;
2296                 }
2297
2298                 return 0;
2299         } else if (mapper && !strncmp(bdev->data->fs_type, EXT4_NAME, strlen(EXT4_NAME))) {
2300                 bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2301                 ret = change_mount_point(bdev, EXTENDEDSD_MOUNT_PATH);
2302                 if (ret < 0) {
2303                         ret = -EPERM;
2304                         free_block_device(bdev);
2305                         return ret;
2306                 }
2307         }
2308
2309         ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2310         if (ret < 0) {
2311                 _E("Failed to add operation(insert, %s).", devnode);
2312                 free_block_device(bdev);
2313                 return ret;
2314         }
2315
2316         // Not a regular filesystem -> skip mounting
2317         if (!bdev->data->fs_usage || strcmp(bdev->data->fs_usage, FILESYSTEM_NAME)) {
2318                 _I("Not a filesystem. Not mounting.");
2319                 return 0;
2320         }
2321
2322         ret = add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL);
2323         if (ret < 0) {
2324                 _E("Failed to add operation(mount, %s).", devnode);
2325                 return ret;
2326         }
2327         return 0;
2328 }
2329
2330 static int remove_block_device(struct udev_device *dev, const char *devnode)
2331 {
2332         struct block_device *bdev;
2333         struct block_device *bdev_extended;
2334         int ret;
2335
2336         bdev = find_block_device(devnode);
2337         if (!bdev) {
2338                 _E("Failed to find block data for %s.", devnode);
2339                 return -ENODEV;
2340         }
2341
2342         BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
2343
2344         bdev->removed = true;
2345         if (bdev->on_private_op != REQ_NORMAL) {
2346                 bdev->on_private_op = REQ_NORMAL;
2347                 _D("Private operation state(%d).", bdev->on_private_op);
2348         }
2349
2350         if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2351                 bdev_extended = find_block_device_path(EXTENDEDSD_MOUNT_PATH);
2352
2353                 if (bdev_extended) {
2354                         BLOCK_FLAG_SET(bdev_extended->data, UNMOUNT_UNSAFE);
2355
2356                         bdev_extended->removed = true;
2357                         if (bdev_extended->on_private_op != REQ_NORMAL) {
2358                                 bdev_extended->on_private_op = REQ_NORMAL;
2359                                 _D("Private operation state(%d).", bdev_extended->on_private_op);
2360                         }
2361
2362                         ret = add_operation(bdev_extended, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2363                         if (ret < 0) {
2364                                 _E("Failed to add operation(unmount, %s).", devnode);
2365                                 return ret;
2366                         }
2367
2368                         ret = add_operation(bdev_extended, BLOCK_LUKS_CLOSE, NULL, NULL);
2369                         if (ret < 0) {
2370                                 _E("Failed to add operation(luks_close, %s).", devnode);
2371                                 return ret;
2372                         }
2373
2374                         ret = add_operation(bdev_extended, BLOCK_DEV_REMOVE, NULL, NULL);
2375                         if (ret < 0) {
2376                                 _E("Failed to add operation(remove, %s).", devnode);
2377                                 return ret;
2378                         }
2379                 } else
2380                         _E("Failed to find block data for extended sd card.");
2381         }
2382
2383         ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2384         if (ret < 0) {
2385                 _E("Failed to add operation(unmount, %s).", devnode);
2386                 return ret;
2387         }
2388
2389         ret = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2390         if (ret < 0) {
2391                 _E("Failed to add operation(remove, %s).", devnode);
2392                 return ret;
2393         }
2394
2395         return 0;
2396 }
2397
2398 static int get_internal_storage_number(void)
2399 {
2400         struct libmnt_table *t = NULL;
2401         struct libmnt_fs *fs;
2402         const char *temp;
2403         char *name;
2404         int r = 0, dev_temp;
2405
2406         if ((!is_emulator() && (dev_internal >= 0 || dev_internal_scsi != '\0')) ||
2407                 (is_emulator() && dev_internal_emul != '\0'))
2408                 return 0;
2409
2410         t = mnt_new_table();
2411         if (!t)
2412                 return -EPERM;
2413
2414         r = mnt_table_parse_mtab(t, NULL);
2415         if (r < 0) {
2416                 mnt_free_table(t);
2417                 return -EPERM;
2418         }
2419
2420         fs = mnt_table_find_target(t, ROOT_DIR, MNT_ITER_BACKWARD);
2421
2422         if (!fs) {
2423                 mnt_free_table(t);
2424                 return -EPERM;
2425         }
2426         temp = mnt_fs_get_srcpath(fs);
2427         if (!temp) {
2428                 mnt_free_table(t);
2429                 return -EPERM;
2430         }
2431
2432         name = strrchr(temp, '/');
2433         if (!name) {
2434                 mnt_free_table(t);
2435                 return -EPERM;
2436         }
2437         name++;
2438
2439         /* Boot from USB is not handled */
2440         if (!is_emulator()) {
2441                 if (!fnmatch(MMC_PATH, temp, 0))
2442                         sscanf(name, "mmcblk%d", &dev_internal);
2443                 else if (!fnmatch(SCSI_PATH, temp, 0))
2444                         sscanf(name, "sd%c", &dev_internal_scsi);
2445         } else {
2446                 if (!fnmatch(MMC_LINK_PATH, temp, 0))
2447                         sscanf(name, "vd%c%d", &dev_internal_emul, &dev_temp);
2448                 else
2449                         dev_internal_emul = '\0';
2450         }
2451
2452         mnt_free_table(t);
2453
2454         return 0;
2455 }
2456
2457 static int check_external_storage(const char* devnode)
2458 {
2459         char dev_scsi = '\0';
2460         char *name;
2461         char emul = '\0';
2462         int dev_num = -1, dev_temp;
2463
2464         if (!devnode)
2465                 return -EPERM;
2466
2467         name = strrchr(devnode, '/');
2468         if (!name)
2469                 return -EPERM;
2470         name++;
2471         if (!is_emulator()) {
2472                 if (!fnmatch(MMC_PATH, devnode, 0)) {
2473                         sscanf(name, "mmcblk%d", &dev_num);
2474                         if (dev_internal == dev_num) {
2475                                 _D("%s is internal storage.", devnode);
2476                                 return 0;
2477                         }
2478                 } else if (!fnmatch(SCSI_PATH, devnode, 0)) {
2479                         sscanf(name, "sd%c", &dev_scsi);
2480                         if (dev_internal_scsi == dev_scsi) {
2481                                 _D("%s is internal storage.", devnode);
2482                                 return 0;
2483                         }
2484                 }
2485         } else {
2486                 if (!fnmatch(MMC_LINK_PATH, devnode, 0)) {
2487                         sscanf(name, "vd%c%d", &emul, &dev_temp);
2488                         if (dev_internal_emul == emul) {
2489                                 _D("%s is internal storage.", devnode);
2490                                 return 0;
2491                         }
2492                 }
2493         }
2494
2495         return 1;
2496 }
2497
2498 static int check_already_handled(const char* devnode)
2499 {
2500         struct block_device *bdev;
2501         struct block_data *data;
2502         GList *elem;
2503         int i;
2504
2505         for (i = 0; i < THREAD_MAX; i++) {
2506                 pthread_mutex_lock(&(th_manager[i].mutex));
2507                 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2508                         data = bdev->data;
2509                         if (!data)
2510                                 continue;
2511                         if (bdev->removed)
2512                                 continue;
2513                         if (!strncmp(data->devnode, devnode, strlen(devnode) + 1)) {
2514                                 pthread_mutex_unlock(&(th_manager[i].mutex));
2515                                 return -1;
2516                         }
2517                 }
2518                 pthread_mutex_unlock(&(th_manager[i].mutex));
2519         }
2520
2521         return 0;
2522 }
2523
2524 static int block_init_from_udev_enumerate(void)
2525 {
2526         struct udev *udev;
2527         struct udev_enumerate *enumerate;
2528         struct udev_list_entry *list_entry, *list_sub_entry;
2529         struct udev_device *dev;
2530         const char *syspath;
2531         const char *devnode;
2532         int r = 0;
2533
2534         udev = udev_new();
2535         if (!udev) {
2536                 _E("Failed to create udev library context.");
2537                 return -EPERM;
2538         }
2539
2540         /* create a list of the devices in the 'usb' subsystem */
2541         enumerate = udev_enumerate_new(udev);
2542         if (!enumerate) {
2543                 _E("Failed to create an enumeration context.");
2544                 return -EPERM;
2545         }
2546
2547         udev_enumerate_add_match_subsystem(enumerate, BLOCK_SUBSYSTEM);
2548         udev_enumerate_add_match_property(enumerate,
2549                         UDEV_DEVTYPE, BLOCK_DEVTYPE_DISK);
2550         udev_enumerate_add_match_property(enumerate,
2551                         UDEV_DEVTYPE, BLOCK_DEVTYPE_PARTITION);
2552         udev_enumerate_scan_devices(enumerate);
2553
2554         udev_list_entry_foreach(list_entry,
2555                         udev_enumerate_get_list_entry(enumerate)) {
2556                 syspath = udev_list_entry_get_name(list_entry);
2557                 if (!syspath)
2558                         continue;
2559
2560                 dev = udev_device_new_from_syspath(
2561                                 udev_enumerate_get_udev(enumerate),
2562                                 syspath);
2563                 if (!dev)
2564                         continue;
2565
2566                 devnode = NULL;
2567                 udev_list_entry_foreach(list_sub_entry,
2568                                 udev_device_get_devlinks_list_entry(dev)) {
2569                         const char *devlink = udev_list_entry_get_name(list_sub_entry);
2570                         if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2571                                 devnode = devlink;
2572                                 break;
2573                         }
2574                 }
2575
2576                 if (!devnode) {
2577                         devnode = udev_device_get_devnode(dev);
2578                         if (!devnode) {
2579                                 udev_device_unref(dev);
2580                                 continue;
2581                         }
2582
2583                         if (fnmatch(MMC_PATH, devnode, 0) &&
2584                             fnmatch(SCSI_PATH, devnode, 0) &&
2585                             fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0)) {
2586                                 udev_device_unref(dev);
2587                                 continue;
2588                         }
2589                 }
2590
2591                 r = check_external_storage(devnode);
2592                 if (r <= 0) {
2593                         udev_device_unref(dev);
2594                         continue;
2595                 }
2596
2597                 r = check_already_handled(devnode);
2598                 if (r < 0) {
2599                         _I("%s is already handled.", devnode);
2600                         udev_device_unref(dev);
2601                         continue;
2602                 }
2603
2604                 _I("%s device add.", devnode);
2605                 add_block_device(dev, devnode, false);
2606
2607                 udev_device_unref(dev);
2608         }
2609
2610         udev_enumerate_unref(enumerate);
2611         udev_unref(udev);
2612         return 0;
2613 }
2614
2615 // Called by MainThread
2616 static void show_block_device_list(void)
2617 {
2618         struct block_device *bdev;
2619         struct block_data *data;
2620         GList *elem;
2621         int i;
2622
2623         for (i = 0; i < THREAD_MAX; i++) {
2624                 pthread_mutex_lock(&(th_manager[i].mutex));
2625                 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2626                         data = bdev->data;
2627                         if (!data)
2628                                 continue;
2629                         if (bdev->removed)
2630                                 continue;
2631                         _D("%s:", data->devnode);
2632                         _D("\tSyspath=%s", data->syspath);
2633                         _D("\tBlock type=%d", data->block_type);
2634                         _D("\tFs type=%s", data->fs_type);
2635                         _D("\tFs usage=%s", data->fs_usage);
2636                         _D("\tFs version=%s", data->fs_version);
2637                         _D("\tFs uuid enc=%s", data->fs_uuid_enc);
2638                         _D("\tReadonly=%s",
2639                                         (data->readonly ? "true" : "false"));
2640                         _D("\tMount point=%s", data->mount_point);
2641                         _D("\tMount state=%s",
2642                                         (data->state == BLOCK_MOUNT ?
2643                                          "mount" : "unmount"));
2644                         _D("\tPrimary=%s",
2645                                         (data->primary ? "true" : "false"));
2646                         _D("\tID=%d", data->id);
2647                 }
2648                 pthread_mutex_unlock(&(th_manager[i].mutex));
2649         }
2650 }
2651
2652 // Called by MainThread
2653 static void remove_whole_block_device(void)
2654 {
2655         struct block_device *bdev;
2656         GList *elem;
2657         GList *next;
2658         int r;
2659         int i;
2660
2661         for (i = 0; i < THREAD_MAX; i++) {
2662                 do {
2663                         pthread_mutex_lock(&(th_manager[i].mutex));
2664                         SYS_G_LIST_FOREACH_SAFE(th_manager[i].block_dev_list, elem, next, bdev) {
2665                                 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2666                                     !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2667                                         continue;
2668                                 if (bdev->removed == false)
2669                                         break;
2670                         }
2671                         pthread_mutex_unlock(&(th_manager[i].mutex));
2672
2673                         if (bdev && bdev->removed == false) {
2674                                 bdev->removed = true;
2675                                 r = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2676                                 if (r < 0)
2677                                         _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
2678
2679                                 r = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2680                                 if (r < 0)
2681                                         _E("Failed to add operation(remove, %s).", bdev->data->devnode);
2682                         } else
2683                                 break;
2684                 } while (true);
2685         }
2686 }
2687
2688 static void add_poweroff_wait_cb(GVariant *var, void *user_data, GError *err)
2689 {
2690         int ret_val = -ENOMSG;
2691
2692         if (!var)
2693                 return ;
2694
2695         if (!g_variant_get_safe(var, "(i)", &ret_val))
2696                 _E("Failed to get(%s): no message", g_variant_get_type_string(var));
2697
2698         if (ret_val >= 0)
2699                 add_poweroff_wait = true;
2700
2701         g_variant_unref(var);
2702 }
2703
2704 static void booting_done(void)
2705 {
2706         static int done = 0;
2707         int ret_val;
2708
2709         if (done > 0)
2710                 return;
2711         done = 1;
2712         _I("Booting done.");
2713
2714         /* register mmc uevent control routine */
2715         ret_val = register_udev_uevent_control(&uh);
2716         if (ret_val < 0)
2717                 _E("Failed to register block uevent: %d", ret_val);
2718
2719         block_control = true;
2720         /* if there is the attached device, try to mount */
2721         block_init_from_udev_enumerate();
2722
2723         ret_val = gdbus_call_async_with_reply(DEVICED_BUS_NAME,
2724                 DEVICED_PATH_POWEROFF,
2725                 DEVICED_INTERFACE_POWEROFF,
2726                 METHOD_ADD_POWEROFF_WAIT,
2727                 NULL,
2728                 add_poweroff_wait_cb,
2729                 -1, NULL);
2730         if (ret_val < 0)
2731                 _E("Failed to call "METHOD_ADD_POWEROFF_WAIT" method.");
2732
2733         block_boot = true;
2734 }
2735
2736 static void block_poweroff(GDBusConnection  *conn,
2737                 const gchar *sender,
2738                 const gchar *path,
2739                 const gchar *iface,
2740                 const gchar *name,
2741                 GVariant *param,
2742                 gpointer data)
2743 {
2744         static int status = 0;
2745         int ret_dbus;
2746
2747         if (status > 0)
2748                 return;
2749         status = 1;
2750         _I("Power off.");
2751         /* unregister mmc uevent control routine */
2752         unregister_udev_uevent_control(&uh);
2753         remove_whole_block_device();
2754         terminate_threads();
2755
2756         if (add_poweroff_wait) {
2757                 ret_dbus = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
2758                         DEVICED_PATH_POWEROFF,
2759                         DEVICED_INTERFACE_POWEROFF,
2760                         METHOD_REMOVE_POWEROFF_WAIT,
2761                         NULL, NULL);
2762                 if (ret_dbus < 0)
2763                         _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method.");
2764                 else
2765                         add_poweroff_wait = false;
2766         }
2767 }
2768
2769 static void uevent_block_handler(struct udev_device *dev)
2770 {
2771         const char *devnode = NULL;
2772         const char *action;
2773         struct udev_list_entry *list_entry;
2774         int r;
2775         bool mapper = false;
2776
2777         udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
2778                 const char *devlink = udev_list_entry_get_name(list_entry);
2779                 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2780                         devnode = devlink;
2781                         break;
2782                 }
2783                 if (!fnmatch(EXTENDEDSD_NODE_PATH, devlink, 0)) {
2784                         mapper = true;
2785                         devnode = devlink;
2786                         break;
2787                 }
2788         }
2789
2790         if (!devnode) {
2791                 devnode = udev_device_get_devnode(dev);
2792                 if (!devnode)
2793                         return;
2794
2795                 if (fnmatch(MMC_PATH, devnode, 0) &&
2796                     fnmatch(SCSI_PATH, devnode, 0))
2797                         return;
2798         }
2799
2800         r = check_external_storage(devnode);
2801         if (r <= 0)
2802                 return;
2803
2804         action = udev_device_get_action(dev);
2805         if (!action)
2806                 return;
2807
2808         _I("%s device %s.", devnode, action);
2809         if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD)) ||
2810            (mapper && !strcmp(action, UDEV_CHANGE))) {
2811                 r = check_already_handled(devnode);
2812                 if (r < 0) {
2813                         _I("%s is already handled.", devnode);
2814                         return;
2815                 }
2816
2817                 add_block_device(dev, devnode, mapper);
2818         } else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE))) {
2819                 remove_block_device(dev, devnode);
2820         } else if (!strncmp(action, UDEV_CHANGE, sizeof(UDEV_CHANGE))) {
2821                 struct block_device *bdev;
2822                 bdev = find_block_device(devnode);
2823                 if (!bdev) {
2824                         _E("Failed to find block data for %s.", devnode);
2825                         return;
2826                 }
2827                 if (!udev_device_get_property_value(dev, "ID_FS_TYPE"))
2828                         return;
2829
2830                 r = update_block_data(bdev->data,
2831                                 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2832                                 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2833                                 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2834                                 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2835                                 udev_device_get_sysattr_value(dev, "ro"),
2836                                 false);
2837                 if (r < 0)
2838                         _E("Failed to update block data for %s.", bdev->data->devnode);
2839                 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2840                         _I("Filesystem type(crypto_LUKS) is updated.");
2841                 if (bdev->data->fs_usage)
2842                         _I("fs_usage=%s", bdev->data->fs_usage);
2843         }
2844 }
2845
2846 static GVariant *request_mount_block(GDBusConnection *conn,
2847                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2848                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2849 {
2850         struct block_device *bdev;
2851         char *mount_point = NULL;
2852         int id;
2853         int ret = -EBADMSG;
2854
2855         if (!block_control) {
2856                 _D("Block module is disabled.");
2857                 ret = -EPERM;
2858                 goto out;
2859         }
2860
2861         g_variant_get(param, "(is)", &id, &mount_point);
2862
2863         bdev = find_block_device_by_id(id);
2864         if (!bdev) {
2865                 _E("Failed to find (%d) in the device list.", id);
2866                 ret = -ENOENT;
2867                 goto out;
2868         }
2869
2870         if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2871             !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2872                 _D("Mount dbus request for extended internal storage is blocked.");
2873                 ret = -EPERM;
2874                 goto out;
2875         }
2876
2877         if (bdev->on_private_op != REQ_NORMAL) {
2878                 ret = -EPERM;
2879                 goto out;
2880         }
2881
2882         if (bdev->data->state == BLOCK_MOUNT) {
2883                 _I("%s is already mounted.", bdev->data->devnode);
2884                 ret = -EALREADY;
2885                 goto out;
2886         }
2887
2888         if (onprivate) {
2889                 bdev->on_private_op = REQ_PRIVATE;
2890                 bdev->private_pid = gdbus_connection_get_sender_pid(NULL, sender);
2891                 _D("Private operation state(%d). pid=%d.", bdev->on_private_op, bdev->private_pid);
2892         }
2893
2894         /* if requester want to use a specific mount point */
2895         if (mount_point && strncmp(mount_point, "", 1) != 0) {
2896                 ret = change_mount_point(bdev, mount_point);
2897                 if (ret < 0) {
2898                         ret = -EPERM;
2899                         goto out;
2900                 }
2901         }
2902
2903         ret = add_operation(bdev, BLOCK_DEV_MOUNT, invocation, NULL);
2904         if (ret < 0) {
2905                 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
2906                 goto out;
2907         }
2908
2909         g_free(mount_point);
2910         return NULL;
2911
2912 out:
2913         g_free(mount_point);
2914         return g_variant_new("(i)", ret);
2915 }
2916
2917 static GVariant *request_public_mount_block(GDBusConnection *conn,
2918                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2919                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2920 {
2921         return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
2922 }
2923
2924 static GVariant *request_private_mount_block(GDBusConnection *conn,
2925                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2926                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2927 {
2928         return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
2929 }
2930
2931 static GVariant *request_unmount_block(GDBusConnection *conn,
2932                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2933                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2934 {
2935         struct block_device *bdev;
2936         pid_t pid;
2937         long option;
2938         int id;
2939         int ret = -EBADMSG;
2940
2941         if (!block_control) {
2942                 _D("Block module is disabled.");
2943                 ret = -EPERM;
2944                 goto out;
2945         }
2946
2947         g_variant_get(param, "(ii)", &id, &option);
2948
2949         bdev = find_block_device_by_id(id);
2950         if (!bdev) {
2951                 _E("Failed to find (%d) in the device list.", id);
2952                 ret = -ENOENT;
2953                 goto out;
2954         }
2955
2956         /* Unmount dbus call is needed when app proceeds extended internal -> portable storage */
2957         if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2958                 _D("Unmount dbus request for extended internal storage is blocked.");
2959                 ret = -EPERM;
2960                 goto out;
2961         }
2962
2963         if (onprivate) {
2964                 pid = gdbus_connection_get_sender_pid(NULL, sender);
2965                 if (bdev->on_private_op == REQ_NORMAL || (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid)) {
2966                         _E("Failed to process private unmount operation pid=%d private_pid=%d.", pid, bdev->private_pid);
2967                         ret = -EPERM;
2968                         goto out;
2969                 }
2970         } else {
2971                 if (bdev->on_private_op != REQ_NORMAL) {
2972                         _E("Failed to process unmount operation.");
2973                         ret = -EPERM;
2974                         goto out;
2975                 }
2976         }
2977
2978         ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, invocation, (void *)option);
2979         if (ret < 0) {
2980                 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
2981                 goto out;
2982         }
2983
2984         if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
2985                 ret = add_operation(bdev, BLOCK_LUKS_CLOSE, NULL, NULL);
2986                 if (ret < 0)
2987                         _E("Failed to add operation(luks_close, %s).", bdev->data->devnode);
2988         }
2989
2990         return NULL;
2991
2992 out:
2993         return g_variant_new("(i)", ret);
2994 }
2995
2996 static GVariant *request_public_unmount_block(GDBusConnection *conn,
2997                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2998                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2999 {
3000         return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
3001 }
3002
3003 static GVariant *request_private_unmount_block(GDBusConnection *conn,
3004                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3005                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3006 {
3007         return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
3008 }
3009
3010 static GVariant *request_format_block(GDBusConnection *conn,
3011                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3012                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3013 {
3014         struct block_device *bdev;
3015         struct format_data *fdata;
3016         pid_t pid;
3017         int id;
3018         int option;
3019         int ret = -EBADMSG;
3020         int prev_state;
3021
3022         if (!block_control) {
3023                 _D("Block module is disabled.");
3024                 ret = -EPERM;
3025                 goto out;
3026         }
3027
3028         g_variant_get(param, "(ii)", &id, &option);
3029
3030         bdev = find_block_device_by_id(id);
3031         if (!bdev) {
3032                 _E("Failed to find (%d) in the device list.", id);
3033                 goto out;
3034         }
3035
3036         if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
3037             !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
3038                 _D("Format dbus request for extended internal storage is blocked.");
3039                 ret = -EPERM;
3040                 goto out;
3041         }
3042
3043         pid = gdbus_connection_get_sender_pid(NULL, sender);
3044         if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
3045                 _E("Failed to format on private state.");
3046                 ret = -EPERM;
3047                 goto out;
3048         }
3049
3050         fdata = get_format_data(NULL, option);
3051         if (!fdata) {
3052                 _E("Failed to get format data.");
3053                 goto out;
3054         }
3055
3056         prev_state = bdev->data->state;
3057         if (prev_state == BLOCK_MOUNT) {
3058                 if (bdev->on_private_op == REQ_PRIVATE) {
3059                         bdev->on_private_op = REQ_PRIVATE_FORMAT;
3060                         _D("Private operation state(%d)", bdev->on_private_op);
3061                 }
3062                 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3063                 if (ret < 0) {
3064                         _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
3065                         release_format_data(fdata);
3066                         goto out;
3067                 }
3068         }
3069
3070         ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3071         if (ret < 0) {
3072                 _E("Failed to add operation(format, %s).", bdev->data->devnode);
3073                 release_format_data(fdata);
3074         }
3075
3076         /* Maintain previous state of mount/unmount */
3077         if (prev_state == BLOCK_MOUNT) {
3078                 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3079                         _E("Failed to add operation(mount, %s).", bdev->data->devnode);
3080                         goto out;
3081                 }
3082         }
3083
3084         return NULL;
3085
3086 out:
3087         return g_variant_new("(i)", ret);
3088 }
3089
3090 static GVariant *request_format_block_type(GDBusConnection *conn,
3091                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3092                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3093 {
3094         struct block_device *bdev;
3095         struct format_data *fdata;
3096         char *type = NULL;
3097         pid_t pid;
3098         int id;
3099         int option;
3100         int ret = -EBADMSG;
3101         int prev_state;
3102
3103         if (!block_control) {
3104                 _D("Block module is disabled.");
3105                 ret = -EPERM;
3106                 goto out;
3107         }
3108
3109         g_variant_get(param, "(iis)", &id, &option, &type);
3110
3111         bdev = find_block_device_by_id(id);
3112         if (!bdev) {
3113                 _E("Failed to find (%d) in the device list.", id);
3114                 goto out;
3115         }
3116
3117         /* FormatwithType dbus call is needed when app proceeds extended internal -> portable storage */
3118         if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
3119                 _D("FormatwithType dbus request for extended internal storage is blocked.");
3120                 ret = -EPERM;
3121                 goto out;
3122         }
3123
3124         pid = gdbus_connection_get_sender_pid(NULL, sender);
3125         if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
3126                 _E("Failed to format on private state.");
3127                 ret = -EPERM;
3128                 goto out;
3129         }
3130
3131         fdata = get_format_data(type, option);
3132         if (!fdata) {
3133                 _E("Failed to get format data.");
3134                 goto out;
3135         }
3136
3137         prev_state = bdev->data->state;
3138         if (prev_state == BLOCK_MOUNT) {
3139                 if (bdev->on_private_op == REQ_PRIVATE) {
3140                         bdev->on_private_op = REQ_PRIVATE_FORMAT;
3141                         _D("Private operation state(%d).", bdev->on_private_op);
3142                 }
3143                 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3144                 if (ret < 0) {
3145                         _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
3146                         release_format_data(fdata);
3147                         goto out;
3148                 }
3149         }
3150
3151         ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3152         if (ret < 0) {
3153                 _E("Failed to add operation(format, %s).", bdev->data->devnode);
3154                 release_format_data(fdata);
3155         }
3156
3157         /* Maintain previous state of mount/unmount */
3158         if (prev_state == BLOCK_MOUNT) {
3159                 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3160                         _E("Failed to add operation(mount, %s).", bdev->data->devnode);
3161                         goto out;
3162                 }
3163         }
3164
3165         g_free(type);
3166         return NULL;
3167
3168 out:
3169         g_free(type);
3170         return g_variant_new("(i)", ret);
3171 }
3172
3173 static GVariant *block_data_to_gvariant(struct block_data *data, int flags)
3174 {
3175         if (!data)
3176                 return gdbus_new_g_variant_tuple();
3177
3178         return g_variant_new("(issssssisibii)",
3179                         data->block_type,
3180                         nullstr(data->devnode),
3181                         nullstr(data->syspath),
3182                         nullstr(data->fs_usage),
3183                         nullstr(data->fs_type),
3184                         nullstr(data->fs_version),
3185                         nullstr(data->fs_uuid_enc),
3186                         data->readonly,
3187                         nullstr(data->mount_point),
3188                         data->state,
3189                         data->primary,
3190                         flags >= 0 ? flags : data->flags,
3191                         data->id);
3192 }
3193
3194 //static int add_device_to_struct_iter(struct block_data *data, DBusMessageIter *iter)
3195 //{
3196 //      //DBusMessageIter piter;
3197 //
3198 //      //if (!data || !iter)
3199 //      //      return -EINVAL;
3200 //
3201 //      //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3202 //      //add_device_to_iter(data, &piter);
3203 //      //dbus_message_iter_close_container(iter, &piter);
3204 //
3205 //      return 0;
3206 //}
3207
3208 //static int add_device_to_iter_2(struct block_data *data, DBusMessageIter *iter)
3209 //{
3210 //      DBusMessageIter piter;
3211 //      char *str_null = "";
3212 //
3213 //      if (!data || !iter)
3214 //              return -EINVAL;
3215 //
3216 //      //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3217 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3218 //      //              &(data->block_type));
3219 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3220 //      //              data->devnode ? &(data->devnode) : &str_null);
3221 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3222 //      //              data->syspath ? &(data->syspath) : &str_null);
3223 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3224 //      //              data->fs_usage ? &(data->fs_usage) : &str_null);
3225 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3226 //      //              data->fs_type ? &(data->fs_type) : &str_null);
3227 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3228 //      //              data->fs_version ? &(data->fs_version) : &str_null);
3229 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3230 //      //              data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
3231 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3232 //      //              &(data->readonly));
3233 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3234 //      //              data->mount_point ? &(data->mount_point) : &str_null);
3235 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3236 //      //              &(data->state));
3237 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_BOOLEAN,
3238 //      //              &(data->primary));
3239 //      //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3240 //      //              &(data->flags));
3241 //      //dbus_message_iter_close_container(iter, &piter);
3242 //
3243 //      return 0;
3244 //}
3245
3246 static GVariant *request_get_device_info(GDBusConnection *conn,
3247                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3248         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3249 {
3250         struct block_device *bdev = NULL;
3251         struct block_data *data = NULL;
3252         struct block_data nodata = {0,};
3253         int id;
3254
3255         g_variant_get(param, "(i)", &id);
3256
3257         bdev = find_block_device_by_id(id);
3258         if (!bdev)
3259                 goto out;
3260         data = bdev->data;
3261         if (!data)
3262                 goto out;
3263
3264 out:
3265         if (!data) {
3266                 nodata.id = -ENODEV;
3267                 data = &nodata;
3268         }
3269
3270         return block_data_to_gvariant(data, -1);
3271 }
3272
3273 static GVariant *request_show_device_list(GDBusConnection *conn,
3274                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3275                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3276 {
3277         show_block_device_list();
3278         return gdbus_new_g_variant_tuple();
3279 }
3280
3281 static enum block_device_type get_bdev_type_from_type_string(const char *type_str)
3282 {
3283         if (!type_str)
3284                 return BLOCK_UNKNOWN_DEV;
3285
3286         if (strcmp(type_str, BLOCK_TYPE_SCSI) == 0)
3287                 return BLOCK_SCSI_DEV;
3288         if (strcmp(type_str, BLOCK_TYPE_MMC) == 0)
3289                 return BLOCK_MMC_DEV;
3290         if (strcmp(type_str, BLOCK_TYPE_ALL) == 0)
3291                 return BLOCK_ALL_DEV;
3292
3293         return BLOCK_UNKNOWN_DEV;
3294 }
3295
3296 // Called by MainThread
3297 static GVariant *request_get_device_list(GDBusConnection *conn,
3298                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3299                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3300 {
3301         GVariant *reply = NULL;
3302         struct block_device *bdev;
3303         struct block_data *data;
3304         GList *elem;
3305         char *type = NULL;
3306         enum block_device_type block_type;
3307         int i;
3308         GVariantBuilder *builder = NULL;
3309         const char *error = NULL;
3310
3311         g_variant_get(param, "(s)", &type);
3312
3313         _D("Block (%s) device list is requested.", type);
3314
3315         block_type = get_bdev_type_from_type_string(type);
3316         if (block_type == BLOCK_UNKNOWN_DEV) {
3317                 _E("Invalid type (%s) is requested.", type);
3318                 error = "Invalid type is requested";
3319                 goto out;
3320         }
3321
3322         builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibii)"));
3323
3324         for (i = 0; i < THREAD_MAX; i++) {
3325                 pthread_mutex_lock(&(th_manager[i].mutex));
3326                 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3327                         if (!bdev->data || bdev->removed)
3328                                 continue;
3329
3330                         data = bdev->data;
3331
3332                         if (block_type != BLOCK_ALL_DEV) {
3333                                 if (data->block_type != block_type)
3334                                         continue;
3335                         }
3336
3337                         g_variant_builder_add(builder, "(issssssisibii)",
3338                                         data->block_type,
3339                                         nullstr(data->devnode),
3340                                         nullstr(data->syspath),
3341                                         nullstr(data->fs_usage),
3342                                         nullstr(data->fs_type),
3343                                         nullstr(data->fs_version),
3344                                         nullstr(data->fs_uuid_enc),
3345                                         data->readonly,
3346                                         nullstr(data->mount_point),
3347                                         data->state,
3348                                         data->primary,
3349                                         data->flags,
3350                                         data->id);
3351                 }
3352                 pthread_mutex_unlock(&(th_manager[i].mutex));
3353         }
3354
3355         reply = g_variant_new("(a(issssssisibii))", builder);
3356
3357         g_variant_builder_unref(builder);
3358
3359 out:
3360         g_free(type);
3361
3362         if (!reply)
3363                 g_dbus_method_invocation_return_error(invocation,
3364                                 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3365                                 "%s", error);
3366         return reply;
3367 }
3368
3369 // Called by MainThread
3370 static GVariant *request_get_device_list_2(GDBusConnection *conn,
3371                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3372                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3373 {
3374         GVariant *reply = NULL;
3375         struct block_device *bdev;
3376         struct block_data *data;
3377         GList *elem;
3378         char *type = NULL;
3379         enum block_device_type block_type;
3380         int i;
3381         GVariantBuilder *builder = NULL;
3382         const char *error = NULL;
3383
3384         g_variant_get(param, "(s)", &type);
3385         if (!type) {
3386                 _E("Delivered type is NULL.");
3387                 error = "Delivered type is NULL";
3388                 goto out;
3389         }
3390
3391         _D("Block (%s) device list is requested.", type);
3392
3393         block_type = get_bdev_type_from_type_string(type);
3394         if (block_type == BLOCK_UNKNOWN_DEV) {
3395                 _E("Invalid type (%s) is requested.", type);
3396                 error = "Invalid type is requested";
3397                 goto out;
3398         }
3399
3400         builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibi)"));
3401
3402         for (i = 0; i < THREAD_MAX; i++) {
3403                 pthread_mutex_lock(&(th_manager[i].mutex));
3404                 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3405                         if (!bdev->data || bdev->removed)
3406                                 continue;
3407
3408                         data = bdev->data;
3409
3410                         if (block_type != BLOCK_ALL_DEV) {
3411                                 if (data->block_type != block_type)
3412                                         continue;
3413                         }
3414
3415                         g_variant_builder_add(builder, "(issssssisibi)",
3416                                         data->block_type,
3417                                         nullstr(data->devnode),
3418                                         nullstr(data->syspath),
3419                                         nullstr(data->fs_usage),
3420                                         nullstr(data->fs_type),
3421                                         nullstr(data->fs_version),
3422                                         nullstr(data->fs_uuid_enc),
3423                                         data->readonly,
3424                                         nullstr(data->mount_point),
3425                                         data->state,
3426                                         data->primary,
3427                                         data->flags);
3428                 }
3429                 pthread_mutex_unlock(&(th_manager[i].mutex));
3430         }
3431
3432         reply = g_variant_new("(a(issssssisibi))", builder);
3433
3434         g_variant_builder_unref(builder);
3435
3436 out:
3437         g_free(type);
3438
3439         if (!reply)
3440                 g_dbus_method_invocation_return_error(invocation,
3441                                 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3442                                 "%s", error);
3443         return reply;
3444 }
3445
3446 static GVariant *request_get_mmc_primary(GDBusConnection *conn,
3447                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3448                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3449 {
3450         struct block_device *bdev;
3451         struct block_data *data = NULL, nodata = {0,};
3452         GList *elem;
3453         bool found = false;
3454         int i;
3455
3456         for (i = 0; i < THREAD_MAX; i++) {
3457                 pthread_mutex_lock(&(th_manager[i].mutex));
3458                 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3459                         data = bdev->data;
3460                         if (!data)
3461                                 continue;
3462                         if (bdev->removed)
3463                                 continue;
3464                         if (data->block_type != BLOCK_MMC_DEV &&
3465                             data->block_type != BLOCK_EXTENDEDSD_DEV)
3466                                 continue;
3467                         if (!data->primary)
3468                                 continue;
3469                         // Return mapper node(/dev/mapper/extendedsd) for primary mmc (not /dev/mmcblk1p1(ex))
3470                         if (!strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
3471                                 continue;
3472                         found = true;
3473                         break;
3474                 }
3475                 pthread_mutex_unlock(&(th_manager[i].mutex));
3476                 if (found)
3477                         break;
3478         }
3479
3480         if (!found) {
3481                 nodata.id = -ENODEV;
3482                 data = &nodata;
3483         }
3484
3485         return block_data_to_gvariant(data, -1);
3486 }
3487
3488 static GVariant *request_check_speed(GDBusConnection *conn,
3489                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3490                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3491 {
3492         struct timespec start_time, end_time;
3493         struct block_device *bdev;
3494         struct block_data *data;
3495         char *buf = NULL;
3496         int ret_val;
3497         int result = 0;
3498         int id;
3499         int fd;
3500         int time_diff;
3501
3502         g_variant_get(param, "(i)", &id);
3503
3504         bdev = find_block_device_by_id(id);
3505         if (!bdev) {
3506                 result = -1;
3507                 goto out;
3508         }
3509         data = bdev->data;
3510         if (!data) {
3511                 result = -1;
3512                 goto out;
3513         }
3514
3515         _D("Speed check %s.", data->devnode);
3516         fd = open(data->devnode, O_RDONLY | O_DIRECT);
3517         if (fd < 0) {
3518                 _E("Failed to open fd(%s): %d", data->devnode, errno);
3519                 result = -1;
3520                 goto out;
3521         }
3522         ret_val = posix_memalign((void**)&buf, 4096, SPEEDCHECK_SIZE << 20);
3523         if (ret_val) {
3524                 _E("Failed to posix_memalign().");
3525                 result = -1;
3526                 goto out_close;
3527         }
3528
3529         clock_gettime(CLOCK_REALTIME, &start_time);
3530         _I("Start time=%lu.%lu", start_time.tv_sec, start_time.tv_nsec);
3531         ret_val = read(fd, buf, SPEEDCHECK_SIZE << 20);
3532         clock_gettime(CLOCK_REALTIME, &end_time);
3533         _I("End time=%lu.%lu", end_time.tv_sec, end_time.tv_nsec);
3534
3535         free(buf);
3536
3537         if (ret_val < 0) {
3538                 _E("Failed to read(): %d", errno);
3539                 result = -1;
3540                 goto out_close;
3541         }
3542
3543         time_diff = end_time.tv_sec - start_time.tv_sec;
3544         if (time_diff > 0 && (SPEEDCHECK_SIZE / time_diff < SPEEDCHECK_CRITERION)) {
3545                 result = -1;
3546                 goto out_close;
3547         }
3548
3549 out_close:
3550         close(fd);
3551 out:
3552         return g_variant_new("(i)", result);
3553 }
3554
3555
3556 static GVariant *request_control_block(GDBusConnection *conn,
3557                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3558                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3559 {
3560         int enable;
3561         int result;
3562
3563         g_variant_get(param, "(i)", &enable);
3564
3565         switch (enable) {
3566         case 0:
3567                 _I("Control block disable.");
3568                 result = 0;
3569                 block_stop(NULL);
3570                 break;
3571         case 1:
3572                 _I("Control block enable.");
3573                 result = 0;
3574                 block_start(NULL);
3575                 break;
3576         default:
3577                 _E("Control block. Wrong request by client.");
3578                 result = 1;
3579                 break;
3580         }
3581
3582         return g_variant_new("(i)", result);
3583 }
3584
3585 static GVariant *request_getcontrol_block(GDBusConnection *conn,
3586                 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3587                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3588 {
3589         int result;
3590
3591         _I("Get control block.");
3592
3593         result = block_control;
3594
3595         return g_variant_new("(i)", result);
3596 }
3597
3598 /*
3599   Method name      Method call format string  Reply format string
3600 { "ShowDeviceList",                      NULL,               NULL, request_show_device_list },
3601 { "GetDeviceList",                        "s", "a(issssssisibii)", request_get_device_list },
3602 { "GetDeviceList2",                       "s",  "a(issssssisibi)", request_get_device_list_2 },
3603 { "Mount",                               "is",                "i", request_public_mount_block },
3604 { "Unmoun,                               "ii",                "i", request_public_unmount_block },
3605 { "Format",                              "ii",                "i", request_format_block },
3606 { "GetDeviceInfo",                        "i",  "(issssssisibii)", request_get_device_info },
3607 { "GetMmcPrimary",                       NULL, "(issssssisibii)" , request_get_mmc_primary },
3608 { "PrivateMount",                        "is",                "i", request_private_mount_block },
3609 { "PrivateUnmount",                      "ii",                "i", request_private_unmount_block },
3610 */
3611
3612 static const dbus_method_s manager_methods[] = {
3613         { "ShowDeviceList",   NULL,                 NULL, request_show_device_list },
3614         { "GetDeviceList" ,    "s",   "a(issssssisibii)", request_get_device_list },
3615         { "GetDeviceList2",    "s",    "a(issssssisibi)", request_get_device_list_2 },
3616         { "Mount",            "is",                  "i", request_public_mount_block },
3617         { "Unmount",          "ii",                  "i", request_public_unmount_block },
3618         { "Format",           "ii",                  "i", request_format_block },
3619         { "FormatwithType",  "iis",                  "i", request_format_block_type },
3620         { "GetDeviceInfo",     "i",      "issssssisibii", request_get_device_info },
3621         { "GetMmcPrimary",    NULL,      "issssssisibii", request_get_mmc_primary },
3622         { "PrivateMount",     "is",                  "i", request_private_mount_block },
3623         { "PrivateUnmount",   "ii",                  "i", request_private_unmount_block },
3624         { "CheckSpeed",        "i",                  "i", request_check_speed },
3625         { "Control",           "i",                  "i", request_control_block },
3626         { "GetControl",       NULL,                  "i", request_getcontrol_block },
3627 };
3628
3629 static const dbus_interface_u block_interface = {
3630         .name = STORAGED_INTERFACE_BLOCK_MANAGER,
3631         .methods = manager_methods,
3632         .nr_methods = ARRAY_SIZE(manager_methods),
3633 };
3634
3635 static int load_config(struct parse_result *result, void *user_data)
3636 {
3637         int index;
3638
3639         if (MATCH(result->section, "Block"))
3640                 return 0;
3641
3642         if (MATCH(result->section, "SCSI"))
3643                 index = BLOCK_SCSI_DEV;
3644         else if (MATCH(result->section, "MMC"))
3645                 index = BLOCK_MMC_DEV;
3646         else if (MATCH(result->section, "Mapper"))
3647                 index = BLOCK_EXTENDEDSD_DEV;
3648         else
3649                 return -EINVAL;
3650
3651         if (MATCH(result->name, "Multimount"))
3652                 block_conf[index].multimount =
3653                         (MATCH(result->value, "yes") ? true : false);
3654         if (MATCH(result->name, "ExtendedInternalStorage"))
3655                 block_conf[index].extendedinternal =
3656                         (MATCH(result->value, "yes") ? true : false);
3657
3658         return 0;
3659 }
3660
3661 #ifdef BLOCK_TMPFS
3662 static int mount_root_path_tmpfs(void)
3663 {
3664         int ret_val;
3665         const char *root;
3666
3667         root = tzplatform_getenv(TZ_SYS_MEDIA);
3668         if (!root)
3669                 return -ENOTSUP;
3670
3671         if (access(root, F_OK) != 0)
3672                 return -ENODEV;
3673
3674         if (mount_check(root))
3675                 return 0;
3676
3677         ret_val = mount("tmpfs", root, "tmpfs", 0, "smackfsroot=System::Shared");
3678         if (ret_val < 0) {
3679                 ret_val = -errno;
3680                 _E("Failed to mount tmpfs: %d", ret_val);
3681                 return ret_val;
3682         }
3683
3684         return 0;
3685 }
3686 #else
3687 #define mount_root_path_tmpfs() 0
3688 #endif
3689
3690 static guint id_block_poweroff;
3691
3692 static void block_init(void *data)
3693 {
3694         int ret_val;
3695         int i;
3696
3697         udev_init(NULL);
3698
3699         /* load config */
3700         ret_val = config_parse(BLOCK_CONF_FILE, load_config, NULL);
3701         if (ret_val < 0)
3702                 _E("Failed to load '%s'. Use default value.", BLOCK_CONF_FILE);
3703
3704         ret_val = mount_root_path_tmpfs();
3705         if (ret_val < 0)
3706                 _E("Failed to mount tmpfs to root mount path: %d", ret_val);
3707
3708         /* register block manager object and interface */
3709         ret_val = gdbus_register_object(NULL, STORAGED_PATH_BLOCK_MANAGER, &block_interface);
3710         if (ret_val < 0)
3711                 _E("Failed to register block interface and methods: %d", ret_val);
3712
3713         /* init pipe */
3714         ret_val = pipe_init();
3715         if (ret_val < 0)
3716                 _E("Failed to init pipe.");
3717
3718         for (i = 0; i < THREAD_MAX; i++) {
3719                 th_manager[i].num_dev = 0;
3720                 th_manager[i].op_len = 0;
3721                 th_manager[i].start_th = false;
3722                 th_manager[i].thread_id = i;
3723                 pthread_mutex_init(&(th_manager[i].mutex), NULL);
3724                 pthread_cond_init(&(th_manager[i].cond), NULL);
3725         }
3726
3727         ret_val = remove_directory(EXTERNAL_STORAGE_PATH);
3728         if (ret_val < 0)
3729                 _E("Failed to remove directory.");
3730         ret_val = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3731         if (ret_val < 0)
3732                 _E("Failed to make directory: %d", errno);
3733
3734         ret_val = remove_directory(EXTENDED_INTERNAL_PATH);
3735         if (ret_val < 0)
3736                 _E("Failed to remove directory.");
3737         ret_val = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3738         if (ret_val < 0)
3739                 _E("Failed to make directory: %d", errno);
3740
3741         ret_val = get_internal_storage_number();
3742         if (ret_val < 0)
3743                 _E("Failed to get internal storage number.");
3744
3745         id_block_poweroff = gdbus_signal_subscribe(NULL, DEVICED_PATH_POWEROFF,
3746                         DEVICED_INTERFACE_POWEROFF,
3747                         SIGNAL_POWEROFF_STATE,
3748                         block_poweroff, NULL, NULL);
3749
3750         booting_done();
3751 }
3752 static void terminate_threads(void)
3753 {
3754         GList *elem, *elem_next;
3755         char *temp;
3756         int i, count;
3757         const int WAIT_TIME = 10;
3758
3759         for (i = 0; i < THREAD_MAX; i++) {
3760                 if (th_manager[i].start_th) {
3761                         count = 0;
3762                         while ((th_manager[i].op_len != 0) && (count < WAIT_TIME)) {
3763                                 _I("Thread(%d) job is not finished. Wait a second.", th_manager[i].thread_id);
3764                                 usleep(200*1000);
3765                                 count++;
3766                         }
3767                         pthread_cancel(th_manager[i].th);
3768                         pthread_join(th_manager[i].th, NULL);
3769                 }
3770                 SYS_G_LIST_FOREACH_SAFE(th_manager[i].th_node_list, elem, elem_next, temp) {
3771                         SYS_G_LIST_REMOVE(th_manager[i].th_node_list, temp);
3772                         free(temp);
3773                 }
3774         }
3775 }
3776
3777 static void block_exit(void *data)
3778 {
3779         int ret_val;
3780
3781         udev_exit(NULL);
3782
3783         /* unregister notifier for below each event */
3784         gdbus_signal_unsubscribe(NULL, id_block_poweroff);
3785
3786         /* unregister mmc uevent control routine */
3787         ret_val = unregister_udev_uevent_control(&uh);
3788         if (ret_val < 0)
3789                 _E("Failed to unregister block uevent: %d", ret_val);
3790
3791         /* remove remaining blocks */
3792         remove_whole_block_device();
3793
3794         terminate_threads();
3795
3796         /* exit pipe */
3797         pipe_exit();
3798
3799         if (add_poweroff_wait) {
3800                 ret_val = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
3801                         DEVICED_PATH_POWEROFF,
3802                         DEVICED_INTERFACE_POWEROFF,
3803                         METHOD_REMOVE_POWEROFF_WAIT,
3804                         NULL, NULL);
3805                 if (ret_val < 0)
3806                         _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method.");
3807                 else
3808                         add_poweroff_wait = false;
3809         }
3810
3811         block_control = false;
3812 }
3813
3814 static int block_start(void *data)
3815 {
3816         if (!block_boot) {
3817                 _E("Cannot be started. Booting is not ready.");
3818                 return -ENODEV;
3819         }
3820
3821         if (block_control) {
3822                 _I("Already started.");
3823                 return 0;
3824         }
3825
3826         block_control = true;
3827
3828         block_init_from_udev_enumerate();
3829
3830         _I("Start.");
3831         return 0;
3832 }
3833
3834 static int block_stop(void *data)
3835 {
3836         if (!block_boot) {
3837                 _E("Cannot be stopped. Booting is not ready.");
3838                 return -ENODEV;
3839         }
3840
3841         if (!block_control) {
3842                 _I("Already stopped.");
3843                 return 0;
3844         }
3845
3846         /* remove the existing blocks */
3847         remove_whole_block_device();
3848
3849         block_control = false;
3850
3851         _I("Stop.");
3852         return 0;
3853 }
3854
3855 static storaged_module_interface block_module = {
3856         .name     = "block",
3857         .init     = block_init,
3858         .exit     = block_exit,
3859         .start    = block_start,
3860         .stop     = block_stop,
3861 };
3862
3863 __attribute__ ((visibility("default")))storaged_module_interface *
3864 storaged_get_module_interface(void)
3865 {
3866         return &block_module;
3867 }