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