Revert "Revert "Support legacy image for backward-compatibility""
[platform/core/appfw/app2sd.git] / plugin / app2sd / server / app2sd_internals_utils.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 #include <dirent.h>
25 #include <time.h>
26 #include <storage-internal.h>
27
28 #include "app2sd_internals.h"
29
30 #define PASSWD_LEN              21
31 #define ASCII_PASSWD_CHAR       93
32
33 /*
34 ########### Internal APIs ##################
35  */
36
37 /*Note: Don't use any printf statement inside this function*/
38 /*This function is similar to Linux's "system()"  for executing a process.*/
39 int _xsystem(const char *argv[])
40 {
41         int status = 0;
42         pid_t pid;
43         char err_buf[1024] = {0,};
44
45         pid = fork();
46         switch (pid) {
47         case -1:
48                 perror("fork failed");
49                 return -1;
50         case 0:
51                 /* child */
52                 strerror_r(errno, err_buf, sizeof(err_buf));
53                 if (execvp(argv[0], (char *const *)argv) < 0)
54                         fprintf(stderr, "execvp failed %d....%s\n",
55                                 errno, err_buf);
56                 _exit(-1);
57         default:
58                 /* parent */
59                 break;
60         }
61         if (waitpid(pid, &status, 0) == -1) {
62                 perror("waitpid failed");
63                 return -1;
64         }
65         if (WIFSIGNALED(status)) {
66                 perror("signal");
67                 return -1;
68         }
69         if (!WIFEXITED(status)) {
70                 /* shouldn't happen */
71                 perror("should not happen");
72                 return -1;
73         }
74         return WEXITSTATUS(status);
75 }
76
77
78 /*
79  * This function checks and returns MMC status
80  */
81 int _app2sd_check_mmc_status(char **sdpath)
82 {
83         int ret = 0;
84         int storage_id = 0;
85         char *sd_mount_path = NULL;
86
87         ret = storage_get_primary_sdcard(&storage_id, &sd_mount_path);
88         if (ret != STORAGE_ERROR_NONE) {
89                 _E("failed to get primary sdcard (%d)", ret);
90                 if (sd_mount_path)
91                         free(sd_mount_path);
92                 return APP2EXT_ERROR_MMC_STATUS;
93         }
94         if (sd_mount_path) {
95                 _D("primary sdcard: id(%d), mount_path(%s)",
96                         storage_id, sd_mount_path);
97                 *sdpath = sd_mount_path;
98                 return APP2EXT_SUCCESS;
99         }
100
101         _E("there is no primary sdcard");
102         if (sd_mount_path)
103                 free(sd_mount_path);
104
105         return APP2EXT_ERROR_MMC_STATUS;
106 }
107
108 /*
109  * This function returns the available free memory in the SD Card.
110  * param [in]: sd_path: This is sd card access path.
111  * param [out]: free_mem: Result will be available in this.
112  * User has to pass valid memory address.
113  * return: On success, it will return 0.
114  * Else, appropriate error no will be returned.
115  */
116 int _app2sd_get_available_free_memory(char *mmc_path, int *free_mem)
117 {
118         struct statvfs buf;
119         int ret = 0;
120         unsigned long long temp = 0;
121
122         if (mmc_path == NULL || free_mem == NULL) {
123                 _E("invalid input parameter");
124                 return -1;
125         }
126
127         memset((void *)&buf, '\0', sizeof(struct statvfs));
128
129         ret = statvfs(mmc_path, &buf);
130         if (ret) {
131                 _E("unable to get SD Card memory information");
132                 return APP2EXT_ERROR_MMC_INFORMATION;
133         }
134
135         temp = (unsigned long long)buf.f_bsize*buf.f_bavail;
136         *free_mem = (int)(temp/(1024*1024));
137
138         return 0;
139 }
140
141 void _app2sd_delete_symlink(const char *dirname)
142 {
143         int ret = 0;
144         DIR *dp = NULL;
145         struct dirent ep;
146         struct dirent *er = NULL;
147         char abs_filename[FILENAME_MAX] = { 0, };
148
149         _D("start clean_symlink [%s]", dirname);
150
151         dp = opendir(dirname);
152         if (dp != NULL) {
153                 while (readdir_r(dp, &ep, &er) == 0 && er != NULL) {
154                         char mmc_path[PATH_MAX] = {0};
155
156                         if (!strcmp(ep.d_name, ".") || !strcmp(ep.d_name, ".."))
157                                 continue;
158
159                         /*get realpath find symlink to ".mmc" and unlink it*/
160                         snprintf(abs_filename, FILENAME_MAX, "%s/%s", dirname, ep.d_name);
161                         char *path = realpath(abs_filename, mmc_path);
162                         if (!path)
163                                 _E("realpath failed");
164
165                         if (strstr(mmc_path, ".mmc")) {
166                                 _E("force unlink [%s]", abs_filename);
167                                 if (unlink(abs_filename)) {
168                                         if (errno == ENOENT)
169                                                 _W("Unable to access file %s", abs_filename);
170                                         else
171                                                 _E("Unable to delete %s", abs_filename);
172                                 }
173                         }
174
175                 }
176                 (void)closedir(dp);
177
178                 /*delete ".mmc" folder*/
179                 snprintf(abs_filename, FILENAME_MAX, "%s/.mmc", dirname);
180                 ret = remove(abs_filename);
181                 if (ret == -1)
182                         return;
183         } else {
184                 _E("couldn't open the directory[%s]", dirname);
185         }
186
187         _D("finish clean_symlink");
188 }
189
190 int _app2sd_copy_dir(const char *src, const char *dest)
191 {
192         int ret = APP2EXT_SUCCESS;
193         DIR *dir = NULL;
194         const char *argv_bin[] = { "/bin/cp", "-raf", src, dest, NULL };
195
196         /* check existence  before copy */
197         dir = opendir(src);
198         if (dir) {
199                 closedir(dir);
200         } else {
201                 if (errno == ENOENT) {
202                         _W("src(%s) not exist, skip!", src);
203                         return ret;
204                 } else {
205                         _E("failed to open src(%s) dir, errno(%d)", errno);
206                         return APP2EXT_ERROR_ACCESS_FILE;
207                 }
208         }
209
210         dir = opendir(dest);
211         if (dir) {
212                 closedir(dir);
213         } else {
214                 if (errno == ENOENT) {
215                         _E("dest(%s) not exist, failed!", dest);
216                         return APP2EXT_ERROR_ACCESS_FILE;
217                 } else {
218                         _E("failed to open dest(%s) dir, errno(%d)", errno);
219                         return APP2EXT_ERROR_ACCESS_FILE;
220                 }
221         }
222
223         ret = _xsystem(argv_bin);
224         if (ret) {
225                 _E("failed to copy dir, errno(%d)", errno);
226                 return APP2EXT_ERROR_ACCESS_FILE;
227         }
228         return ret;
229 }
230
231 int _app2sd_rename_dir(const char *old_name, const char *new_name)
232 {
233         int ret = APP2EXT_SUCCESS;
234         const char *argv_bin[] = { "/bin/mv", old_name, new_name, NULL };
235         ret = _xsystem(argv_bin);
236         if (ret) {
237                 _E("mv/rename fail");
238                 return APP2EXT_ERROR_ACCESS_FILE;
239         }
240         return ret;
241 }
242
243 unsigned long long _app2sd_calculate_dir_size(char *dirname)
244 {
245         static unsigned long long total = 0;
246         DIR *dp = NULL;
247         struct dirent ep;
248         struct dirent *er = NULL;
249         char abs_filename[FILENAME_MAX] = { 0, };;
250
251         dp = opendir(dirname);
252         if (dp != NULL) {
253                 while (readdir_r(dp, &ep, &er) == 0 && er != NULL) {
254                         struct stat stFileInfo;
255
256                         snprintf(abs_filename, FILENAME_MAX, "%s/%s", dirname,
257                                  ep.d_name);
258
259                         if (stat(abs_filename, &stFileInfo) < 0)
260                                 perror(abs_filename);
261                         else {
262                                 total += stFileInfo.st_size;
263
264                                 if (S_ISDIR(stFileInfo.st_mode)) {
265                                         if (strcmp(ep.d_name, ".")
266                                             && strcmp(ep.d_name, "..")) {
267                                                 _app2sd_calculate_dir_size
268                                                     (abs_filename);
269                                         }
270                                 } else {
271                                         /*Do Nothing */
272                                 }
273                         }
274                 }
275                 (void)closedir(dp);
276         } else {
277                 _E("error in opening directory");
278         }
279         return total;
280 }
281
282 unsigned long long _app2sd_calculate_file_size(const char *filename)
283 {
284         struct stat stFileInfo;
285         _D("calculating file size for (%s)", filename);
286
287         if (stat(filename, &stFileInfo) < 0) {
288                 perror(filename);
289                 return 0;
290         } else
291                 return stFileInfo.st_size;
292 }
293
294 /*Note: Don't use any printf statement inside this function*/
295 char *_app2sd_encrypt_device(const char *device,
296         const char *loopback_device, char *passwd)
297 {
298         const char *argv[] = { "/sbin/losetup", device,
299                 loopback_device, NULL };
300         pid_t pid = 0;
301         int my_pipe[2] = { 0, };
302         char buf[FILENAME_MAX] = { 0, };
303         char *ret_result = NULL;
304         int result = 0;
305         char err_buf[1024] = { 0,};
306
307         if (pipe(my_pipe) < 0) {
308                 fprintf(stderr, "Unable to create pipe\n");
309                 return NULL;
310         }
311         pid = fork();
312         switch (pid) {
313         case -1:
314                 perror("fork failed");
315                 return NULL;
316         case 0:
317                 /* child */
318                 close(1);
319                 close(2);
320                 result = dup(my_pipe[1]);
321                 if (result < 0) {
322                         strerror_r(errno, err_buf, sizeof(err_buf));
323                         fprintf(stderr, "dup failed %d....%s\n",
324                                 errno, err_buf);
325                         _exit(-1);
326                 }
327                 result = dup(my_pipe[1]);
328                 if (result < 0) {
329                         strerror_r(errno, err_buf, sizeof(err_buf));
330                         fprintf(stderr, "dup failed %d....%s\n",
331                                 errno, err_buf);
332                         _exit(-1);
333                 }
334                 if (execvp(argv[0], (char *const *)argv) < 0) {
335                         strerror_r(errno, err_buf, sizeof(err_buf));
336                         fprintf(stderr, "execvp failed %d....%s\n",
337                                 errno, err_buf); /*Don't use d_msg_app2sd */
338                 }
339                 _exit(-1);
340         default:
341                 /* parent */
342                 close(my_pipe[1]);
343                 result = read(my_pipe[0], buf, FILENAME_MAX);
344                 if (result < 0) {
345                         strerror_r(errno, err_buf, sizeof(err_buf));
346                         fprintf(stderr, "read failed %d....%s\n",
347                                 errno, err_buf);
348                 }
349                 break;
350         }
351
352         ret_result = (char *)malloc(strlen(buf) + 1);
353         if (ret_result == NULL) {
354                 _E("malloc failed");
355                 return NULL;
356         }
357         memset(ret_result, '\0', strlen(buf) + 1);
358         memcpy(ret_result, buf, strlen(buf));
359
360         return ret_result;
361 }
362
363 /*Note: Don't use any printf statement inside this function*/
364 char *_app2sd_detach_loop_device(const char *device)
365 {
366         const char *argv[] = { "/sbin/losetup", "-d", device, NULL };
367         pid_t pid;
368         int my_pipe[2] = { 0, };
369         char buf[FILENAME_MAX] = { 0, };
370         char *ret_result = NULL;
371         int result = 0;
372         char err_buf[1024] = {0,};
373
374         if (pipe(my_pipe) < 0) {
375                 fprintf(stderr, "Unable to create pipe\n");
376                 return NULL;
377         }
378         pid = fork();
379         switch (pid) {
380         case -1:
381                 perror("fork failed");
382                 return NULL;
383         case 0:
384                 /* child */
385                 close(1);
386                 close(2);
387                 result = dup(my_pipe[1]);
388                 if (result < 0) {
389                         strerror_r(errno, err_buf, sizeof(err_buf));
390                         fprintf(stderr, "dup failed %d....%s\n",
391                                 errno, err_buf);
392                         _exit(-1);
393                 }
394                 result = dup(my_pipe[1]);
395                 if (result < 0) {
396                         strerror_r(errno, err_buf, sizeof(err_buf));
397                         fprintf(stderr, "dup failed %d....%s\n",
398                                 errno, err_buf);
399                         _exit(-1);
400                 }
401                 if (execvp(argv[0], (char *const *)argv) < 0) {
402                         fprintf(stderr, "execvp failed\n");
403                                 /* Don't use d_msg_app2sd */
404                 }
405                 _exit(-1);
406         default:
407                 /* parent */
408                 close(my_pipe[1]);
409                 result = read(my_pipe[0], buf, FILENAME_MAX);
410                 if (result < 0) {
411                         strerror_r(errno, err_buf, sizeof(err_buf));
412                         fprintf(stderr, "read failed %d....%s\n",
413                                 errno, err_buf);
414                 }
415                 break;
416         }
417
418         ret_result = (char *)malloc(strlen(buf) + 1);
419         if (ret_result == NULL) {
420                 _E("malloc failed");
421                 return NULL;
422         }
423         memset(ret_result, '\0', strlen(buf) + 1);
424         memcpy(ret_result, buf, strlen(buf));
425
426         return ret_result;
427 }
428
429 /* Note: Don't use any printf statement inside this function*/
430 char *_app2sd_find_associated_device(const char *loopback_device)
431 {
432         const char *argv[] = { "/sbin/losetup", "-a", NULL };
433         pid_t pid;
434         int my_pipe[2] = { 0, };
435         char buf[FILENAME_MAX] = { 0, };
436         char *ret_result_temp = NULL;
437         char *ret_result = NULL;
438         char *line = NULL;;
439         char *save_str = NULL;
440         int result = 0;
441         char err_buf[1024] = {0,};
442
443         if (pipe(my_pipe) < 0) {
444                 fprintf(stderr, "Unable to create pipe\n");
445                 return NULL;
446         }
447         pid = fork();
448         switch (pid) {
449         case -1:
450                 perror("fork failed");
451                 return NULL;
452         case 0:
453                 /* child */
454                 close(1);
455                 close(2);
456                 result = dup(my_pipe[1]);
457                 if (result < 0) {
458                         strerror_r(errno, err_buf, sizeof(err_buf));
459                         fprintf(stderr, "dup failed %d....%s\n",
460                                 errno, err_buf);
461                         _exit(-1);
462                 }
463                 result = dup(my_pipe[1]);
464                 if (result < 0) {
465                         strerror_r(errno, err_buf, sizeof(err_buf));
466                         fprintf(stderr, "dup failed %d....%s\n",
467                                 errno, err_buf);
468                         _exit(-1);
469                 }
470                 if (execvp(argv[0], (char *const *)argv) < 0) {
471                         fprintf(stderr, "execvp failed\n");
472                                 /* Don't use d_msg_app2sd */
473                 }
474                 _exit(-1);
475         default:
476                 /* parent */
477                 close(my_pipe[1]);
478                 result = read(my_pipe[0], buf, FILENAME_MAX);
479                 if (result < 0) {
480                         strerror_r(errno, err_buf, sizeof(err_buf));
481                         fprintf(stderr, "read failed %d....%s\n",
482                                 errno, err_buf);
483                 }
484                 break;
485         }
486
487         ret_result_temp = (char *)malloc(strlen(buf) + 1);
488         if (ret_result_temp == NULL) {
489                 _E("malloc failed");
490                 return NULL;
491         }
492         memset(ret_result_temp, '\0', strlen(buf) + 1);
493         memcpy(ret_result_temp, buf, strlen(buf));
494
495         line = strtok_r(ret_result_temp, "\n", &save_str);
496         while (line) {
497                 if (strstr(line, loopback_device) != NULL) {
498                         _D("found: (%s)", line);
499                         if (ret_result)
500                                 _D("duplicated device");
501                         else
502                                 ret_result = strdup(line);
503                 }
504                 line = strtok_r(NULL, "\n", &save_str);
505         }
506         free(ret_result_temp);
507
508         return ret_result;
509 }
510
511 /*Note: Don't use any printf statement inside this function*/
512 char *_app2sd_find_free_device(void)
513 {
514         const char *argv[] = { "/sbin/losetup", "-f", NULL };
515         pid_t pid;
516         int my_pipe[2] = { 0, };
517         char buf[FILENAME_MAX + 1] = { 0, };
518         char *ret_result = NULL;
519         int result = 0;
520         char err_buf[1024] = {0,};
521
522         if (pipe(my_pipe) < 0) {
523                 fprintf(stderr, "Unable to create pipe\n");
524                 return NULL;
525         }
526         pid = fork();
527         switch (pid) {
528         case -1:
529                 perror("fork failed");
530                 return NULL;
531         case 0:
532                 /* child */
533                 close(1);
534                 close(2);
535                 result = dup(my_pipe[1]);
536                 if (result < 0) {
537                         strerror_r(errno, err_buf, sizeof(err_buf));
538                         fprintf(stderr, "dup failed %d....%s\n",
539                                 errno, err_buf);
540                         _exit(-1);
541                 }
542                 result = dup(my_pipe[1]);
543                 if (result < 0) {
544                         strerror_r(errno, err_buf, sizeof(err_buf));
545                         fprintf(stderr, "dup failed %d....%s\n",
546                                 errno, err_buf);
547                         _exit(-1);
548                 }
549                 if (execvp(argv[0], (char *const *)argv) < 0) {
550                         fprintf(stderr, "execvp failed\n");
551                                 /* Don't use d_msg_app2sd */
552                 }
553                 _exit(-1);
554         default:
555                 /* parent */
556                 close(my_pipe[1]);
557                 result = read(my_pipe[0], buf, FILENAME_MAX);
558                 if (result < 0) {
559                         strerror_r(errno, err_buf, sizeof(err_buf));
560                         fprintf(stderr, "read failed %d....%s\n",
561                                 errno, err_buf);
562                 }
563                 break;
564         }
565
566         ret_result = (char *)malloc(strlen(buf) + 1);
567         if (ret_result == NULL) {
568                 _E("malloc failed");
569                 return NULL;
570         }
571         memset(ret_result, '\0', strlen(buf) + 1);
572         memcpy(ret_result, buf, strlen(buf));
573
574         return ret_result;
575 }
576
577 /*
578 * This is a simple password generator
579 * return: On success, it will return the password, else NULL.
580 */
581 char *_app2sd_generate_password(const char *pkgid)
582 {
583         char passwd[PASSWD_LEN + 1] = { 0, };
584         char *ret_result = NULL;
585         char set[ASCII_PASSWD_CHAR + 1] =
586                 "!\"#$%&()*+,-./0123456789:;<=>?@ABCDE" \
587                 "FGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
588         unsigned char char_1;
589         unsigned char char_2;
590         int i = 0;
591         int appname_len = strlen(pkgid);
592         int j = appname_len;
593         unsigned int seed;
594
595         /* length of the password */
596         ret_result = (char *)malloc(PASSWD_LEN + 1);
597         if (NULL == ret_result) {
598                 _E("unable to allocate memory");
599                 return NULL;
600         }
601         memset((void *)ret_result, '\0', PASSWD_LEN + 1);
602
603         while (i < PASSWD_LEN) {
604                 seed = time(NULL);
605                 if (j > 0) j--;
606                 char_1 = (rand_r(&seed) + pkgid[j]) % ASCII_PASSWD_CHAR;
607                 char_2 = rand_r(&seed) % ASCII_PASSWD_CHAR;
608                 passwd[i] = set[char_1];
609                 if (j > 0) j--;
610                 passwd[i + 1] = set[((pkgid[j]) * 2) % ASCII_PASSWD_CHAR];
611                 if (i < PASSWD_LEN - 3)
612                         passwd[i + 2] = set[char_2];
613                 i++;
614         }
615
616         memcpy(ret_result, passwd, PASSWD_LEN + 1);
617
618         return ret_result;
619 }
620
621 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
622 int _app2sd_check_is_luks_device(const char *device_path)
623 {
624         int ret = 0;
625         int result = 1; /* default: luks format */
626         const char *argv_bin[] = { "/sbin/cryptsetup", "isLuks", device_path };
627         ret = _xsystem(argv_bin);
628         if (ret < 0)
629                 _E("there was errot to check isLuks");
630
631         if (ret == 1) /* legacy format */
632                 result = 0;
633
634         _D("ret(%d), result(%d)", ret, result);
635         return result;
636 }
637 #endif