tizen 2.3 release
[framework/system/deviced.git] / src / mmc / mmc-handler.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 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
20 #include <stdlib.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <sys/mount.h>
24 #include <sys/statvfs.h>
25 #include <errno.h>
26 #include <vconf.h>
27 #include <fcntl.h>
28 #include <dirent.h>
29 #include <sys/statfs.h>
30 #include <signal.h>
31 #include <stdbool.h>
32 #include <pthread.h>
33 #include <assert.h>
34
35 #include "core/log.h"
36 #include "core/device-handler.h"
37 #include "core/device-notifier.h"
38 #include "core/common.h"
39 #include "core/devices.h"
40 #include "ode/ode.h"
41 #include "mmc-handler.h"
42 #include "config.h"
43 #include "core/edbus-handler.h"
44 #include "core/list.h"
45 #include "core/config-parser.h"
46
47 #define VCONFKEY_INTERNAL_PRIVATE_MMC_ID        "db/private/sysman/mmc_device_id"
48
49 #define MMC_PARENT_PATH "/opt/storage"
50 #define MMC_DEV                 "/dev/mmcblk"
51
52 #define SMACKFS_MAGIC   0x43415d53
53 #define SMACKFS_MNT             "/smack"
54
55 #ifndef ST_RDONLY
56 #define ST_RDONLY               0x0001
57 #endif
58
59 #define MMC_32GB_SIZE   61315072
60 #define FORMAT_RETRY    3
61 #define UNMOUNT_RETRY   5
62
63 #define ODE_MOUNT_STATE 1
64
65 #define COMM_PKG_MGR_DBUS_SERVICE     "com.samsung.slp.pkgmgr"
66 #define COMM_PKG_MGR_DBUS_PATH          "/com/samsung/slp/pkgmgr"
67 #define COMM_PKG_MGR_DBUS_INTERFACE COMM_PKG_MGR_DBUS_SERVICE
68 #define COMM_PKG_MGR_METHOD                "CreateExternalDirectory"
69
70 #define SMACK_LABELING_TIME (0.5)
71
72 enum unmount_operation {
73         UNMOUNT_NORMAL = 0,
74         UNMOUNT_FORCE,
75 };
76
77 enum mmc_operation {
78         MMC_MOUNT = 0,
79         MMC_UNMOUNT,
80         MMC_FORMAT,
81         MMC_END,
82 };
83
84 static void *mount_start(void *arg);
85 static void *unmount_start(void *arg);
86 static void *format_start(void *arg);
87
88 static const struct mmc_thread_func {
89         enum mmc_operation type;
90         void *(*func) (void*);
91 } mmc_func[MMC_END] = {
92         [MMC_MOUNT] = {.type = MMC_MOUNT, .func = mount_start},
93         [MMC_UNMOUNT] = {.type = MMC_UNMOUNT, .func = unmount_start},
94         [MMC_FORMAT] = {.type = MMC_FORMAT, .func = format_start},
95 };
96
97 struct mmc_data {
98         int option;
99         char *devpath;
100 };
101
102 struct popup_data {
103         char *name;
104         char *key;
105         char *value;
106 };
107
108 static dd_list *fs_head;
109 static char *mmc_curpath;
110 static bool smack = false;
111 static bool mmc_disabled = false;
112 static Ecore_Timer *smack_timer = NULL;
113
114 int __WEAK__ app2ext_unmount(void);
115
116 static void __CONSTRUCTOR__ smack_check(void)
117 {
118         struct statfs sfs;
119         int ret;
120
121         do {
122                 ret = statfs(SMACKFS_MNT, &sfs);
123         } while (ret < 0 && errno == EINTR);
124
125         if (ret == 0 && sfs.f_type == SMACKFS_MAGIC)
126                 smack = true;
127         _I("smackfs check %d", smack);
128 }
129
130 void add_fs(const struct mmc_fs_ops *fs)
131 {
132         DD_LIST_APPEND(fs_head, (void*)fs);
133 }
134
135 void remove_fs(const struct mmc_fs_ops *fs)
136 {
137         DD_LIST_REMOVE(fs_head, (void*)fs);
138 }
139
140 const struct mmc_fs_ops *find_fs(enum mmc_fs_type type)
141 {
142         struct mmc_fs_ops *fs;
143         dd_list *elem;
144
145         DD_LIST_FOREACH(fs_head, elem, fs) {
146                 if (fs->type == type)
147                         return fs;
148         }
149         return NULL;
150 }
151
152 bool mmc_check_mounted(const char *mount_point)
153 {
154         struct stat parent_stat, mount_stat;
155         char parent_path[PATH_MAX];
156
157         snprintf(parent_path, sizeof(parent_path), "%s", MMC_PARENT_PATH);
158
159         if (stat(mount_point, &mount_stat) != 0 || stat(parent_path, &parent_stat) != 0)
160                 return false;
161
162         if (mount_stat.st_dev == parent_stat.st_dev)
163                 return false;
164
165         return true;
166 }
167
168 static void launch_syspopup(char *str)
169 {
170         struct popup_data *params;
171         static const struct device_ops *apps = NULL;
172
173         FIND_DEVICE_VOID(apps, "apps");
174
175         params = malloc(sizeof(struct popup_data));
176         if (params == NULL) {
177                 _E("Malloc failed");
178                 return;
179         }
180         params->name = MMC_POPUP_NAME;
181         params->key = POPUP_KEY_CONTENT;
182         params->value = strdup(str);
183         apps->init((void *)params);
184         free(params);
185 }
186
187 static int get_partition(const char *devpath, char *subpath)
188 {
189         char path[NAME_MAX];
190         int i;
191
192         for (i = 1; i < 5; ++i) {
193                 snprintf(path, sizeof(path), "%sp%d", devpath, i);
194                 if (!access(path, R_OK)) {
195                         strncpy(subpath, path, strlen(path));
196                         return 0;
197                 }
198         }
199         return -ENODEV;
200 }
201
202 static int create_partition(const char *devpath)
203 {
204         int r;
205         char data[NAME_MAX];
206
207         snprintf(data, sizeof(data), "\"n\\n\\n\\n\\n\\nw\" | fdisk %s", devpath);
208
209         r = launch_evenif_exist("/usr/bin/printf", data);
210         if (WIFSIGNALED(r) && (WTERMSIG(r) == SIGINT || WTERMSIG(r) == SIGQUIT || WEXITSTATUS(r)))
211                 return -1;
212
213         return 0;
214 }
215
216 static int mmc_check_and_unmount(const char *path)
217 {
218         int ret = 0, retry = 0;
219         while (mount_check(path)) {
220                 ret = umount(path);
221                 if (ret < 0) {
222                         retry++;
223                         if (retry > UNMOUNT_RETRY)
224                                 return -errno;
225                 }
226         }
227         return ret;
228 }
229
230 int get_block_number(void)
231 {
232         DIR *dp;
233         struct dirent *dir;
234         struct stat stat;
235         char buf[255];
236         int fd;
237         int r;
238         int mmcblk_num;
239         char *pre_mmc_device_id = NULL;
240         int mmc_dev_changed = 0;
241
242         if ((dp = opendir("/sys/block")) == NULL) {
243                 _E("Can not open directory..");
244                 return -1;
245         }
246
247         r = chdir("/sys/block");
248         if (r < 0) {
249                 _E("Fail to change the directory..");
250                 closedir(dp);
251                 return r;
252         }
253
254         while ((dir = readdir(dp)) != NULL) {
255                 memset(&stat, 0, sizeof(struct stat));
256                 if(lstat(dir->d_name, &stat) < 0) {continue;}
257                 if (S_ISDIR(stat.st_mode) || S_ISLNK(stat.st_mode)) {
258                         if (strncmp(".", dir->d_name, 1) == 0
259                             || strncmp("..", dir->d_name, 2) == 0)
260                                 continue;
261                         if (strncmp("mmcblk", dir->d_name, 6) == 0) {
262                                 snprintf(buf, 255, "/sys/block/%s/device/type",
263                                          dir->d_name);
264
265                                 fd = open(buf, O_RDONLY);
266                                 if (fd == -1) {
267                                         continue;
268                                 }
269                                 r = read(fd, buf, 10);
270                                 if ((r >= 0) && (r < 10))
271                                         buf[r] = '\0';
272                                 else
273                                         _E("%s read error: %s", buf,
274                                                       strerror(errno));
275                                 close(fd);
276                                 if (strncmp("SD", buf, 2) == 0) {
277                                         char *str_mmcblk_num = strndup((dir->d_name) + 6, 1);
278                                         if (str_mmcblk_num == NULL) {
279                                                 _E("Memory Allocation Failed");
280                                                 closedir(dp);
281                                                 return -1;
282                                         }
283                                         mmcblk_num =
284                                             atoi(str_mmcblk_num);
285
286                                         free(str_mmcblk_num);
287                                         closedir(dp);
288                                         _I("%d", mmcblk_num);
289
290                                         snprintf(buf, 255, "/sys/block/%s/device/cid", dir->d_name);
291
292                                         fd = open(buf, O_RDONLY);
293                                         if (fd == -1) {
294                                                 _E("%s open error", buf, strerror(errno));
295                                                 return mmcblk_num;
296                                         }
297                                         r = read(fd, buf, 255);
298                                         if ((r >=0) && (r < 255)) {
299                                                 buf[r] = '\0';
300                                         } else {
301                                                 _E("%s read error: %s", buf,strerror(errno));
302                                         }
303                                         close(fd);
304                                         pre_mmc_device_id = vconf_get_str(VCONFKEY_INTERNAL_PRIVATE_MMC_ID);
305                                         if (pre_mmc_device_id) {
306                                                 if (strcmp(pre_mmc_device_id, "") == 0) {
307                                                         vconf_set_str(VCONFKEY_INTERNAL_PRIVATE_MMC_ID, buf);
308                                                 } else if (strncmp(pre_mmc_device_id,buf,33) == 0) {
309                                                         if ( vconf_get_int(VCONFKEY_SYSMAN_MMC_DEVICE_CHANGED,&mmc_dev_changed) == 0
310                                                         && mmc_dev_changed != VCONFKEY_SYSMAN_MMC_NOT_CHANGED) {
311                                                                 vconf_set_int(VCONFKEY_SYSMAN_MMC_DEVICE_CHANGED, VCONFKEY_SYSMAN_MMC_NOT_CHANGED);
312                                                         }
313                                                 } else if (strncmp(pre_mmc_device_id,buf,32) != 0) {
314                                                         vconf_set_str(VCONFKEY_INTERNAL_PRIVATE_MMC_ID, buf);
315                                                         vconf_set_int(VCONFKEY_SYSMAN_MMC_DEVICE_CHANGED, VCONFKEY_SYSMAN_MMC_CHANGED);
316                                                 }
317                                                 free(pre_mmc_device_id);
318                                         } else {
319                                                 _E("failed to get pre_mmc_device_id");
320                                         }
321                                         return mmcblk_num;
322                                 }
323                         }
324
325                 }
326         }
327         closedir(dp);
328         _E("failed to find mmc block number");
329         return -1;
330 }
331
332 static int find_mmc_node(char devpath[])
333 {
334         int num;
335
336         num = get_block_number();
337         if (num < 0)
338                 return -ENODEV;
339
340         snprintf(devpath, NAME_MAX, "%s%d", MMC_DEV, num);
341         return 0;
342 }
343
344 static int get_mmc_size(const char *devpath)
345 {
346         int fd, r;
347         unsigned long long ullbytes;
348         unsigned int nbytes;
349
350         fd = open(devpath, O_RDONLY);
351         if (fd < 0) {
352                 _E("open error");
353                 return -EINVAL;
354         }
355
356         r = ioctl(fd, BLKGETSIZE64, &ullbytes);
357         close(fd);
358
359         if (r < 0) {
360                 _E("ioctl BLKGETSIZE64 error");
361                 return -EINVAL;
362         }
363
364         nbytes = ullbytes/512;
365         _I("block size(64) : %d", nbytes);
366         return nbytes;
367 }
368
369 static int rw_mount(const char *szPath)
370 {
371         struct statvfs mount_stat;
372         if (!statvfs(szPath, &mount_stat)) {
373                 if ((mount_stat.f_flag & ST_RDONLY) == ST_RDONLY)
374                         return -1;
375         }
376         return 0;
377 }
378
379 static void request_smack_broadcast(void)
380 {
381         int ret;
382
383         ret = dbus_method_sync_timeout(COMM_PKG_MGR_DBUS_SERVICE,
384                         COMM_PKG_MGR_DBUS_PATH,
385                         COMM_PKG_MGR_DBUS_INTERFACE,
386                         COMM_PKG_MGR_METHOD,
387                         NULL, NULL, SMACK_LABELING_TIME*1000);
388         if (ret != 0)
389                 _E("Failed to call dbus method (err: %d)", ret);
390 }
391
392 static Eina_Bool smack_timer_cb(void *data)
393 {
394         if (smack_timer) {
395                 ecore_timer_del(smack_timer);
396                 smack_timer = NULL;
397         }
398         vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, VCONFKEY_SYSMAN_MMC_MOUNTED);
399         vconf_set_int(VCONFKEY_SYSMAN_MMC_MOUNT, VCONFKEY_SYSMAN_MMC_MOUNT_COMPLETED);
400         return EINA_FALSE;
401 }
402
403 void mmc_mount_done(void)
404 {
405         request_smack_broadcast();
406         smack_timer = ecore_timer_add(SMACK_LABELING_TIME,
407                         smack_timer_cb, NULL);
408         if (smack_timer) {
409                 _I("Wait to check");
410                 return;
411         }
412         _E("Fail to add abnormal check timer");
413         smack_timer_cb(NULL);
414 }
415
416 static int mmc_mount(const char *devpath, const char *mount_point)
417 {
418         struct mmc_fs_ops *fs;
419         dd_list *elem;
420         char path[NAME_MAX] = {0,};
421         int r;
422
423         /* mmc_disabled set by start/stop func. */
424         if (mmc_disabled)
425                 return -EWOULDBLOCK;
426
427         if (!devpath)
428                 return -ENODEV;
429
430         /* check partition */
431         r = get_partition(devpath, path);
432         if (!r)
433                 devpath = path;
434
435         DD_LIST_FOREACH(fs_head, elem, fs) {
436                 if (fs->match(devpath))
437                         break;
438         }
439
440         if (!fs)
441                 return -EINVAL;
442
443         _I("devpath : %s", devpath);
444         r = fs->check(devpath);
445         if (r < 0)
446                 _E("failt to check devpath : %s", devpath);
447
448         r = fs->mount(smack, devpath, mount_point);
449         if (r < 0)
450                 return r;
451
452         r = rw_mount(mount_point);
453         if (r < 0)
454                 return -EROFS;
455
456         return 0;
457 }
458
459 static void *mount_start(void *arg)
460 {
461         struct mmc_data *data = (struct mmc_data*)arg;
462         char *devpath;
463         int r;
464
465         devpath = data->devpath;
466         if (!devpath) {
467                 r = -EINVAL;
468                 goto error;
469         }
470
471         /* clear previous filesystem */
472         ode_mmc_removed();
473         mmc_check_and_unmount(MMC_MOUNT_POINT);
474
475         /* check mount point */
476         if (access(MMC_MOUNT_POINT, R_OK) != 0) {
477                 if (mkdir(MMC_MOUNT_POINT, 0755) < 0) {
478                         r = -errno;
479                         goto error;
480                 }
481         }
482
483         /* mount operation */
484         r = mmc_mount(devpath, MMC_MOUNT_POINT);
485         if (r == -EROFS)
486                 launch_syspopup("mountrdonly");
487         /* Do not need to show error popup, if mmc is disabled */
488         else if (r == -EWOULDBLOCK)
489                 goto error_without_popup;
490         else if (r < 0)
491                 goto error;
492
493         mmc_set_config(MAX_RATIO);
494         r = ode_mmc_inserted();
495         if (r < 0)
496                 goto error_ode;
497
498         free(devpath);
499         free(data);
500
501         /* give a transmutable attribute to mount_point */
502         r = setxattr(MMC_MOUNT_POINT, "security.SMACK64TRANSMUTE", "TRUE", strlen("TRUE"), 0);
503         if (r < 0)
504                 _E("setxattr error : %s", strerror(errno));
505
506         request_smack_broadcast();
507         vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, VCONFKEY_SYSMAN_MMC_MOUNTED);
508         vconf_set_int(VCONFKEY_SYSMAN_MMC_MOUNT, VCONFKEY_SYSMAN_MMC_MOUNT_COMPLETED);
509         return 0;
510
511 error:
512         launch_syspopup("mounterr");
513
514 error_without_popup:
515         vconf_set_int(VCONFKEY_SYSMAN_MMC_MOUNT, VCONFKEY_SYSMAN_MMC_MOUNT_FAILED);
516         vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
517
518         free(devpath);
519         free(data);
520         _E("failed to mount device : %s", strerror(-r));
521         return (void *)r;
522
523 error_ode:
524         /* to ignore previous mount callbck func,
525            set a specific value(-1) to MMC_MOUNT key */
526         vconf_set_int(VCONFKEY_SYSMAN_MMC_MOUNT, -1);
527         vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, -1);
528         r = ODE_MOUNT_STATE;
529
530         free(devpath);
531         free(data);
532         _I("you should mount with encryption");
533         return (void *)r;
534 }
535
536 static int mmc_unmount(int option, const char *mount_point)
537 {
538         int r, retry = 0;
539         int kill_op;
540
541         /* try to unmount app2ext */
542         r = app2ext_unmount();
543         if (r < 0)
544                 _I("Faild to unmount app2ext : %s", strerror(-r));
545         /* it must called before unmounting mmc */
546         ode_mmc_removed();
547         r = mmc_check_and_unmount(mount_point);
548         if (!r)
549                 return r;
550         if (option == UNMOUNT_NORMAL) {
551                 _I("Failed to unmount with normal option : %s", strerror(-r));
552                 return r;
553         }
554
555         _I("Execute force unmount!");
556         /* Force Unmount Scenario */
557         while (1) {
558                 switch (retry++) {
559                 case 0:
560                         /* At first, notify to other app who already access sdcard */
561                         _I("Notify to other app who already access sdcard");
562                         vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
563                         break;
564                 case 1:
565                         /* Second, kill app with SIGTERM */
566                         _I("Kill app with SIGTERM");
567                         terminate_process(MMC_MOUNT_POINT, false);
568                         break;
569                 case 2:
570                         /* Last time, kill app with SIGKILL */
571                         _I("Kill app with SIGKILL");
572                         terminate_process(MMC_MOUNT_POINT, true);
573                         break;
574                 default:
575                         if (umount2(mount_point, MNT_DETACH) != 0) {
576                                 _I("Failed to unmount with lazy option : %s", strerror(errno));
577                                 return -errno;
578                         }
579                         return 0;
580                 }
581
582                 /* it takes some seconds til other app completely clean up */
583                 usleep(500*1000);
584
585                 /* try to unmount app2ext */
586                 r = app2ext_unmount();
587                 if (r < 0)
588                         _I("Faild to unmount app2ext : %s", strerror(-r));
589
590                 ode_mmc_removed();
591                 r = mmc_check_and_unmount(mount_point);
592                 if (!r)
593                         break;
594         }
595
596         return r;
597 }
598
599 static void *unmount_start(void *arg)
600 {
601         struct mmc_data *data = (struct mmc_data*)arg;
602         int option, r;
603
604         option = data->option;
605
606         assert(option == UNMOUNT_NORMAL || option == UNMOUNT_FORCE);
607
608         r = mmc_unmount(option, MMC_MOUNT_POINT);
609         if (r < 0)
610                 goto error;
611
612         free(data);
613         vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
614         return 0;
615
616 error:
617         free(data);
618         _E("Failed to unmount device : %s", strerror(-r));
619         vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, VCONFKEY_SYSMAN_MMC_MOUNTED);
620         return (void *)r;
621 }
622
623 static int format(const char *devpath)
624 {
625         const struct mmc_fs_ops *fs = NULL;
626         dd_list *elem;
627         char path[NAME_MAX] = {0,};
628         int r, size, retry;
629
630         if (!devpath)
631                 return -ENODEV;
632
633         /* check partition */
634         r = get_partition(devpath, path);
635         if (!r) {
636                 /* if there is partition, find partition file system */
637                 DD_LIST_FOREACH(fs_head, elem, fs) {
638                         if (fs->match(path))
639                                 break;
640                 }
641         } else {
642                 /* if there isn't partition, create partition */
643                 create_partition(devpath);
644                 r = get_partition(devpath, path);
645                 if (r < 0)
646                         memcpy(path, devpath, strlen(devpath));
647         }
648
649         _I("format partition : %s", path);
650
651         if (!fs) {
652                 /* find root file system */
653                 DD_LIST_FOREACH(fs_head, elem, fs) {
654                         if (fs->match(devpath))
655                                 break;
656                 }
657         }
658
659         if (!fs) {
660                 /* cannot find root and partition file system,
661                    find suitable file system */
662                 size = get_mmc_size(path);
663                 if (size <= MMC_32GB_SIZE)
664                         fs = find_fs(FS_TYPE_VFAT);
665                 else
666                         fs = find_fs(FS_TYPE_EXFAT);
667         }
668
669         if (!fs)
670                 return -EINVAL;
671
672         for (retry = FORMAT_RETRY; retry > 0; --retry) {
673                 fs->check(devpath);
674                 _I("format path : %s", path);
675                 r = fs->format(path);
676                 if (!r)
677                         break;
678         }
679         return r;
680 }
681
682 static void *format_start(void *arg)
683 {
684         struct mmc_data *data = (struct mmc_data*)arg;
685         char *devpath;
686         int option, r, key = VCONFKEY_SYSMAN_MMC_MOUNTED;
687         bool format_ret = true;
688
689         option = data->option;
690         devpath = data->devpath;
691
692         assert(devpath);
693         assert(option == UNMOUNT_NORMAL || option == UNMOUNT_FORCE);
694
695         _I("Format Start (option:%d)", option);
696         r = mmc_unmount(option, MMC_MOUNT_POINT);
697         if (r < 0)
698                 goto release_memory;
699
700         vconf_set_int(VCONFKEY_SYSMAN_MMC_FORMAT_PROGRESS, VCONFKEY_SYSMAN_MMC_FORMAT_PROGRESS_NOW);
701         r = format(devpath);
702         vconf_set_int(VCONFKEY_SYSMAN_MMC_FORMAT_PROGRESS, VCONFKEY_SYSMAN_MMC_FORMAT_PROGRESS_NONE);
703         if (r != 0)
704                 format_ret = false;
705
706         mount_start(arg);
707         if (!format_ret)
708                 goto error;
709         _I("Format Successful");
710         vconf_set_int(VCONFKEY_SYSMAN_MMC_FORMAT, VCONFKEY_SYSMAN_MMC_FORMAT_COMPLETED);
711         return 0;
712
713 release_memory:
714         free(devpath);
715         free(data);
716 error:
717         _E("Format Failed : %s", strerror(-r));
718         vconf_set_int(VCONFKEY_SYSMAN_MMC_FORMAT, VCONFKEY_SYSMAN_MMC_FORMAT_FAILED);
719         return (void*)r;
720 }
721
722 static int mmc_make_thread(int type, int option, const char *devpath)
723 {
724         pthread_t th;
725         struct mmc_data *pdata;
726         int r;
727
728         if (type < 0 || type >= MMC_END)
729                 return -EINVAL;
730
731         pdata = malloc(sizeof(struct mmc_data));
732         if (!pdata) {
733                 _E("malloc failed");
734                 return -errno;
735         }
736
737         if (option >= 0)
738                 pdata->option = option;
739         if (devpath)
740                 pdata->devpath = strdup(devpath);
741         r = pthread_create(&th, NULL, mmc_func[type].func, pdata);
742         if (r != 0) {
743                 _E("pthread create failed");
744                 free(pdata->devpath);
745                 free(pdata);
746                 return -EPERM;
747         }
748
749         pthread_detach(th);
750         return 0;
751 }
752
753 static int mmc_inserted(const char *devpath)
754 {
755         int r;
756         _I("MMC inserted : %s", devpath);
757         mmc_curpath = strdup(devpath);
758         r = mmc_make_thread(MMC_MOUNT, -1, devpath);
759         if (r < 0)
760                 return r;
761         return 0;
762 }
763
764 static int mmc_removed(void)
765 {
766         _I("MMC removed");
767         /* first, try to unmount app2ext */
768         app2ext_unmount();
769         /* unmount */
770         ode_mmc_removed();
771         mmc_check_and_unmount((const char *)MMC_MOUNT_POINT);
772         vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, VCONFKEY_SYSMAN_MMC_REMOVED);
773         free(mmc_curpath);
774         mmc_curpath = NULL;
775         return 0;
776 }
777
778 static int mmc_changed_cb(void *data)
779 {
780         char *devpath = (char*)data;
781
782         /* if MMC is inserted */
783         if (devpath)
784                 return mmc_inserted(devpath);
785         else
786                 return mmc_removed();
787 }
788
789 static int mmc_booting_done(void* data)
790 {
791         char devpath[NAME_MAX] = {0,};
792         int r;
793
794         /* check mmc exists */
795         r = find_mmc_node(devpath);
796         if (r < 0)
797                 return 0;
798
799         /* if MMC exists */
800         return mmc_inserted(devpath);
801 }
802
803 static DBusMessage *edbus_request_secure_mount(E_DBus_Object *obj, DBusMessage *msg)
804 {
805         DBusMessageIter iter;
806         DBusMessage *reply;
807         char *path;
808         int ret;
809
810         ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &path,
811                         DBUS_TYPE_INVALID);
812         if (!ret) {
813                 ret = -EBADMSG;
814                 goto error;
815         }
816
817         if (!mmc_curpath) {
818                 ret = -ENODEV;
819                 goto error;
820         }
821
822         /* check mount point */
823         if (access(path, R_OK) != 0) {
824                 if (mkdir(path, 0755) < 0) {
825                         ret = -errno;
826                         goto error;
827                 }
828         }
829
830         _I("mount path : %s", path);
831         ret = mmc_mount(mmc_curpath, path);
832
833 error:
834         reply = dbus_message_new_method_return(msg);
835         dbus_message_iter_init_append(reply, &iter);
836         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
837         return reply;
838 }
839
840 static DBusMessage *edbus_request_secure_unmount(E_DBus_Object *obj, DBusMessage *msg)
841 {
842         DBusMessageIter iter;
843         DBusMessage *reply;
844         char *path;
845         int ret;
846
847         ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &path,
848                         DBUS_TYPE_INVALID);
849         if (!ret) {
850                 ret = -EBADMSG;
851                 goto error;
852         }
853
854         _I("unmount path : %s", path);
855         ret = mmc_unmount(UNMOUNT_NORMAL, path);
856
857 error:
858         reply = dbus_message_new_method_return(msg);
859         dbus_message_iter_init_append(reply, &iter);
860         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
861         return reply;
862 }
863
864 static DBusMessage *edbus_request_mount(E_DBus_Object *obj, DBusMessage *msg)
865 {
866         DBusMessageIter iter;
867         DBusMessage *reply;
868         struct mmc_data *pdata;
869         int ret;
870
871         if (!mmc_curpath) {
872                 ret = -ENODEV;
873                 goto error;
874         }
875
876         pdata = malloc(sizeof(struct mmc_data));
877         if (!pdata) {
878                 _E("malloc failed");
879                 ret = -errno;
880                 goto error;
881         }
882
883         pdata->devpath = strdup(mmc_curpath);
884         if (!pdata->devpath) {
885                 free(pdata);
886                 ret = -errno;
887                 goto error;
888         }
889
890         ret = (int)mount_start(pdata);
891
892 error:
893         reply = dbus_message_new_method_return(msg);
894         dbus_message_iter_init_append(reply, &iter);
895         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
896         return reply;
897 }
898
899 static DBusMessage *edbus_request_unmount(E_DBus_Object *obj, DBusMessage *msg)
900 {
901         DBusMessageIter iter;
902         DBusMessage *reply;
903         int opt, ret;
904         char params[NAME_MAX];
905         struct mmc_data *pdata;
906
907         ret = dbus_message_get_args(msg, NULL,
908                         DBUS_TYPE_INT32, &opt, DBUS_TYPE_INVALID);
909         if (!ret) {
910                 _I("there is no message");
911                 ret = -EBADMSG;
912                 goto error;
913         }
914
915         pdata = malloc(sizeof(struct mmc_data));
916         if (!pdata) {
917                 _E("malloc failed");
918                 ret = -errno;
919                 goto error;
920         }
921
922         pdata->option = opt;
923         ret = (int)unmount_start(pdata);
924
925 error:
926         reply = dbus_message_new_method_return(msg);
927         dbus_message_iter_init_append(reply, &iter);
928         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
929         return reply;
930 }
931
932 static DBusMessage *edbus_request_format(E_DBus_Object *obj, DBusMessage *msg)
933 {
934         DBusMessageIter iter;
935         DBusMessage *reply;
936         int opt, ret;
937         struct mmc_data *pdata;
938
939         ret = dbus_message_get_args(msg, NULL,
940                         DBUS_TYPE_INT32, &opt, DBUS_TYPE_INVALID);
941         if (!ret) {
942                 _I("there is no message");
943                 ret = -EBADMSG;
944                 goto error;
945         }
946
947         if (!mmc_curpath) {
948                 ret = -ENODEV;
949                 goto error;
950         }
951
952         pdata = malloc(sizeof(struct mmc_data));
953         if (!pdata) {
954                 _E("malloc failed");
955                 ret = -errno;
956                 goto error;
957         }
958
959         pdata->option = opt;
960         pdata->devpath = strdup(mmc_curpath);
961         if (!pdata->devpath) {
962                 free(pdata);
963                 ret = -errno;
964                 goto error;
965         }
966
967         ret = (int)format_start(pdata);
968
969 error:
970         reply = dbus_message_new_method_return(msg);
971         dbus_message_iter_init_append(reply, &iter);
972         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
973         return reply;
974 }
975
976 static DBusMessage *edbus_request_insert(E_DBus_Object *obj, DBusMessage *msg)
977 {
978         DBusMessageIter iter;
979         DBusMessage *reply;
980         char *devpath;
981         int ret;
982
983         ret = dbus_message_get_args(msg, NULL,
984                         DBUS_TYPE_STRING, &devpath, DBUS_TYPE_INVALID);
985         if (!ret) {
986                 _I("there is no message");
987                 ret = -EBADMSG;
988                 goto error;
989         }
990
991         ret = mmc_inserted(devpath);
992
993 error:
994         reply = dbus_message_new_method_return(msg);
995         dbus_message_iter_init_append(reply, &iter);
996         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
997         return reply;
998 }
999
1000 static DBusMessage *edbus_request_remove(E_DBus_Object *obj, DBusMessage *msg)
1001 {
1002         DBusMessageIter iter;
1003         DBusMessage *reply;
1004         int ret;
1005
1006         ret = mmc_removed();
1007
1008         reply = dbus_message_new_method_return(msg);
1009         dbus_message_iter_init_append(reply, &iter);
1010         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
1011         return reply;
1012 }
1013
1014 static DBusMessage *edbus_change_status(E_DBus_Object *obj, DBusMessage *msg)
1015 {
1016         DBusMessageIter iter;
1017         DBusMessage *reply;
1018         int opt, ret;
1019         char params[NAME_MAX];
1020         struct mmc_data *pdata;
1021
1022         ret = dbus_message_get_args(msg, NULL,
1023                         DBUS_TYPE_INT32, &opt, DBUS_TYPE_INVALID);
1024         if (!ret) {
1025                 _I("there is no message");
1026                 ret = -EBADMSG;
1027                 goto error;
1028         }
1029         if (opt == VCONFKEY_SYSMAN_MMC_MOUNTED)
1030                 mmc_mount_done();
1031 error:
1032         reply = dbus_message_new_method_return(msg);
1033         dbus_message_iter_init_append(reply, &iter);
1034         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
1035         return reply;
1036 }
1037
1038 int get_mmc_devpath(char devpath[])
1039 {
1040         if (mmc_disabled)
1041                 return -EWOULDBLOCK;
1042         if (!mmc_curpath)
1043                 return -ENODEV;
1044         snprintf(devpath, NAME_MAX, "%s", mmc_curpath);
1045         return 0;
1046 }
1047
1048 static const struct edbus_method edbus_methods[] = {
1049         { "RequestSecureMount",    "s", "i", edbus_request_secure_mount },
1050         { "RequestSecureUnmount",  "s", "i", edbus_request_secure_unmount },
1051         { "RequestMount",         NULL, "i", edbus_request_mount },
1052         { "RequestUnmount",        "i", "i", edbus_request_unmount },
1053         { "RequestFormat",         "i", "i", edbus_request_format },
1054         { "RequestInsert",         "s", "i", edbus_request_insert },
1055         { "RequestRemove",        NULL, "i", edbus_request_remove },
1056         { "ChangeStatus",          "i", "i", edbus_change_status },
1057 };
1058
1059 static int mmc_poweroff(void *data)
1060 {
1061         mmc_uevent_stop();
1062         return 0;
1063 }
1064
1065 static void mmc_init(void *data)
1066 {
1067         int ret;
1068
1069         mmc_load_config();
1070         ret = register_edbus_method(DEVICED_PATH_MMC, edbus_methods, ARRAY_SIZE(edbus_methods));
1071         if (ret < 0)
1072                 _E("fail to init edbus method(%d)", ret);
1073
1074         /* register mmc uevent control routine */
1075         ret = mmc_uevent_start();
1076         if (ret < 0)
1077                 _E("fail to mmc uevent start");
1078
1079         /* register notifier if mmc exist or not */
1080         register_notifier(DEVICE_NOTIFIER_POWEROFF, mmc_poweroff);
1081         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, mmc_booting_done);
1082         register_notifier(DEVICE_NOTIFIER_MMC, mmc_changed_cb);
1083 }
1084
1085 static void mmc_exit(void *data)
1086 {
1087         /* unregister notifier */
1088         unregister_notifier(DEVICE_NOTIFIER_POWEROFF, mmc_poweroff);
1089         unregister_notifier(DEVICE_NOTIFIER_MMC, mmc_changed_cb);
1090         unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, mmc_booting_done);
1091
1092         /* unregister mmc uevent control routine */
1093         mmc_uevent_stop();
1094 }
1095
1096 static int mmc_start(enum device_flags flags)
1097 {
1098         mmc_disabled = false;
1099         _I("start");
1100         return 0;
1101 }
1102
1103 static int mmc_stop(enum device_flags flags)
1104 {
1105         mmc_disabled = true;
1106         vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, VCONFKEY_SYSMAN_MMC_REMOVED);
1107         _I("stop");
1108         return 0;
1109 }
1110
1111 const struct device_ops mmc_device_ops = {
1112         .priority = DEVICE_PRIORITY_NORMAL,
1113         .name     = "mmc",
1114         .init     = mmc_init,
1115         .exit     = mmc_exit,
1116         .start    = mmc_start,
1117         .stop     = mmc_stop,
1118 };
1119
1120 DEVICE_OPS_REGISTER(&mmc_device_ops)