Revert "Revert "Adjust log level not to recognized an error always""
[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         dp = opendir(dirname);
150         if (dp != NULL) {
151                 while (readdir_r(dp, &ep, &er) == 0 && er != NULL) {
152                         char mmc_path[PATH_MAX] = {0};
153
154                         if (!strcmp(ep.d_name, ".") || !strcmp(ep.d_name, ".."))
155                                 continue;
156
157                         /*get realpath find symlink to ".mmc" and unlink it*/
158                         snprintf(abs_filename, FILENAME_MAX, "%s/%s", dirname, ep.d_name);
159                         char *path = realpath(abs_filename, mmc_path);
160                         if (!path)
161                                 _E("realpath failed");
162
163                         if (strstr(mmc_path, ".mmc")) {
164                                 _E("force unlink [%s]", abs_filename);
165                                 if (unlink(abs_filename)) {
166                                         if (errno == ENOENT)
167                                                 _W("Unable to access file %s", abs_filename);
168                                         else
169                                                 _E("Unable to delete %s", abs_filename);
170                                 }
171                         }
172
173                 }
174                 (void)closedir(dp);
175
176                 /*delete ".mmc" folder*/
177                 snprintf(abs_filename, FILENAME_MAX, "%s/.mmc", dirname);
178                 ret = remove(abs_filename);
179                 if (ret == -1)
180                         return;
181         }
182 }
183
184 int _app2sd_copy_dir(const char *src, const char *dest)
185 {
186         int ret = APP2EXT_SUCCESS;
187         DIR *dir = NULL;
188         const char *argv_bin[] = { "/bin/cp", "-raf", src, dest, NULL };
189
190         /* check existence  before copy */
191         dir = opendir(src);
192         if (dir) {
193                 closedir(dir);
194         } else {
195                 if (errno == ENOENT) {
196                         _W("src(%s) not exist, skip!", src);
197                         return ret;
198                 } else {
199                         _E("failed to open src(%s) dir, errno(%d)", errno);
200                         return APP2EXT_ERROR_ACCESS_FILE;
201                 }
202         }
203
204         dir = opendir(dest);
205         if (dir) {
206                 closedir(dir);
207         } else {
208                 if (errno == ENOENT) {
209                         _E("dest(%s) not exist, failed!", dest);
210                         return APP2EXT_ERROR_ACCESS_FILE;
211                 } else {
212                         _E("failed to open dest(%s) dir, errno(%d)", errno);
213                         return APP2EXT_ERROR_ACCESS_FILE;
214                 }
215         }
216
217         ret = _xsystem(argv_bin);
218         if (ret) {
219                 _E("failed to copy dir, errno(%d)", errno);
220                 return APP2EXT_ERROR_ACCESS_FILE;
221         }
222         return ret;
223 }
224
225 int _app2sd_rename_dir(const char *old_name, const char *new_name)
226 {
227         int ret = APP2EXT_SUCCESS;
228         const char *argv_bin[] = { "/bin/mv", old_name, new_name, NULL };
229         ret = _xsystem(argv_bin);
230         if (ret) {
231                 _E("mv/rename fail");
232                 return APP2EXT_ERROR_ACCESS_FILE;
233         }
234         return ret;
235 }
236
237 unsigned long long _app2sd_calculate_dir_size(char *dirname)
238 {
239         static unsigned long long total = 0;
240         DIR *dp = NULL;
241         struct dirent ep;
242         struct dirent *er = NULL;
243         char abs_filename[FILENAME_MAX] = { 0, };;
244
245         dp = opendir(dirname);
246         if (dp != NULL) {
247                 while (readdir_r(dp, &ep, &er) == 0 && er != NULL) {
248                         struct stat stFileInfo;
249
250                         snprintf(abs_filename, FILENAME_MAX, "%s/%s", dirname,
251                                  ep.d_name);
252
253                         if (stat(abs_filename, &stFileInfo) < 0)
254                                 perror(abs_filename);
255                         else {
256                                 total += stFileInfo.st_size;
257
258                                 if (S_ISDIR(stFileInfo.st_mode)) {
259                                         if (strcmp(ep.d_name, ".")
260                                             && strcmp(ep.d_name, "..")) {
261                                                 _app2sd_calculate_dir_size
262                                                     (abs_filename);
263                                         }
264                                 } else {
265                                         /*Do Nothing */
266                                 }
267                         }
268                 }
269                 (void)closedir(dp);
270         } else {
271                 _E("error in opening directory");
272         }
273         return total;
274 }
275
276 unsigned long long _app2sd_calculate_file_size(const char *filename)
277 {
278         struct stat stFileInfo;
279         _D("calculating file size for (%s)", filename);
280
281         if (stat(filename, &stFileInfo) < 0) {
282                 perror(filename);
283                 return 0;
284         } else
285                 return stFileInfo.st_size;
286 }
287
288 /*Note: Don't use any printf statement inside this function*/
289 char *_app2sd_encrypt_device(const char *device,
290         const char *loopback_device, char *passwd)
291 {
292         const char *argv[] = { "/sbin/losetup", device,
293                 loopback_device, NULL };
294         pid_t pid = 0;
295         int my_pipe[2] = { 0, };
296         char buf[FILENAME_MAX] = { 0, };
297         char *ret_result = NULL;
298         int result = 0;
299         char err_buf[1024] = { 0,};
300
301         if (pipe(my_pipe) < 0) {
302                 fprintf(stderr, "Unable to create pipe\n");
303                 return NULL;
304         }
305         pid = fork();
306         switch (pid) {
307         case -1:
308                 perror("fork failed");
309                 return NULL;
310         case 0:
311                 /* child */
312                 close(1);
313                 close(2);
314                 result = dup(my_pipe[1]);
315                 if (result < 0) {
316                         strerror_r(errno, err_buf, sizeof(err_buf));
317                         fprintf(stderr, "dup failed %d....%s\n",
318                                 errno, err_buf);
319                         _exit(-1);
320                 }
321                 result = dup(my_pipe[1]);
322                 if (result < 0) {
323                         strerror_r(errno, err_buf, sizeof(err_buf));
324                         fprintf(stderr, "dup failed %d....%s\n",
325                                 errno, err_buf);
326                         _exit(-1);
327                 }
328                 if (execvp(argv[0], (char *const *)argv) < 0) {
329                         strerror_r(errno, err_buf, sizeof(err_buf));
330                         fprintf(stderr, "execvp failed %d....%s\n",
331                                 errno, err_buf); /*Don't use d_msg_app2sd */
332                 }
333                 _exit(-1);
334         default:
335                 /* parent */
336                 close(my_pipe[1]);
337                 result = read(my_pipe[0], buf, FILENAME_MAX);
338                 if (result < 0) {
339                         strerror_r(errno, err_buf, sizeof(err_buf));
340                         fprintf(stderr, "read failed %d....%s\n",
341                                 errno, err_buf);
342                 }
343                 break;
344         }
345
346         ret_result = (char *)malloc(strlen(buf) + 1);
347         if (ret_result == NULL) {
348                 _E("malloc failed");
349                 return NULL;
350         }
351         memset(ret_result, '\0', strlen(buf) + 1);
352         memcpy(ret_result, buf, strlen(buf));
353
354         return ret_result;
355 }
356
357 /*Note: Don't use any printf statement inside this function*/
358 char *_app2sd_detach_loop_device(const char *device)
359 {
360         const char *argv[] = { "/sbin/losetup", "-d", device, NULL };
361         pid_t pid;
362         int my_pipe[2] = { 0, };
363         char buf[FILENAME_MAX] = { 0, };
364         char *ret_result = NULL;
365         int result = 0;
366         char err_buf[1024] = {0,};
367
368         if (pipe(my_pipe) < 0) {
369                 fprintf(stderr, "Unable to create pipe\n");
370                 return NULL;
371         }
372         pid = fork();
373         switch (pid) {
374         case -1:
375                 perror("fork failed");
376                 return NULL;
377         case 0:
378                 /* child */
379                 close(1);
380                 close(2);
381                 result = dup(my_pipe[1]);
382                 if (result < 0) {
383                         strerror_r(errno, err_buf, sizeof(err_buf));
384                         fprintf(stderr, "dup failed %d....%s\n",
385                                 errno, err_buf);
386                         _exit(-1);
387                 }
388                 result = dup(my_pipe[1]);
389                 if (result < 0) {
390                         strerror_r(errno, err_buf, sizeof(err_buf));
391                         fprintf(stderr, "dup failed %d....%s\n",
392                                 errno, err_buf);
393                         _exit(-1);
394                 }
395                 if (execvp(argv[0], (char *const *)argv) < 0) {
396                         fprintf(stderr, "execvp failed\n");
397                                 /* Don't use d_msg_app2sd */
398                 }
399                 _exit(-1);
400         default:
401                 /* parent */
402                 close(my_pipe[1]);
403                 result = read(my_pipe[0], buf, FILENAME_MAX);
404                 if (result < 0) {
405                         strerror_r(errno, err_buf, sizeof(err_buf));
406                         fprintf(stderr, "read failed %d....%s\n",
407                                 errno, err_buf);
408                 }
409                 break;
410         }
411
412         ret_result = (char *)malloc(strlen(buf) + 1);
413         if (ret_result == NULL) {
414                 _E("malloc failed");
415                 return NULL;
416         }
417         memset(ret_result, '\0', strlen(buf) + 1);
418         memcpy(ret_result, buf, strlen(buf));
419
420         return ret_result;
421 }
422
423 /* Note: Don't use any printf statement inside this function*/
424 char *_app2sd_find_associated_device(const char *loopback_device)
425 {
426         const char *argv[] = { "/sbin/losetup", "-a", NULL };
427         pid_t pid;
428         int my_pipe[2] = { 0, };
429         char buf[FILENAME_MAX] = { 0, };
430         char *ret_result_temp = NULL;
431         char *ret_result = NULL;
432         char *line = NULL;;
433         char *save_str = NULL;
434         int result = 0;
435         char err_buf[1024] = {0,};
436
437         if (pipe(my_pipe) < 0) {
438                 fprintf(stderr, "Unable to create pipe\n");
439                 return NULL;
440         }
441         pid = fork();
442         switch (pid) {
443         case -1:
444                 perror("fork failed");
445                 return NULL;
446         case 0:
447                 /* child */
448                 close(1);
449                 close(2);
450                 result = dup(my_pipe[1]);
451                 if (result < 0) {
452                         strerror_r(errno, err_buf, sizeof(err_buf));
453                         fprintf(stderr, "dup failed %d....%s\n",
454                                 errno, err_buf);
455                         _exit(-1);
456                 }
457                 result = dup(my_pipe[1]);
458                 if (result < 0) {
459                         strerror_r(errno, err_buf, sizeof(err_buf));
460                         fprintf(stderr, "dup failed %d....%s\n",
461                                 errno, err_buf);
462                         _exit(-1);
463                 }
464                 if (execvp(argv[0], (char *const *)argv) < 0) {
465                         fprintf(stderr, "execvp failed\n");
466                                 /* Don't use d_msg_app2sd */
467                 }
468                 _exit(-1);
469         default:
470                 /* parent */
471                 close(my_pipe[1]);
472                 result = read(my_pipe[0], buf, FILENAME_MAX);
473                 if (result < 0) {
474                         strerror_r(errno, err_buf, sizeof(err_buf));
475                         fprintf(stderr, "read failed %d....%s\n",
476                                 errno, err_buf);
477                 }
478                 break;
479         }
480
481         ret_result_temp = (char *)malloc(strlen(buf) + 1);
482         if (ret_result_temp == NULL) {
483                 _E("malloc failed");
484                 return NULL;
485         }
486         memset(ret_result_temp, '\0', strlen(buf) + 1);
487         memcpy(ret_result_temp, buf, strlen(buf));
488
489         line = strtok_r(ret_result_temp, "\n", &save_str);
490         while (line) {
491                 if (strstr(line, loopback_device) != NULL) {
492                         _D("found: (%s)", line);
493                         if (ret_result)
494                                 _D("duplicated device");
495                         else
496                                 ret_result = strdup(line);
497                 }
498                 line = strtok_r(NULL, "\n", &save_str);
499         }
500         free(ret_result_temp);
501
502         return ret_result;
503 }
504
505 /*Note: Don't use any printf statement inside this function*/
506 char *_app2sd_find_free_device(void)
507 {
508         const char *argv[] = { "/sbin/losetup", "-f", NULL };
509         pid_t pid;
510         int my_pipe[2] = { 0, };
511         char buf[FILENAME_MAX + 1] = { 0, };
512         char *ret_result = NULL;
513         int result = 0;
514         char err_buf[1024] = {0,};
515
516         if (pipe(my_pipe) < 0) {
517                 fprintf(stderr, "Unable to create pipe\n");
518                 return NULL;
519         }
520         pid = fork();
521         switch (pid) {
522         case -1:
523                 perror("fork failed");
524                 return NULL;
525         case 0:
526                 /* child */
527                 close(1);
528                 close(2);
529                 result = dup(my_pipe[1]);
530                 if (result < 0) {
531                         strerror_r(errno, err_buf, sizeof(err_buf));
532                         fprintf(stderr, "dup failed %d....%s\n",
533                                 errno, err_buf);
534                         _exit(-1);
535                 }
536                 result = dup(my_pipe[1]);
537                 if (result < 0) {
538                         strerror_r(errno, err_buf, sizeof(err_buf));
539                         fprintf(stderr, "dup failed %d....%s\n",
540                                 errno, err_buf);
541                         _exit(-1);
542                 }
543                 if (execvp(argv[0], (char *const *)argv) < 0) {
544                         fprintf(stderr, "execvp failed\n");
545                                 /* Don't use d_msg_app2sd */
546                 }
547                 _exit(-1);
548         default:
549                 /* parent */
550                 close(my_pipe[1]);
551                 result = read(my_pipe[0], buf, FILENAME_MAX);
552                 if (result < 0) {
553                         strerror_r(errno, err_buf, sizeof(err_buf));
554                         fprintf(stderr, "read failed %d....%s\n",
555                                 errno, err_buf);
556                 }
557                 break;
558         }
559
560         ret_result = (char *)malloc(strlen(buf) + 1);
561         if (ret_result == NULL) {
562                 _E("malloc failed");
563                 return NULL;
564         }
565         memset(ret_result, '\0', strlen(buf) + 1);
566         memcpy(ret_result, buf, strlen(buf));
567
568         return ret_result;
569 }
570
571 /*
572 * This is a simple password generator
573 * return: On success, it will return the password, else NULL.
574 */
575 char *_app2sd_generate_password(const char *pkgid)
576 {
577         char passwd[PASSWD_LEN + 1] = { 0, };
578         char *ret_result = NULL;
579         char set[ASCII_PASSWD_CHAR + 1] =
580                 "!\"#$%&()*+,-./0123456789:;<=>?@ABCDE" \
581                 "FGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
582         unsigned char char_1;
583         unsigned char char_2;
584         int i = 0;
585         int appname_len = strlen(pkgid);
586         int j = appname_len;
587         unsigned int seed;
588
589         /* length of the password */
590         ret_result = (char *)malloc(PASSWD_LEN + 1);
591         if (NULL == ret_result) {
592                 _E("unable to allocate memory");
593                 return NULL;
594         }
595         memset((void *)ret_result, '\0', PASSWD_LEN + 1);
596
597         while (i < PASSWD_LEN) {
598                 seed = time(NULL);
599                 if (j > 0) j--;
600                 char_1 = (rand_r(&seed) + pkgid[j]) % ASCII_PASSWD_CHAR;
601                 char_2 = rand_r(&seed) % ASCII_PASSWD_CHAR;
602                 passwd[i] = set[char_1];
603                 if (j > 0) j--;
604                 passwd[i + 1] = set[((pkgid[j]) * 2) % ASCII_PASSWD_CHAR];
605                 if (i < PASSWD_LEN - 3)
606                         passwd[i + 2] = set[char_2];
607                 i++;
608         }
609
610         memcpy(ret_result, passwd, PASSWD_LEN + 1);
611
612         return ret_result;
613 }
614
615 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
616 int _app2sd_check_is_luks_device(const char *device_path)
617 {
618         int ret = 0;
619         int result = 1; /* default: luks format */
620         const char *argv_bin[] = { "/sbin/cryptsetup", "isLuks", device_path };
621         ret = _xsystem(argv_bin);
622         if (ret < 0)
623                 _E("there was errot to check isLuks");
624
625         if (ret == 1) /* legacy format */
626                 result = 0;
627
628         _D("ret(%d), result(%d)", ret, result);
629         return result;
630 }
631 #endif