Get the random value from /dev/urandom
[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 #define _GNU_SOURCE
25 #include <dirent.h>
26 #include <glib.h>
27 #include <storage-internal.h>
28
29 #include "app2sd_internals.h"
30
31 #define PASSWD_LEN              21
32 #define ASCII_PASSWD_CHAR       93
33
34 /*
35 ########### Internal APIs ##################
36  */
37
38 /* Note: Don't use any printf statement inside this function
39  * This function is similar to Linux's "system()" for executing a process.
40  */
41 int _xsystem(const char *argv[])
42 {
43         int status;
44         pid_t pid;
45         char err_buf[1024];
46         const char *err_str;
47
48         pid = fork();
49         switch (pid) {
50         case -1:
51                 perror("fork failed");
52                 return -1;
53         case 0:
54                 /* child */
55                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
56                 if (execvp(argv[0], (char *const *)argv) < 0)
57                         fprintf(stderr, "execvp failed %d....%s\n",
58                                         errno, err_str);
59                 _exit(-1);
60         default:
61                 /* parent */
62                 break;
63         }
64         if (waitpid(pid, &status, 0) == -1) {
65                 perror("waitpid failed");
66                 return -1;
67         }
68         if (WIFSIGNALED(status)) {
69                 perror("signal");
70                 return -1;
71         }
72         if (!WIFEXITED(status)) {
73                 /* shouldn't happen */
74                 perror("should not happen");
75                 return -1;
76         }
77         return WEXITSTATUS(status);
78 }
79
80 /*
81  * This function checks and returns MMC status
82  */
83 int _app2sd_check_mmc_status(char **sdpath)
84 {
85         int ret;
86         int storage_id;
87         char *sd_mount_path;
88
89         ret = storage_get_primary_sdcard(&storage_id, &sd_mount_path);
90         if (ret != STORAGE_ERROR_NONE) {
91                 _E("failed to get primary sdcard (%d)", ret);
92                 return APP2EXT_ERROR_MMC_STATUS;
93         }
94
95         _D("primary sdcard: id(%d), mount_path(%s)", storage_id, sd_mount_path);
96         *sdpath = sd_mount_path;
97
98         return APP2EXT_SUCCESS;
99 }
100
101 /*
102  * This function returns the available free memory in the storage.
103  * param [in]: mmc_path: This is storage access path.
104  * param [out]: free_mem: Result will be available in this.
105  * User has to pass valid memory address.
106  * return: On success, it will return 0.
107  * Else, appropriate error no will be returned.
108  */
109 int _app2sd_get_available_free_memory(char *mmc_path, int *free_mem)
110 {
111         struct statvfs buf;
112         int ret = 0;
113         unsigned long long temp = 0;
114
115         if (mmc_path == NULL || free_mem == NULL) {
116                 _E("invalid input parameter");
117                 return -1;
118         }
119
120         memset((void *)&buf, '\0', sizeof(struct statvfs));
121
122         ret = statvfs(mmc_path, &buf);
123         if (ret) {
124                 _E("unable to get memory information");
125                 return APP2EXT_ERROR_MMC_INFORMATION;
126         }
127
128         temp = (unsigned long long)buf.f_bsize * buf.f_bavail;
129         *free_mem = (int)(temp/(1024*1024));
130
131         return 0;
132 }
133
134 void _app2sd_delete_symlink(const char *dirname)
135 {
136         int ret;
137         DIR *dp;
138         struct dirent *ep;
139         char abs_filename[FILENAME_MAX];
140         char *mmc_path;
141
142         dp = opendir(dirname);
143         if (dp == NULL)
144                 return;
145
146         while ((ep = readdir(dp)) != NULL) {
147                 if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
148                         continue;
149
150                 /* get realpath find symlink to ".mmc" and unlink it */
151                 snprintf(abs_filename, sizeof(abs_filename), "%s/%s", dirname,
152                                 ep->d_name);
153                 mmc_path = realpath(abs_filename, NULL);
154                 if (!mmc_path) {
155                         _E("realpath failed");
156                         continue;
157                 }
158
159                 if (strstr(mmc_path, ".mmc") == NULL) {
160                         free(mmc_path);
161                         continue;
162                 }
163                 free(mmc_path);
164
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         (void)closedir(dp);
174
175         /* delete ".mmc" directory */
176         snprintf(abs_filename, sizeof(abs_filename), "%s/.mmc", dirname);
177         ret = remove(abs_filename);
178         if (ret == -1) {
179                 _W("failed to remove %s", abs_filename);
180                 return;
181         }
182 }
183
184 int _app2sd_copy_dir(const char *src, const char *dest)
185 {
186         int ret;
187         DIR *dir;
188         const char *argv_bin[] = { "/bin/cp", "-raf", src, dest, NULL };
189
190         /* check existence  before copy */
191         dir = opendir(src);
192         if (dir == NULL) {
193                 if (errno == ENOENT) {
194                         _W("src(%s) not exist, skip!", src);
195                         return APP2EXT_SUCCESS;
196                 } else {
197                         _E("failed to open src(%s) dir, errno(%d)", src, errno);
198                         return APP2EXT_ERROR_ACCESS_FILE;
199                 }
200         }
201         closedir(dir);
202
203         dir = opendir(dest);
204         if (dir == NULL) {
205                 if (errno == ENOENT) {
206                         _E("dest(%s) not exist, failed!", dest);
207                         return APP2EXT_ERROR_ACCESS_FILE;
208                 } else {
209                         _E("failed to open dest(%s) dir: errno(%d)",
210                                         dest, errno);
211                         return APP2EXT_ERROR_ACCESS_FILE;
212                 }
213         }
214         closedir(dir);
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;
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 APP2EXT_SUCCESS;
234 }
235
236 unsigned long long _app2sd_calculate_dir_size(char *dirname)
237 {
238         unsigned long long total = 0;
239         DIR *dp = NULL;
240         struct dirent *ep = NULL;
241         char abs_filename[FILENAME_MAX] = { 0, };;
242         struct stat sb;
243
244         dp = opendir(dirname);
245         if (dp == NULL) {
246                 _E("error in opening directory");
247                 return 0;
248         }
249
250         while ((ep = readdir(dp)) != NULL) {
251                 snprintf(abs_filename, sizeof(abs_filename), "%s/%s", dirname,
252                                  ep->d_name);
253                 if (stat(abs_filename, &sb) < 0) {
254                         perror(abs_filename);
255                         continue;
256                 }
257                 total += sb.st_size;
258                 if (!S_ISDIR(sb.st_mode))
259                         continue;
260
261                 if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
262                         continue;
263                 /* calculate subdirectory */
264                 total += _app2sd_calculate_dir_size(abs_filename);
265         }
266         (void)closedir(dp);
267
268         return total;
269 }
270
271 unsigned long long _app2sd_calculate_file_size(const char *filename)
272 {
273         struct stat sb;
274         _D("calculating file size for (%s)", filename);
275
276         if (stat(filename, &sb) < 0) {
277                 perror(filename);
278                 return 0;
279         }
280
281         return sb.st_size;
282 }
283
284 /* Note: Don't use any printf statement inside this function */
285 char *_app2sd_execute_command(const char *argv[])
286 {
287         pid_t pid;
288         int my_pipe[2];
289         char buf[FILENAME_MAX] = { 0, };
290         char *ret_result;
291         int result;
292         char err_buf[1024];
293         const char *err_str;
294
295         if (pipe(my_pipe) < 0) {
296                 fprintf(stderr, "Unable to create pipe\n");
297                 return NULL;
298         }
299         pid = fork();
300         switch (pid) {
301         case -1:
302                 perror("fork failed");
303                 return NULL;
304         case 0:
305                 /* child */
306                 close(0);
307                 result = dup2(my_pipe[1], 1);
308                 if (result < 0) {
309                         err_str = strerror_r(errno, err_buf, sizeof(err_buf));
310                         fprintf(stderr, "dup failed %d...%s\n", errno, err_str);
311                         _exit(-1);
312                 }
313                 result = dup2(my_pipe[1], 2);
314                 if (result < 0) {
315                         err_str = strerror_r(errno, err_buf, sizeof(err_buf));
316                         fprintf(stderr, "dup failed %d...%s\n", errno, err_str);
317                         _exit(-1);
318                 }
319                 if (execvp(argv[0], (char *const *)argv) < 0) {
320                         err_str = strerror_r(errno, err_buf, sizeof(err_buf));
321                         fprintf(stderr, "execvp failed %d....%s\n",
322                                         errno, err_str);
323                 }
324                 _exit(-1);
325         default:
326                 /* parent */
327                 close(my_pipe[1]);
328                 result = read(my_pipe[0], buf, sizeof(buf) - 1);
329                 if (result < 0) {
330                         err_str = strerror_r(errno, err_buf, sizeof(err_buf));
331                         fprintf(stderr, "read failed %d..%s\n", errno, err_str);
332                 }
333                 break;
334         }
335
336         ret_result = strdup(buf);
337         if (ret_result == NULL) {
338                 _E("strdup failed");
339                 return NULL;
340         }
341
342         return ret_result;
343
344 }
345
346 static int generate_random_num(unsigned short* buf, int len) {
347         int fd = open("/dev/urandom", O_RDONLY);
348         if (fd < 0)
349                 return -1;
350
351         if (read(fd, buf, len) < 0)
352                 return -1;
353
354         close(fd);
355
356         return 0;
357 }
358
359 /*
360 * This is a simple password generator
361 * return: On success, it will return the password, else NULL.
362 */
363 char *_app2sd_generate_password(void)
364 {
365         char *passwd;
366         static const char charset[ASCII_PASSWD_CHAR + 1] =
367                 "!\"#$%&()*+,-./0123456789:;<=>?@ABCDE" \
368                 "FGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
369         int i;
370         unsigned short rand_nums[PASSWD_LEN];
371
372         if (generate_random_num(rand_nums, sizeof(rand_nums)) < 0) {
373                 _E("Failed to read random data");
374                 return NULL;
375         }
376
377         /* include null byte */
378         passwd = (char *)malloc(sizeof(char) * (PASSWD_LEN + 1));
379         if (passwd == NULL) {
380                 _E("unable to allocate memory");
381                 return NULL;
382         }
383
384         for (i = 0; i < PASSWD_LEN; i++)
385                 passwd[i] = charset[rand_nums[i] % ASCII_PASSWD_CHAR];
386         passwd[i] = '\0';
387
388         return passwd;
389 }
390
391 int _app2sd_check_is_luks_device(const char *device_path)
392 {
393         int ret = 0;
394         int result = 1; /* default: luks format */
395         const char *argv_bin[] = { "/sbin/cryptsetup", "isLuks", device_path };
396         ret = _xsystem(argv_bin);
397         if (ret < 0)
398                 _E("there was errot to check isLuks");
399
400         if (ret == 1) /* legacy format */
401                 result = 0;
402
403         _D("ret(%d), result(%d)", ret, result);
404         return result;
405 }
406
407 int _app2sd_get_loopback_device_path(const char *mmc_path,
408                 const char *pkgid, uid_t uid, char *loopback_device, size_t len)
409 {
410         char *encoded_id;
411
412         encoded_id = _app2sd_get_encoded_name(pkgid, uid);
413         if (encoded_id == NULL)
414                 return APP2EXT_ERROR_MEMORY_ALLOC_FAILED;
415
416         snprintf(loopback_device, len, "%s/%s/%s", mmc_path, EXTIMG_DIR,
417                         encoded_id);
418         free(encoded_id);
419         return APP2EXT_SUCCESS;
420 }