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