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