common: move file IO to libsyscommon
[platform/core/system/deviced.git] / src / shared / common.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #define _GNU_SOURCE
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <time.h>
27 #include <assert.h>
28 #include <sys/time.h>
29 #include <fcntl.h>
30 #include <signal.h>
31 #include <dirent.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <errno.h>
36 #include <poll.h>
37 #include <mntent.h>
38 #include <system_info.h>
39 #include <sys/mount.h>
40 #include "log.h"
41 #include "common.h"
42
43 #define BUFF_MAX        255
44
45 #define APP_ATTR_PATH "/proc/%d/attr/current"
46
47 int get_cmdline_name(pid_t pid, char *cmdline, size_t cmdline_size)
48 {
49         int fd, ret;
50         char buf[PATH_MAX + 1];
51         char *filename;
52
53         snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
54         fd = open(buf, O_RDONLY);
55         if (fd < 0) {
56                 errno = ESRCH;
57                 return -1;
58         }
59
60         ret = read(fd, buf, PATH_MAX);
61         close(fd);
62         if (ret < 0)
63                 return -1;
64
65         buf[PATH_MAX] = '\0';
66
67         filename = strrchr(buf, '/');
68         if (filename == NULL)
69                 filename = buf;
70         else
71                 filename = filename + 1;
72
73         if (cmdline_size < strlen(filename) + 1) {
74                 errno = EOVERFLOW;
75                 return -1;
76         }
77
78         strncpy(cmdline, filename, cmdline_size - 1);
79         cmdline[cmdline_size - 1] = '\0';
80         return 0;
81 }
82
83 int is_app(pid_t pid)
84 {
85         char attr[64];
86         size_t len;
87         int ret;
88
89         ret = get_privilege(pid, attr, sizeof(attr));
90         if (ret < 0) {
91                 _E("Failed to get privilege of PID(%d).", pid);
92                 return -1;
93         }
94
95         len = strlen(attr) + 1;
96
97         if (!strncmp("System", attr, len))
98                 return 0;
99
100         if (!strncmp("User", attr, len))
101                 return 0;
102
103         if (!strncmp("System::Privileged", attr, len))
104                 return 0;
105
106         return 1;
107 }
108
109 /*
110  * Helper function
111  * - Read from sysfs entry
112  * - Write to sysfs entry
113  */
114 int sys_check_node(char *path)
115 {
116         int fd;
117
118         fd = open(path, O_RDONLY);
119         if (fd == -1)
120                 return -1;
121
122         close(fd);
123         return 0;
124 }
125
126 int get_systemd_reboot_param(char *buf, unsigned bufsize)
127 {
128         int r = sys_read_buf("/run/systemd/reboot-param", buf, bufsize);
129         if (r < 0)
130                 return r;
131
132         if (r > 0 && buf[r - 1] == '\n') {
133                 buf[r - 1] = '\0';
134                 r -= 1;
135         }
136
137         return r;
138 }
139
140 static int terminate_processes_on_partition(const char *partition, bool force)
141 {
142         const char *argv[7] = {"/usr/bin/fuser", "-m", "-k", "-s", NULL, NULL, NULL};
143         int argc;
144
145         if (force)
146                 argv[4] = "-SIGKILL";
147         else
148                 argv[4] = "-SIGTERM";
149
150         argv[5] = partition;
151         argc = sizeof(argv) / sizeof(argv[0]);
152
153         return run_child(argc, argv);
154 }
155
156 int mount_check(const char *path)
157 {
158         int ret = false;
159         struct mntent *mnt;
160         const char *table = "/etc/mtab";
161         FILE *fp;
162         int len;
163
164         fp = setmntent(table, "r");
165         if (!fp)
166                 return ret;
167
168         len = strlen(path) + 1;
169         while (1) {
170                 mnt = getmntent(fp);
171                 if (mnt == NULL)
172                         break;
173                 if (!strncmp(mnt->mnt_dir, path, len)) {
174                         ret = true;
175                         break;
176                 }
177         }
178         endmntent(fp);
179         return ret;
180 }
181
182 static int get_num_processes_on_partition(const char *part_path)
183 {
184         FILE *fp;
185         char *cmd = NULL;
186         char *line = NULL;
187         size_t len = 0;
188         int num_processes = 0;
189         int ret = 0;
190
191         ret = asprintf(&cmd, "fuser -m %s | grep -o '[0-9]*'", part_path);
192         if (ret < 0)
193                 return -1;
194
195         printf("cmd=%s\n", cmd);
196         fp = popen(cmd, "r");
197         free(cmd);
198         if (fp == NULL)
199                 return -1;
200
201         while (getline(&line, &len, fp) != -1)
202                 num_processes++;
203
204         free(line);
205         pclose(fp);
206
207         return num_processes;
208 }
209
210 void umount_partition_by_kill(const char *path, const int max_retry)
211 {
212         FILE *fp;
213         char *part_path = NULL;
214         size_t len = 0;
215         int ret = 0, retry = 0;
216         int remain;
217         char *cmd = NULL;
218
219         /* if the path is not a mountpoint, do not perform umounting and killing */
220         if (!mount_check(path))
221                 return;
222
223         ret = asprintf(&cmd, "mount | grep \" on %s \" | awk '{print $1}'", path);
224         if (ret < 0)
225                 return;
226
227         fp = popen(cmd, "r");
228         free(cmd);
229         if (!fp)
230                 return;
231
232         ret = getline(&part_path, &len, fp);
233         if (ret == -1 || !part_path) {
234                 pclose(fp);
235                 free(part_path);
236                 return;
237         } else if (ret > 0 && *(part_path + ret - 1) == '\n') {
238                 *(part_path + ret -1) = '\0';
239         }
240
241         sync();
242         umount2(path, MNT_DETACH);
243
244         do {
245                 /* Kill processes with SIGTERM */
246                 terminate_processes_on_partition(part_path, false);
247                 usleep((useconds_t)MSEC_TO_USEC(500));
248
249                 /* Kill processes with SIGKILL */
250                 terminate_processes_on_partition(part_path, true);
251                 usleep((useconds_t)MSEC_TO_USEC(200));
252
253                 remain = get_num_processes_on_partition(part_path);
254
255                 retry++;
256
257         } while (remain > 0 && retry < max_retry);
258         sync();
259
260         free(part_path);
261         pclose(fp);
262         return;
263 }
264
265 #define CMD_FROZEN "FROZEN"
266 #define CMD_THAWED "THAWED"
267 static int freeze_processes_on_path(const char *frz_name, const char *part_path)
268 {
269         char *fuser_cmd = NULL;
270         FILE *fuser_fp;
271         char *line = NULL;
272         size_t len = 0;
273         int task_fd;
274         int freezer_fd;
275         char *freezer_procs;
276         char *freezer_state;
277         int ret;
278
279         ret = asprintf(&fuser_cmd, "fuser -m %s | grep -o '[0-9]*'", part_path);
280         if (ret < 0)
281                 return -1;
282
283         fuser_fp = popen(fuser_cmd, "r");
284         free(fuser_cmd);
285         if (fuser_fp == NULL)
286                 return -1;
287
288         ret = asprintf(&freezer_procs, "/sys/fs/cgroup/freezer/%s/cgroup.procs", frz_name);
289         if (ret < 0) {
290                 pclose(fuser_fp);
291                 return -1;
292         }
293
294         task_fd = open(freezer_procs, O_RDWR);
295         free(freezer_procs);
296         if (task_fd < 0) {
297                 pclose(fuser_fp);
298                 return -1;
299         }
300
301         while (getline(&line, &len, fuser_fp) != -1) {
302                 int ret;
303                 int str_len = strlen(line);
304                 if (str_len <= 1)
305                         continue;
306
307                 ret = write(task_fd, line, str_len-1);
308                 if (ret < 0)
309                         break;
310         }
311
312         close(task_fd);
313         free(line);
314         pclose(fuser_fp);
315
316         ret = asprintf(&freezer_state, "/sys/fs/cgroup/freezer/%s/freezer.state", frz_name);
317         if (ret < 0)
318                 return -1;
319
320         freezer_fd = open(freezer_state, O_RDWR);
321         free(freezer_state);
322         if (freezer_fd < 0)
323                 return -1;
324
325         ret = write(freezer_fd, CMD_FROZEN, strlen(CMD_FROZEN));
326         close(freezer_fd);
327         if (ret < 0)
328                 return -1;
329
330         return 0;
331 }
332
333 static bool check_frozen(const char *frz_name)
334 {
335         char *state_path = NULL;
336         char *line = NULL;
337         size_t len = 0;
338         FILE *fd;
339         int ret;
340         bool result = false;
341
342         ret = asprintf(&state_path, "/sys/fs/cgroup/freezer/%s/freezer.state", frz_name);
343         if (ret < 0)
344                 return false;
345
346         fd = fopen(state_path, "r");
347         free(state_path);
348         if (fd == NULL)
349                 return false;
350
351         ret = getline(&line, &len, fd);
352         if (ret != -1 && line) {
353                 if (!strncmp(line, CMD_FROZEN, strlen(CMD_FROZEN)))
354                         result = true;
355                 else
356                         result = false;
357
358         }
359
360         free(line);
361         fclose(fd);
362
363         return result;
364 }
365
366 static int thaw_processes_on_path(const char *frz_name)
367 {
368         int freezer_fd;
369         int ret;
370
371         char *freezer_state;
372         ret = asprintf(&freezer_state, "/sys/fs/cgroup/freezer/%s/freezer.state", frz_name);
373         if (ret < 0)
374                 return -1;
375
376         freezer_fd = open(freezer_state, O_RDWR);
377         free(freezer_state);
378         if (freezer_fd < 0)
379                 return -1;
380
381         ret = write(freezer_fd, CMD_THAWED, strlen(CMD_THAWED));
382         close(freezer_fd);
383         if (ret < 0)
384                 return -1;
385
386         return 0;
387 }
388
389 void suspend_path(const char *frz_name, const char *path, const int max_retry)
390 {
391         bool frozen = false;
392         int retry = 0;
393
394         freeze_processes_on_path(frz_name, path);
395
396         do {
397                 usleep((useconds_t)MSEC_TO_USEC(500));
398
399                 frozen = check_frozen(frz_name);
400
401                 retry++;
402
403         } while (!frozen && retry < max_retry);
404 }
405
406 void resume_path(const char *frz_name, const char *path)
407 {
408         thaw_processes_on_path(frz_name);
409 }
410
411 int get_privilege(pid_t pid, char *name, size_t len)
412 {
413         char path[PATH_MAX];
414         char attr[BUFF_MAX];
415         size_t attr_len;
416         FILE *fp;
417
418         snprintf(path, sizeof(path), APP_ATTR_PATH, pid);
419
420         fp = fopen(path, "r");
421         if (!fp)
422                 return -errno;
423
424         attr_len = fread(attr, 1, sizeof(attr) - 1, fp);
425         fclose(fp);
426         if (attr_len <= 0)
427                 return -ENOENT;
428
429         attr[attr_len] = '\0';
430
431         snprintf(name, len, "%s", attr);
432         return 0;
433 }
434
435 #define MODEL_NAME      "http://tizen.org/system/model_name"
436 #define MODEL_EMULATOR  "Emulator"
437
438 bool is_emulator(void)
439 {
440         int ret;
441         char *model_name = NULL;
442         static bool emul = false;
443         static int set = 0;
444
445         if (set)
446                 return emul;
447
448         ret = system_info_get_platform_string(MODEL_NAME, &model_name);
449         if (ret < 0) {
450                 _E("Cannot get model name: %d", ret);
451                 return emul;
452         }
453
454         if (!strncmp(MODEL_EMULATOR, model_name, strlen(model_name) + 1))
455                 emul = true;
456
457         set = 1;
458         free(model_name);
459
460         return emul;
461 }
462
463 int do_mkdir(const char *path, mode_t mode)
464 {
465         char d[PATH_MAX];
466         size_t s, l;
467         int r, p;
468
469         assert(path);
470
471         l = strlen(path);
472
473         for (p = 0, s = 0; p < l; p += s + 1) {
474                 s = strcspn(path + p, "/");
475                 if (!s)
476                         continue;
477
478                 assert(PATH_MAX > p + s + 1);
479
480                 r = snprintf(d, p + s + 1, "%s", path);
481                 if (r < 0)
482                         return r;
483
484                 r = mkdir(d, mode);
485                 if (r < 0 && errno != EEXIST)
486                         return -errno;
487         }
488
489         return 0;
490 }
491
492 static int do_copy_internal(const char *src, const char *dst, mode_t mode, bool force)
493 {
494         _cleanup_close_ int rfd = -1, wfd = -1;
495         char buf[1024];
496         ssize_t red;
497         int r;
498
499         assert(src);
500         assert(dst);
501
502         if (!force) {
503                 r = access(dst, F_OK);
504                 if (r == 0)
505                         return -EALREADY;
506                 else if (errno != ENOENT)
507                         return -errno;
508         }
509
510         wfd = open(dst, O_CREAT | O_WRONLY | O_TRUNC, mode);
511         if (wfd < 0)
512                 return -errno;
513
514         rfd = open(src, O_RDONLY);
515         if (rfd < 0)
516                 return -errno;
517
518         while ((red = read(rfd, buf, 1024)) > 0)
519                 if (write(wfd, buf, red) != red)
520                         return -errno;
521
522         if (red < 0)
523                 return -errno;
524
525         return 0;
526 }
527
528 int do_copy_force(const char *src, const char *dst)
529 {
530         assert(src);
531         assert(dst);
532
533         return do_copy_internal(src, dst, 0644, true);
534 }