Fix usage of strerror_r()
[platform/core/appfw/app2sd.git] / plugin / app2sd / server / app2sd_internals.c
1 /*
2  * app2ext
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Garima Shrivastava<garima.s@samsung.com>
7  *      Jyotsna Dhumale <jyotsna.a@samsung.com>
8  *      Venkatesha Sarpangala <sarpangala.v@samsung.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */
23
24 #define _GNU_SOURCE
25 #include <dirent.h>
26 #include <time.h>
27 #include <pwd.h>
28
29 #include "app2sd_internals.h"
30
31 #define DMCRYPT_ITER_TIME       50
32 #define DMCRYPT_KEY_LEN         128
33
34 static int _app2sd_make_directory(const char *path, uid_t uid)
35 {
36         int ret;
37         int fd;
38         mode_t mode = DIR_PERMS;
39         struct passwd pwd;
40         struct passwd *pwd_result;
41         char buf[1024];
42
43         ret = _app2sd_delete_directory(path);
44         if (ret) {
45                 _E("unable to delete (%s), errno(%d)", path, errno);
46                 return APP2EXT_ERROR_DELETE_DIRECTORY;
47         }
48
49         ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwd_result);
50         if (ret != 0 || pwd_result == NULL) {
51                 _E("get uid failed(%d)", ret);
52                 return APP2EXT_ERROR_ACCESS_FILE;
53         }
54         _D("uid(%d), gid(%d)", uid, pwd.pw_gid);
55
56         /* create directory */
57         ret = mkdir(path, mode);
58         if (ret) {
59                 if (errno != EEXIST) {
60                         _E("create directory failed, error is (%d)", errno);
61                         return APP2EXT_ERROR_CREATE_DIRECTORY;
62                 }
63         }
64
65         fd = open(path, O_RDONLY|O_DIRECTORY);
66         if (fd < 0) {
67                 _E("can't open path(%s)", path);
68                 return APP2EXT_ERROR_OPEN_DIR;
69         }
70
71         ret = fchmod(fd, 0755);
72         if (ret < 0) {
73                 _E("change file permission error");
74                 close(fd);
75                 return APP2EXT_ERROR_ACCESS_FILE;
76         }
77
78         ret = fchown(fd, uid, pwd.pw_gid);
79         if (ret < 0) {
80                 _E("change file owner error");
81                 close(fd);
82                 return APP2EXT_ERROR_ACCESS_FILE;
83         }
84
85         close(fd);
86
87         return APP2EXT_SUCCESS;
88 }
89
90 int _app2sd_dmcrypt_setup_device(const char *pkgid,
91                 const char *loopback_device, bool is_dup, uid_t uid)
92 {
93         int ret;
94         char *passwd;
95         char dmcrypt_setup_cmd[BUF_SIZE];
96         char err_buf[BUF_SIZE];
97         const char *err_str;
98
99         if (pkgid == NULL || loopback_device == NULL) {
100                 _E("invalid argument");
101                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
102         }
103
104         /* get password for dmcrypt encryption */
105         ret = _app2sd_initialize_db();
106         if (ret) {
107                 _E("app2sd db initialize failed");
108                 return APP2EXT_ERROR_DB_INITIALIZE;
109         }
110
111         passwd = _app2sd_get_password_from_db(pkgid, uid);
112         if (passwd == NULL) {
113                 if (is_dup) {
114                         _E("no password found for (%s)", pkgid);
115                         return APP2EXT_ERROR_SQLITE_REGISTRY;
116                 }
117                 passwd = _app2sd_generate_password();
118                 if (passwd == NULL) {
119                         _E("unable to generate password");
120                         return APP2EXT_ERROR_PASSWD_GENERATION;
121                 }
122
123                 ret = _app2sd_set_info_in_db(pkgid, passwd, loopback_device,
124                                 uid);
125                 if (ret < 0) {
126                         _E("unable to save password");
127                         free(passwd);
128                         return APP2EXT_ERROR_SQLITE_REGISTRY;
129                 }
130         }
131
132         snprintf(dmcrypt_setup_cmd, sizeof(dmcrypt_setup_cmd),
133                         "/bin/echo '%s' | /sbin/cryptsetup -q -i %d "
134                         "-c aes-cbc-lmk -s %d --align-payload=8 luksFormat %s",
135                         passwd, DMCRYPT_ITER_TIME, DMCRYPT_KEY_LEN,
136                         loopback_device);
137         free(passwd);
138         ret = system(dmcrypt_setup_cmd);
139         if (ret) {
140                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
141                 _E("Error setting up dmcrypt on app2sd file, error:%s, ret:%d",
142                                 err_str, ret);
143                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
144         }
145
146         return ret;
147 }
148
149 int _app2sd_dmcrypt_open_device(const char *pkgid, const char *loopback_device,
150                 bool is_dup, uid_t uid, char **dev_node)
151 {
152         int ret;
153         char *passwd;
154         char dmcrypt_open_cmd[BUF_SIZE];
155         char dev_name[BUF_SIZE];
156         char buf[BUF_SIZE];
157         const char *err_str;
158
159         if (pkgid == NULL || loopback_device == NULL) {
160                 _E("invalid argument");
161                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
162         }
163
164         if (is_dup)
165                 snprintf(dev_name, sizeof(dev_name), "%s.new_%d", pkgid, uid);
166         else
167                 snprintf(dev_name, sizeof(dev_name), "%s_%d", pkgid, uid);
168
169         /* get password for dmcrypt encryption */
170         ret = _app2sd_initialize_db();
171         if (ret) {
172                 _E("app2sd db initialize failed");
173                 return APP2EXT_ERROR_DB_INITIALIZE;
174         }
175
176         passwd = _app2sd_get_password_from_db(pkgid, uid);
177         if (passwd == NULL) {
178                 _E("no password found for [%s]", pkgid);
179                 return APP2EXT_ERROR_SQLITE_REGISTRY;
180         }
181
182         if (_app2sd_check_is_luks_device(loopback_device) == 0) {
183                 _W("legacy image format!");
184                 snprintf(dmcrypt_open_cmd, sizeof(dmcrypt_open_cmd),
185                                 "/bin/echo '%s' | /sbin/cryptsetup "
186                                 "-M plain -c aes-cbc-plain -h plain open %s %s",
187                                 passwd, loopback_device, dev_name);
188         } else {
189                 snprintf(dmcrypt_open_cmd, sizeof(dmcrypt_open_cmd),
190                                 "/bin/echo '%s' | /sbin/cryptsetup -q luksOpen "
191                                 "%s %s",
192                                 passwd, loopback_device, dev_name);
193         }
194         free(passwd);
195
196         ret = system(dmcrypt_open_cmd);
197         if (ret) {
198                 err_str = strerror_r(errno, buf, sizeof(buf));
199                 _E("error opening dmcrypt device, error: [%s]", err_str);
200                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
201         }
202
203         snprintf(buf, sizeof(buf), "/dev/mapper/%s", dev_name);
204         *dev_node = strdup(buf);
205         if (*dev_node == NULL) {
206                 _E("memory alloc failed");
207                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
208         }
209
210         return ret;
211 }
212
213 int _app2sd_dmcrypt_close_device(const char *pkgid, uid_t uid)
214 {
215         int ret;
216         char dev_node[BUF_SIZE];
217         char dmcrypt_close_cmd[BUF_SIZE];
218         char err_buf[BUF_SIZE];
219         const char *err_str;
220         char *t_dev_node;
221
222         if (pkgid == NULL) {
223                 _E("invalid argument");
224                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
225         }
226
227         t_dev_node = _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
228         if (!t_dev_node) {
229                 _W("no associated device node(%s_%d) found", pkgid, uid);
230                 return APP2EXT_ERROR_DMCRYPT_DEVICE_UNAVAILABLE;
231         }
232
233         free(t_dev_node);
234
235         snprintf(dev_node, sizeof(dev_node), "/dev/mapper/%s_%d", pkgid, uid);
236         snprintf(dmcrypt_close_cmd, sizeof(dmcrypt_close_cmd),
237                         "/sbin/cryptsetup -q luksClose %s", dev_node);
238         ret = system(dmcrypt_close_cmd);
239         if (ret) {
240                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
241                 _E("error closing dmcrypt on app2sd file: %s", err_str);
242                 return APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
243         }
244
245         return ret;
246 }
247
248 char *_app2sd_find_associated_dmcrypt_device_node(const char *pkgid, uid_t uid)
249 {
250         char *dev_node;
251         char buf[BUF_SIZE];
252
253         snprintf(buf, sizeof(buf), "/dev/mapper/%s_%d", pkgid, uid);
254         if (access(buf, F_OK) == 0) {
255                 dev_node = strdup(buf);
256                 if (dev_node == NULL) {
257                         _E("memory alloc failed");
258                         return NULL;
259                 }
260                 _D("device_node: (%s)", dev_node);
261                 return dev_node;
262         }
263         _D("can not access dev_node(%s), errno(%d)", buf, errno);
264
265         return NULL;
266 }
267
268 char *_app2sd_dmcrypt_duplicate_encryption_setup(const char *pkgid,
269                 const char *temp_loopback_device, uid_t uid)
270 {
271         int ret;
272         char *device_node;
273
274         if (pkgid == NULL || temp_loopback_device == NULL) {
275                 _E("invalid argument");
276                 return NULL;
277         }
278
279         ret = _app2sd_dmcrypt_setup_device(pkgid, temp_loopback_device, true,
280                         uid);
281         if (ret) {
282                 _E("dmcrypt setup device error(%d)", ret);
283                 return NULL;
284         }
285
286         ret = _app2sd_dmcrypt_open_device(pkgid, temp_loopback_device, true,
287                         uid, &device_node);
288         if (ret) {
289                 _E("dmcrypt open device error");
290                 return NULL;
291         }
292
293         return device_node;
294 }
295
296 int _app2sd_create_loopback_device(const char *pkgid,
297                 const char *loopback_device, int size)
298 {
299         int ret;
300         char command[FILENAME_MAX];
301         char buff[BUF_SIZE];
302         FILE *fp;
303         const char *argv[] = { "/bin/dd", "if=/dev/zero", command,
304                 "bs=1M", buff, NULL };
305
306         if (pkgid == NULL || size <= 0) {
307                 _E("invalid argument");
308                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
309         }
310
311         fp = fopen(loopback_device, "r+");
312         if (fp != NULL) {
313                 _W("encrypted file already exists (%s)", loopback_device);
314                 fclose(fp);
315                 return APP2EXT_ERROR_PKG_EXISTS;
316         }
317
318         snprintf(command, sizeof(command), "of=%s", loopback_device);
319         snprintf(buff, sizeof(buff), "count=%d", size);
320
321         ret = _xsystem(argv);
322         if (ret)
323                 _E("command (%s) failed, ret(%d), errno(%d)",
324                                 command, ret, errno);
325
326         return ret;
327 }
328
329 int _app2sd_delete_loopback_device(const char *loopback_device)
330 {
331         int ret;
332
333         ret = unlink(loopback_device);
334         if (ret) {
335                 if (errno == ENOENT) {
336                         _W("unable to access file (%s)", loopback_device);
337                 } else {
338                         _E("unable to delete (%s)", loopback_device);
339                         return APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
340                 }
341         }
342
343         return APP2EXT_SUCCESS;
344 }
345
346 int _app2sd_create_file_system(const char *device_path)
347 {
348         int ret;
349         FILE *fp;
350         char err_buf[1024];
351         const char *err_str;
352         const char *argv[] = { "/sbin/mkfs.ext4", device_path, NULL };
353
354         if (device_path == NULL) {
355                 _E("invalid param");
356                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
357         }
358
359         /* Format the filesystem [create a filesystem]*/
360         fp = fopen(device_path, "r+");
361         if (fp == NULL) {
362                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
363                 _E("unable to access (%s) error is (%d, %s)",
364                                 device_path, errno, err_buf);
365                 return APP2EXT_ERROR_ACCESS_FILE;
366         }
367         fclose(fp);
368
369         ret = _xsystem(argv);
370         if (ret) {
371                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
372                 _E("creating file system failed, error is (%s)", err_str);
373                 return APP2EXT_ERROR_CREATE_FS;
374         }
375         return ret;
376 }
377
378 static int _app2sd_create_dir_with_link(const char *application_path,
379                 const char *pkgid, const char *dir_name, uid_t uid)
380 {
381         int ret;
382         char app_dir_mmc_path[FILENAME_MAX];
383         char app_dir_path[FILENAME_MAX];
384
385         snprintf(app_dir_mmc_path, sizeof(app_dir_mmc_path), "%s/.mmc/%s",
386                         application_path, dir_name);
387         snprintf(app_dir_path, sizeof(app_dir_path), "%s/%s",
388                         application_path, dir_name);
389
390         ret = _app2sd_make_directory(app_dir_mmc_path, uid);
391         if (ret) {
392                 _E("create directory failed");
393                 return APP2EXT_ERROR_CREATE_DIRECTORY;
394         }
395
396         ret = symlink(app_dir_mmc_path, app_dir_path);
397         if (ret < 0) {
398                 if (errno == EEXIST) {
399                         _D("file with symlink name present (%s)", app_dir_path);
400                 } else {
401                         _E("symbolic link creation failed, error: %d", errno);
402                         return APP2EXT_ERROR_CREATE_SYMLINK;
403                 }
404         }
405
406         return APP2EXT_SUCCESS;
407 }
408
409 static int _app2sd_create_directory_entry(const char *application_path,
410                 const char *pkgid, GList *dir_list, uid_t uid)
411 {
412         int ret;
413         GList *list;
414         app2ext_dir_details *dir_detail;
415
416         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
417                 dir_detail = (app2ext_dir_details *)list->data;
418                 if (dir_detail == NULL || dir_detail->name == NULL ||
419                                 dir_detail->type != APP2EXT_DIR_RO)
420                         continue;
421                 ret = _app2sd_create_dir_with_link(application_path,
422                                 pkgid, dir_detail->name, uid);
423                 if (ret)
424                         return ret;
425         }
426         return APP2EXT_SUCCESS;
427 }
428
429 int _app2sd_mount_app_content(const char *application_path, const char *pkgid,
430                 const char *dev, int mount_type, GList *dir_list,
431                 app2sd_cmd cmd, uid_t uid)
432 {
433         int ret;
434         int fd;
435         char app_mmc_path[FILENAME_MAX];
436         char temp_path[FILENAME_MAX];
437         char err_buf[1024];
438         const char *err_str;
439         struct timespec time = {
440                 .tv_sec = 0,
441                 .tv_nsec = 1000 * 1000 * 200
442         };
443         char mountflags_str[BUF_SIZE];
444         const char *argv_mount[] = { "/bin/app2sd-mount-helper", dev,
445                 app_mmc_path, FS_TYPE, mountflags_str, NULL };
446
447         if (dev == NULL) {
448                 _E("input param is NULL (%s)", dev);
449                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
450         }
451
452         /* check directory existence */
453         fd = open(application_path, O_RDONLY | O_DIRECTORY);
454         if (fd < 0) {
455                 _E("path(%s) error(%d)", application_path, errno);
456                 return APP2EXT_ERROR_OPEN_DIR;
457         }
458         close(fd);
459
460         snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
461                         application_path);
462         fd = open(app_mmc_path, O_RDONLY | O_DIRECTORY);
463         if (fd < 0) {
464                 _E("path(%s) error(%d)", app_mmc_path, errno);
465                 return APP2EXT_ERROR_OPEN_DIR;
466         }
467         close(fd);
468
469         nanosleep(&time, NULL); /* 200ms sleep */
470         _D("give a delay for mount");
471
472         switch (mount_type) {
473         case MOUNT_TYPE_RD:
474                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
475                                 MS_MGC_VAL | MS_RDONLY | MS_NOSUID);
476                 ret = _xsystem(argv_mount);
477                 if (ret) {
478                         _E("read only mount failed, errono is (%d), "
479                                         "dev is (%s) path is (%s)",
480                                         ret, dev, app_mmc_path);
481                         ret = APP2EXT_ERROR_MOUNT;
482                 }
483                 break;
484         case MOUNT_TYPE_RW:
485                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
486                                 MS_MGC_VAL | MS_NOSUID);
487                 ret = _xsystem(argv_mount);
488                 if (ret) {
489                         _E("read write mount failed, errno is (%d)", ret);
490                         ret = APP2EXT_ERROR_MOUNT;
491                 }
492                 break;
493         case MOUNT_TYPE_RW_NOEXEC:
494                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
495                                 MS_MGC_VAL | MS_NOEXEC | MS_NOSUID);
496                 ret = _xsystem(argv_mount);
497                 if (ret) {
498                         _E("rwnx mount failed errno is (%d)", ret);
499                         ret = APP2EXT_ERROR_MOUNT;
500                 }
501                 break;
502         case MOUNT_TYPE_RD_REMOUNT:
503                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
504                                 MS_MGC_VAL | MS_RDONLY | MS_REMOUNT |
505                                 MS_NOSUID);
506                 ret = _xsystem(argv_mount);
507                 if (ret) {
508                         _E("read remount failed errno is (%d)", ret);
509                         ret = APP2EXT_ERROR_MOUNT;
510                 }
511                 break;
512         case MOUNT_TYPE_RW_REMOUNT:
513                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
514                                 MS_MGC_VAL | MS_REMOUNT | MS_NOSUID);
515                 ret = _xsystem(argv_mount);
516                 err_str = strerror_r(ret, err_buf, sizeof(err_buf));
517                 if (ret) {
518                         _E("read write remount failed errno(%d), errstr(%s)",
519                                         ret, err_str);
520                         ret = APP2EXT_ERROR_MOUNT;
521                 }
522                 break;
523         default:
524                 _E("invalid mount type");
525                 break;
526         }
527
528         if (cmd == APP2SD_PRE_INSTALL || cmd == APP2SD_MOVE_APP_TO_MMC ||
529                         cmd == APP2SD_PRE_UPGRADE) {
530                 ret = _app2sd_create_directory_entry(application_path,
531                                 pkgid, dir_list, uid);
532         }
533
534         if (mount_type != MOUNT_TYPE_RD &&
535                         mount_type != MOUNT_TYPE_RD_REMOUNT) {
536                 /* change lost+found permission */
537                 snprintf(temp_path, sizeof(temp_path), "%s/lost+found",
538                                 app_mmc_path);
539                 ret = _app2sd_make_directory(temp_path, uid);
540                 if (ret) {
541                         _E("create directory(%s) failed", temp_path);
542                         return APP2EXT_ERROR_CREATE_DIRECTORY;
543                 }
544         }
545
546         return ret;
547 }
548
549 int _app2sd_unmount_app_content(const char *application_path)
550 {
551         int ret;
552         char app_mmc_path[FILENAME_MAX];
553         char err_buf[1024];
554         const char *err_str;
555
556         snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
557                         application_path);
558         ret = umount(app_mmc_path);
559         if (ret < 0) {
560                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
561                 _D("unable to umount the dir, ret(%d) error(%d, %s)",
562                                 ret, errno, err_str);
563         }
564
565         return ret;
566 }
567
568 static int _app2sd_move_to_archive(const char *src_path, const char *arch_path)
569 {
570         int ret;
571         char err_buf[1024];
572         const char *err_str;
573
574         ret = _app2sd_copy_dir(src_path, arch_path);
575         if (ret && ret != APP2EXT_ERROR_ACCESS_FILE) {
576                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
577                 _E("unable to copy from (%s) to (%s), err is (%s)",
578                                 src_path, arch_path, err_str);
579                 return APP2EXT_ERROR_MOVE;
580         }
581
582         ret = _app2sd_delete_directory(src_path);
583         if (ret) {
584                 _E("unable to delete (%s)", src_path);
585                 return APP2EXT_ERROR_DELETE_DIRECTORY;
586         }
587
588         return ret;
589 }
590
591 static int _app2sd_move_app_to_external(const char *pkgid, GList *dir_list,
592                 uid_t uid, char *mmc_path, char **image_path)
593 {
594         int ret;
595         mode_t mode = DIR_PERMS;
596         char temp_dir_path[FILENAME_MAX];
597         char app_mmc_path[FILENAME_MAX];
598         char app_archive_path[FILENAME_MAX];
599         char application_path[FILENAME_MAX];
600         char loopback_device[FILENAME_MAX];
601         unsigned long long total_size = 0;
602         int reqd_size;
603         int reqd_disk_size;
604         char *device_node;
605         int free_mmc_mem;
606         FILE *fp;
607         GList *list;
608         app2ext_dir_details *dir_detail;
609         char err_buf[1024];
610         const char *err_str;
611
612         ret = _app2sd_get_loopback_device_path(mmc_path, pkgid, uid,
613                         loopback_device, sizeof(loopback_device));
614         if (ret)
615                 return ret;
616
617         _app2sd_set_application_path(pkgid, uid, application_path,
618                         sizeof(application_path));
619
620         /* check whether application is in external memory or not */
621         fp = fopen(loopback_device, "r+");
622         if (fp != NULL) {
623                 _W("Already %s entry is present in the SD Card, "
624                                 "delete entry and go on without return", pkgid);
625                 fclose(fp);
626                 _app2sd_force_clean(pkgid, application_path, loopback_device,
627                                 uid);
628         }
629
630         snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
631                         application_path);
632         snprintf(app_archive_path, sizeof(app_archive_path), "%s/.archive",
633                         application_path);
634
635         ret = mkdir(app_mmc_path, mode);
636         if (ret) {
637                 if (errno != EEXIST) {
638                         _E("unable to create directory for archiving,"
639                                         " error(%d)", errno);
640                         return APP2EXT_ERROR_CREATE_DIRECTORY;
641                 }
642         }
643
644         ret = mkdir(app_archive_path, mode);
645         if (ret) {
646                 if (errno != EEXIST) {
647                         _E("unable to create directory for archiving,"
648                                         " error(%d)", errno);
649                         return APP2EXT_ERROR_CREATE_DIRECTORY;
650                 }
651         }
652
653         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
654                 dir_detail = (app2ext_dir_details *)list->data;
655                 if (dir_detail == NULL || dir_detail->name == NULL ||
656                                 dir_detail->type != APP2EXT_DIR_RO)
657                         continue;
658                 snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
659                                 application_path, dir_detail->name);
660                 _D("cal size of app dirs, temp_dir_path(%s)", temp_dir_path);
661                 total_size += _app2sd_calculate_dir_size(temp_dir_path);
662         }
663
664         reqd_size = ((total_size) / (1024 * 1024)) + 2;
665         reqd_disk_size = reqd_size + ceil(reqd_size * 0.2);
666
667         /* find avialable free memory in the MMC card */
668         ret = _app2sd_get_available_free_memory(mmc_path, &free_mmc_mem);
669         if (ret) {
670                 _E("unable to get available free memory in MMC (%d)", ret);
671                 return APP2EXT_ERROR_MMC_STATUS;
672         }
673         /* if avaialalbe free memory in MMC is less than
674          * required size + 5MB, return error
675          */
676         if (reqd_disk_size > free_mmc_mem) {
677                 _E("insufficient memory in MMC for "
678                                 "application installation (%d)", ret);
679                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
680         }
681         /* create a loopback device */
682         ret = _app2sd_create_loopback_device(pkgid, loopback_device,
683                         (reqd_disk_size + PKG_BUF_SIZE));
684         if (ret) {
685                 _E("loopback node creation failed");
686                 return ret;
687         }
688
689         ret = _app2sd_dmcrypt_setup_device(pkgid, loopback_device, false, uid);
690         if (ret) {
691                 _E("dmcrypt setup device error(%d)", ret);
692                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
693         }
694
695         ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device, false,
696                         uid, &device_node);
697         if (ret) {
698                 _E("dmcrypt open device error");
699                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
700         }
701         /* format the loopback file system */
702         ret = _app2sd_create_file_system(device_node);
703         if (ret) {
704                 _E("create ext4 filesystem failed");
705                 ret = APP2EXT_ERROR_CREATE_FS;
706                 goto ERR;
707         }
708
709         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
710                 dir_detail = (app2ext_dir_details *)list->data;
711                 if (dir_detail == NULL || dir_detail->name == NULL ||
712                                 dir_detail->type != APP2EXT_DIR_RO)
713                         continue;
714                 snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
715                                 application_path, dir_detail->name);
716                 _D("app2archive, temp_dir_path(%s)", temp_dir_path);
717                 ret = _app2sd_move_to_archive(temp_dir_path, app_archive_path);
718                 if (ret) {
719                         _E("unable to copy from (%s) to (%s)",
720                                         temp_dir_path, app_archive_path);
721                         goto ERR;
722                 }
723         }
724
725         /* mount the loopback encrypted pseudo device on
726          * application installation path as with Read Write permission
727          */
728         ret = _app2sd_mount_app_content(application_path, pkgid, device_node,
729                         MOUNT_TYPE_RW, dir_list, APP2SD_MOVE_APP_TO_MMC, uid);
730         if (ret) {
731                 _E("mount failed");
732                 goto ERR;
733         }
734
735         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
736                 dir_detail = (app2ext_dir_details *)list->data;
737                 if (dir_detail == NULL || dir_detail->name == NULL ||
738                                 dir_detail->type != APP2EXT_DIR_RO)
739                         continue;
740                 snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
741                                 app_archive_path, dir_detail->name);
742                 _D("archive2mmc, temp_dir_path(%s)", temp_dir_path);
743                 ret = _app2sd_copy_dir(temp_dir_path, app_mmc_path);
744                 if (ret) {
745                         if (ret == APP2EXT_ERROR_ACCESS_FILE) {
746                                 _E("unable to access (%s)", temp_dir_path);
747                         } else {
748                                 err_str = strerror_r(errno, err_buf,
749                                                 sizeof(err_buf));
750                                 _E("unable to copy from (%s) to (%s),"
751                                                 " error is (%s)", temp_dir_path,
752                                                 app_mmc_path, err_str);
753                         }
754                         goto ERR;
755                 }
756                 ret = _app2sd_delete_directory(temp_dir_path);
757                 if (ret) {
758                         _E("unable to delete (%s)", temp_dir_path);
759                         goto ERR;
760                 }
761         }
762
763         ret = _app2sd_delete_directory(app_archive_path);
764         if (ret) {
765                 _E("unable to delete (%s)", app_archive_path);
766                 ret = APP2EXT_ERROR_DELETE_DIRECTORY;
767                 goto ERR;
768         }
769
770         *image_path = strdup(loopback_device);
771         return APP2EXT_SUCCESS;
772
773 ERR:
774         if (device_node)
775                 free(device_node);
776
777         *image_path = NULL;
778         return ret;
779 }
780
781 static int _app2sd_move_app_to_internal(const char *pkgid, GList *dir_list,
782                 uid_t uid, char *mmc_path)
783 {
784         int ret;
785         mode_t mode = DIR_PERMS;
786         char temp_dir_path[FILENAME_MAX];
787         char app_mmc_path[FILENAME_MAX];
788         char app_archive_path[FILENAME_MAX];
789         char application_path[FILENAME_MAX];
790         char loopback_device[FILENAME_MAX];
791         char *device_node;
792         FILE *fp;
793         GList *list;
794         app2ext_dir_details *dir_detail;
795         int reqd_size;
796         int free_internal_mem;
797         unsigned long long temp = 0;
798         char err_buf[1024];
799         const char *err_str;
800         int mount_type;
801
802         ret = _app2sd_get_loopback_device_path(mmc_path, pkgid, uid,
803                         loopback_device, sizeof(loopback_device));
804         if (ret)
805                 return ret;
806
807         _app2sd_set_application_path(pkgid, uid, application_path,
808                 sizeof(application_path));
809
810         /* check whether application is in external memory or not */
811         fp = fopen(loopback_device, "r+");
812         if (fp == NULL) {
813                 _E("application (%s) is not installed on SD Card",
814                      pkgid);
815                 return APP2EXT_ERROR_FILE_ABSENT;
816         }
817         fclose(fp);
818
819         /* find avialable free memory in the internal storage */
820         ret = _app2sd_get_available_free_memory(INTERNAL_STORAGE_PATH,
821                         &free_internal_mem);
822         if (ret) {
823                 _E("unable to get available free memory in internal (%d)", ret);
824                 return APP2EXT_ERROR_MMC_STATUS;
825         }
826
827         fp = fopen(loopback_device, "r+");
828         if (fp == NULL) {
829                 _E("app entry is not present in SD card");
830                 return APP2EXT_ERROR_INVALID_PACKAGE;
831         }
832         fclose(fp);
833
834         /* get installed app size*/
835         temp = _app2sd_calculate_file_size(loopback_device);
836         reqd_size = (int)((temp) / (1024 * 1024));
837         _D("reqd size is (%d)", reqd_size);
838
839         if (reqd_size == 0) {
840                 _E("app entry is not present in SD Card");
841                 return APP2EXT_ERROR_LOOPBACK_DEVICE_UNAVAILABLE;
842         }
843
844         _I("reqd size: (%d)MB, free internal mem: (%d)MB",
845                         reqd_size, free_internal_mem);
846
847         /* if avaialalbe free memory in internal storage is
848          * less than required size, return error
849          */
850         if (reqd_size > free_internal_mem) {
851                 _E("innsufficient memory in internal storage"
852                         " for application installation (%d)", ret);
853                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
854         }
855
856         device_node =
857                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
858         if (device_node == NULL) {
859                 /* do loopback setup */
860                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
861                                 false, uid, &device_node);
862                 if (ret) {
863                         _E("dmcrypt open device error(%d)", ret);
864                         return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
865                 }
866                 mount_type = MOUNT_TYPE_RW;
867         } else {
868                 mount_type = MOUNT_TYPE_RW_REMOUNT;
869         }
870         /* do mounting */
871         ret = _app2sd_mount_app_content(application_path,
872                         pkgid, device_node, mount_type,
873                         dir_list, APP2SD_MOVE_APP_TO_PHONE, uid);
874         if (ret) {
875                 _E("mount failed");
876                 ret = APP2EXT_ERROR_MOUNT_PATH;
877                 goto ERR;
878         }
879
880         snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
881                         application_path);
882         snprintf(app_archive_path, sizeof(app_archive_path), "%s/.archive",
883                         application_path);
884
885         ret = mkdir(app_archive_path, mode);
886         if (ret) {
887                 if (errno != EEXIST) {
888                         _E("unable to create directory for archiving,"
889                                         " error(%d)", errno);
890                         ret = APP2EXT_ERROR_CREATE_DIRECTORY;
891                         goto ERR;
892                 }
893         }
894
895         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
896                 dir_detail = (app2ext_dir_details *)list->data;
897                 if (dir_detail == NULL || dir_detail->name == NULL ||
898                                 dir_detail->type != APP2EXT_DIR_RO)
899                         continue;
900                 /* archiving code */
901                 snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
902                                 app_mmc_path, dir_detail->name);
903                 _D("mmc2archive, temp_dir_path(%s)", temp_dir_path);
904                 ret = _app2sd_copy_dir(temp_dir_path, app_archive_path);
905                 if (ret) {
906                         if (ret == APP2EXT_ERROR_ACCESS_FILE) {
907                                 _E("unable to access (%s)", temp_dir_path);
908                         } else {
909                                 err_str = strerror_r(errno, err_buf,
910                                                 sizeof(err_buf));
911                                 _E("unable to copy from (%s) to (%s),"
912                                                 "error is (%s)", temp_dir_path,
913                                                 app_archive_path, err_str);
914                         }
915                         goto ERR;
916                 }
917                 /* delete the symbolic link files [bin, lib, res]*/
918                 snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
919                                 application_path, dir_detail->name);
920                 _D("unlink, temp_dir_path(%s)", temp_dir_path);
921                 ret = unlink(temp_dir_path);
922                 if (ret) {
923                         if (errno == ENOENT) {
924                                 _W("(%s) does not exist", temp_dir_path);
925                         } else {
926                                 _E("unable to remove the symbolic link file "
927                                                 "(%s), it is already unlinked",
928                                                 temp_dir_path);
929                                 goto ERR;
930                         }
931                 }
932                 /* Copy content to destination */
933                 snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
934                                 app_archive_path, dir_detail->name);
935                 _D("archive2app, temp_dir_path(%s)", temp_dir_path);
936                 ret = _app2sd_copy_dir(temp_dir_path, application_path);
937                 if (ret) {
938                         if (ret == APP2EXT_ERROR_ACCESS_FILE) {
939                                 _E("unable to access (%s)", temp_dir_path);
940                         } else {
941                                 err_str = strerror_r(errno, err_buf,
942                                                 sizeof(err_buf));
943                                 _E("unable to copy from (%s) to (%s), "
944                                                 "error is (%s)", temp_dir_path,
945                                                 application_path, err_str);
946                         }
947                         goto ERR;
948                 }
949         }
950
951         _D("copying file completed");
952         ret = _app2sd_unmount_app_content(application_path);
953         if (ret)
954                 _E("unable to unmount SD directory for app (%s)", pkgid);
955
956         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
957         if (ret)
958                 _E("close dmcrypt device error(%d)", ret);
959
960         ret = _app2sd_delete_loopback_device(loopback_device);
961         if (ret)
962                 _E("unable to delete the loopback device for (%s)", pkgid);
963
964         ret = _app2sd_delete_directory(app_mmc_path);
965         if (ret)
966                 _E("unable to delete (%s)", app_mmc_path);
967
968         ret = _app2sd_delete_directory(app_archive_path);
969         if (ret)
970                 _E("unable to delete (%s)", app_archive_path);
971
972         /* remove passwrd from DB */
973         ret = _app2sd_initialize_db();
974         if (ret)
975                 _E("app2sd db initialize failed");
976
977         ret = _app2sd_remove_info_from_db(pkgid, uid);
978         if (ret)
979                 _E("cannot remove info from db");
980
981         return APP2EXT_SUCCESS;
982
983 ERR:
984         if (device_node)
985                 free(device_node);
986
987         return ret;
988 }
989
990 int _app2sd_usr_move_app(const char *pkgid, app2ext_move_type move_type,
991                 GList *dir_list, uid_t uid, char *mmc_path, char **image_path)
992 {
993         int ret;
994
995         switch (move_type) {
996         case APP2EXT_MOVE_TO_EXT:
997                 ret = _app2sd_move_app_to_external(pkgid, dir_list,
998                                 uid, mmc_path, image_path);
999                 if (ret) {
1000                         _E("move app to external memory failed(%d)", ret);
1001                         return ret;
1002                 }
1003                 break;
1004         case APP2EXT_MOVE_TO_PHONE:
1005                 ret = _app2sd_move_app_to_internal(pkgid, dir_list,
1006                                 uid, mmc_path);
1007                 if (ret) {
1008                         _E("move app to internal memory failed(%d)", ret);
1009                         return ret;
1010                 }
1011                 break;
1012         default:
1013                 _E("invalid argument");
1014                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
1015         }
1016
1017         return ret;
1018 }
1019
1020 int _app2sd_copy_ro_content(const char *src, const char *dest, GList *dir_list)
1021 {
1022         char path[FILENAME_MAX];
1023         int ret;
1024         GList *list;
1025         app2ext_dir_details *dir_detail;
1026
1027         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
1028                 dir_detail = (app2ext_dir_details *)list->data;
1029                 if (dir_detail == NULL || dir_detail->name == NULL ||
1030                                 dir_detail->type != APP2EXT_DIR_RO)
1031                         continue;
1032
1033                 snprintf(path, sizeof(path), "%s/%s", src, dir_detail->name);
1034                 ret = _app2sd_copy_dir(path, dest);
1035                 if (ret) {
1036                         if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1037                                 _E("unable to access (%s)", path);
1038                         } else {
1039                                 _E("unable to copy from (%s) "
1040                                                 "to (%s), errno is (%d)",
1041                                                 path, dest, errno);
1042                                 return APP2EXT_ERROR_MOVE;
1043                         }
1044                 }
1045         }
1046
1047         return APP2EXT_SUCCESS;
1048 }
1049
1050 int _app2sd_duplicate_device(const char *pkgid, const char *loopback_device,
1051                 const char *temp_pkgid, const char *temp_application_path,
1052                 const char *temp_loopback_device, GList *dir_list,
1053                 char *dev_node, int size, uid_t uid)
1054 {
1055         int ret;
1056         int err_res;
1057
1058         /* create a new loopback device */
1059         ret = _app2sd_create_loopback_device(temp_pkgid,
1060                         temp_loopback_device, (size + PKG_BUF_SIZE));
1061         if (ret) {
1062                 _E("package already present");
1063                 return ret;
1064         }
1065
1066         /* perform loopback encryption setup */
1067         dev_node = _app2sd_dmcrypt_duplicate_encryption_setup(pkgid,
1068                         temp_loopback_device, uid);
1069         if (!dev_node) {
1070                 _E("dmcrypt duplicate encryption setup failed");
1071                 _app2sd_delete_loopback_device(temp_loopback_device);
1072                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
1073         }
1074
1075         /* format the loopback file system */
1076         ret = _app2sd_create_file_system(dev_node);
1077         if (ret) {
1078                 _E("creating fs failed");
1079                 err_res = APP2EXT_ERROR_CREATE_FS;
1080                 goto FINISH_OFF;
1081         }
1082         _D("create filesystem SUCCESS");
1083
1084         /* do mounting for new dev*/
1085         ret = _app2sd_mount_app_content(temp_application_path, pkgid,
1086                         dev_node, MOUNT_TYPE_RW, dir_list,
1087                         APP2SD_PRE_UPGRADE, uid);
1088         if (ret) {
1089                 _E("remount failed");
1090                 err_res = APP2EXT_ERROR_MOUNT_PATH;
1091                 goto FINISH_OFF;
1092         }
1093
1094         return APP2EXT_SUCCESS;
1095
1096 FINISH_OFF:
1097         if (dev_node) {
1098                 ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1099                 if (ret)
1100                         _E("close dmcrypt device error(%d)", ret);
1101                 _app2sd_delete_loopback_device(temp_loopback_device);
1102                 free(dev_node);
1103         }
1104
1105         return err_res;
1106 }
1107
1108 int _app2sd_update_loopback_device_size(const char *pkgid,
1109                 const char *loopback_device, const char *application_path,
1110                 const char *temp_pkgid, const char *temp_loopback_device,
1111                 const char *temp_application_path, int size, GList *dir_list,
1112                 uid_t uid)
1113 {
1114         int ret;
1115         char *old_device_node;
1116         int err_res;
1117         char app_mmc_path[FILENAME_MAX];
1118         char temp_app_mmc_path[FILENAME_MAX];
1119         int mount_type;
1120
1121         ret = _app2sd_duplicate_device(pkgid, loopback_device, temp_pkgid,
1122                         temp_application_path, temp_loopback_device,
1123                         dir_list, NULL, size, uid);
1124         if (ret) {
1125                 _E("creating duplicate device failed");
1126                 return ret;
1127         }
1128
1129         /* get the associated device node for SD card applicatione */
1130         old_device_node =
1131                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
1132         if (old_device_node == NULL) {
1133                 /* do loopback setup */
1134                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
1135                         false, uid, &old_device_node);
1136                 if (ret) {
1137                         _E("dmcrypt open device error");
1138                         err_res = APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1139                         goto FINISH_OFF;
1140                 }
1141                 mount_type = MOUNT_TYPE_RW;
1142         } else {
1143                 mount_type = MOUNT_TYPE_RW_REMOUNT;
1144         }
1145
1146         /* do mounting */
1147         ret = _app2sd_mount_app_content(application_path, pkgid,
1148                         old_device_node, mount_type, dir_list,
1149                         APP2SD_PRE_UPGRADE, uid);
1150         if (ret) {
1151                 _E("remount failed");
1152                 err_res = APP2EXT_ERROR_MOUNT_PATH;
1153         }
1154
1155         snprintf(app_mmc_path, sizeof(app_mmc_path),
1156                         "%s/.mmc", application_path);
1157         snprintf(temp_app_mmc_path, sizeof(temp_app_mmc_path),
1158                         "%s/.mmc", temp_application_path);
1159
1160         ret = _app2sd_copy_ro_content(app_mmc_path,
1161                         temp_app_mmc_path, dir_list);
1162         if (ret) {
1163                 _E("copy ro content failed");
1164                 err_res = ret;
1165         }
1166
1167         ret = _app2sd_unmount_app_content(application_path);
1168         if (ret) {
1169                 _E("unable to unmount the SD application");
1170                 err_res = APP2EXT_ERROR_UNMOUNT;
1171         }
1172
1173         ret = _app2sd_unmount_app_content(temp_application_path);
1174         if (ret) {
1175                 _E("unable to unmount the SD application");
1176                 err_res = APP2EXT_ERROR_UNMOUNT;
1177                 goto FINISH_OFF;
1178         }
1179
1180         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1181         if (ret) {
1182                 _E("close dmcrypt device error(%d)", ret);
1183                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1184                 goto FINISH_OFF;
1185         }
1186
1187         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1188         if (ret) {
1189                 _E("close dmcrypt device error(%d)", ret);
1190                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1191                 goto FINISH_OFF;
1192         }
1193
1194         ret = _app2sd_delete_directory(loopback_device);
1195         if (ret) {
1196                 _E("unable to delete (%s)", loopback_device);
1197                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1198                 goto FINISH_OFF;
1199         }
1200
1201         ret = _app2sd_rename_dir(temp_loopback_device, loopback_device);
1202         if (ret) {
1203                 _E("unable to rename (%s)", temp_loopback_device);
1204                 err_res = APP2EXT_ERROR_MOVE;
1205                 goto FINISH_OFF;
1206         }
1207
1208         ret = _app2sd_delete_directory(temp_application_path);
1209         if (ret) {
1210                 _E("unable to delete (%s)", temp_application_path);
1211                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1212                 goto FINISH_OFF;
1213         }
1214
1215         return APP2EXT_SUCCESS;
1216
1217 FINISH_OFF:
1218         if (old_device_node)
1219                 free(old_device_node);
1220
1221         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1222         if (ret)
1223                 _E("close dmcrypt device error(%d)", ret);
1224
1225         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1226         if (ret)
1227                 _E("close dmcrypt device error(%d)", ret);
1228
1229         _app2sd_delete_loopback_device(temp_loopback_device);
1230
1231         ret = _app2sd_delete_directory(temp_application_path);
1232         if (ret)
1233                 _E("unable to delete (%s)", temp_application_path);
1234
1235         return err_res;
1236 }
1237
1238 int _app2sd_force_clean(const char *pkgid, const char *application_path,
1239                 const char *loopback_device, uid_t uid)
1240 {
1241         int ret;
1242
1243         /* unmount the loopback encrypted pseudo device from
1244          * the application installation path
1245          */
1246         ret = _app2sd_unmount_app_content(application_path);
1247         if (ret)
1248                 _W("unable to unmount the app content (%d)", ret);
1249
1250         /* detach the loopback encryption setup for the application */
1251         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1252         if (ret)
1253                 _W("close dmcrypt device error (%d)", ret);
1254
1255         /* delete the loopback device from the SD card */
1256         ret = _app2sd_delete_loopback_device(loopback_device);
1257         if (ret)
1258                 _W("unable to detach the loopback encryption setup for "
1259                                 "the application");
1260
1261         /* delete symlink */
1262         _app2sd_delete_symlink(application_path);
1263
1264         /* remove passwrd from DB */
1265         ret = _app2sd_initialize_db();
1266         if (ret)
1267                 _W("app2sd db initialize failed");
1268
1269         ret = _app2sd_remove_info_from_db(pkgid, uid);
1270         if (ret)
1271                 _W("cannot remove info from db");
1272
1273         return ret;
1274 }