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