shared: Move suspend_path()/resume_path() to tzip
[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 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <time.h>
26 #include <assert.h>
27 #include <sys/time.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <dirent.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <errno.h>
35 #include <poll.h>
36 #include <mntent.h>
37 #include <system_info.h>
38 #include <sys/mount.h>
39 #include "log.h"
40 #include "common.h"
41
42 #define BUFF_MAX        255
43
44 #define APP_ATTR_PATH "/proc/%d/attr/current"
45
46 int get_cmdline_name(pid_t pid, char *cmdline, size_t cmdline_size)
47 {
48         int fd, ret;
49         char buf[PATH_MAX + 1];
50         char *filename;
51
52         snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
53         fd = open(buf, O_RDONLY);
54         if (fd < 0) {
55                 errno = ESRCH;
56                 return -1;
57         }
58
59         ret = read(fd, buf, PATH_MAX);
60         close(fd);
61         if (ret < 0)
62                 return -1;
63
64         buf[PATH_MAX] = '\0';
65
66         filename = strrchr(buf, '/');
67         if (filename == NULL)
68                 filename = buf;
69         else
70                 filename = filename + 1;
71
72         if (cmdline_size < strlen(filename) + 1) {
73                 errno = EOVERFLOW;
74                 return -1;
75         }
76
77         strncpy(cmdline, filename, cmdline_size - 1);
78         cmdline[cmdline_size - 1] = '\0';
79         return 0;
80 }
81
82 int is_app(pid_t pid)
83 {
84         char attr[64];
85         size_t len;
86         int ret;
87
88         ret = get_privilege(pid, attr, sizeof(attr));
89         if (ret < 0) {
90                 _E("Failed to get privilege of PID(%d).", pid);
91                 return -1;
92         }
93
94         len = strlen(attr) + 1;
95
96         if (!strncmp("System", attr, len))
97                 return 0;
98
99         if (!strncmp("User", attr, len))
100                 return 0;
101
102         if (!strncmp("System::Privileged", attr, len))
103                 return 0;
104
105         return 1;
106 }
107
108 /*
109  * Helper function
110  * - Read from sysfs entry
111  * - Write to sysfs entry
112  */
113 int sys_check_node(char *path)
114 {
115         int fd;
116
117         fd = open(path, O_RDONLY);
118         if (fd == -1)
119                 return -1;
120
121         close(fd);
122         return 0;
123 }
124
125 int get_systemd_reboot_param(char *buf, unsigned bufsize)
126 {
127         int r = sys_read_buf("/run/systemd/reboot-param", buf, bufsize);
128         if (r < 0)
129                 return r;
130
131         if (r > 0 && buf[r - 1] == '\n') {
132                 buf[r - 1] = '\0';
133                 r -= 1;
134         }
135
136         return r;
137 }
138
139 static int terminate_processes_on_partition(const char *partition, bool force)
140 {
141         const char *argv[7] = {"/usr/bin/fuser", "-m", "-k", "-s", NULL, NULL, NULL};
142         int argc;
143
144         if (force)
145                 argv[4] = "-SIGKILL";
146         else
147                 argv[4] = "-SIGTERM";
148
149         argv[5] = partition;
150         argc = sizeof(argv) / sizeof(argv[0]);
151
152         return run_child(argc, argv);
153 }
154
155 int mount_check(const char *path)
156 {
157         int ret = false;
158         struct mntent *mnt;
159         const char *table = "/etc/mtab";
160         FILE *fp;
161         int len;
162
163         fp = setmntent(table, "r");
164         if (!fp)
165                 return ret;
166
167         len = strlen(path) + 1;
168         while (1) {
169                 mnt = getmntent(fp);
170                 if (mnt == NULL)
171                         break;
172                 if (!strncmp(mnt->mnt_dir, path, len)) {
173                         ret = true;
174                         break;
175                 }
176         }
177         endmntent(fp);
178         return ret;
179 }
180
181 static int get_num_processes_on_partition(const char *part_path)
182 {
183         FILE *fp;
184         char *cmd = NULL;
185         char *line = NULL;
186         size_t len = 0;
187         int num_processes = 0;
188         int ret = 0;
189
190         ret = asprintf(&cmd, "fuser -m %s | grep -o '[0-9]*'", part_path);
191         if (ret < 0)
192                 return -1;
193
194         printf("cmd=%s\n", cmd);
195         fp = popen(cmd, "r");
196         free(cmd);
197         if (fp == NULL)
198                 return -1;
199
200         while (getline(&line, &len, fp) != -1)
201                 num_processes++;
202
203         free(line);
204         pclose(fp);
205
206         return num_processes;
207 }
208
209 void umount_partition_by_kill(const char *path, const int max_retry)
210 {
211         FILE *fp;
212         char *part_path = NULL;
213         size_t len = 0;
214         int ret = 0, retry = 0;
215         int remain;
216         char *cmd = NULL;
217
218         /* if the path is not a mountpoint, do not perform umounting and killing */
219         if (!mount_check(path))
220                 return;
221
222         ret = asprintf(&cmd, "mount | grep \" on %s \" | awk '{print $1}'", path);
223         if (ret < 0)
224                 return;
225
226         fp = popen(cmd, "r");
227         free(cmd);
228         if (!fp)
229                 return;
230
231         ret = getline(&part_path, &len, fp);
232         if (ret == -1 || !part_path) {
233                 pclose(fp);
234                 free(part_path);
235                 return;
236         } else if (ret > 0 && *(part_path + ret - 1) == '\n') {
237                 *(part_path + ret -1) = '\0';
238         }
239
240         sync();
241         umount2(path, MNT_DETACH);
242
243         do {
244                 /* Kill processes with SIGTERM */
245                 terminate_processes_on_partition(part_path, false);
246                 usleep((useconds_t)MSEC_TO_USEC(500));
247
248                 /* Kill processes with SIGKILL */
249                 terminate_processes_on_partition(part_path, true);
250                 usleep((useconds_t)MSEC_TO_USEC(200));
251
252                 remain = get_num_processes_on_partition(part_path);
253
254                 retry++;
255
256         } while (remain > 0 && retry < max_retry);
257         sync();
258
259         free(part_path);
260         pclose(fp);
261         return;
262 }
263
264 int get_privilege(pid_t pid, char *name, size_t len)
265 {
266         char path[PATH_MAX];
267         char attr[BUFF_MAX];
268         size_t attr_len;
269         FILE *fp;
270
271         snprintf(path, sizeof(path), APP_ATTR_PATH, pid);
272
273         fp = fopen(path, "r");
274         if (!fp)
275                 return -errno;
276
277         attr_len = fread(attr, 1, sizeof(attr) - 1, fp);
278         fclose(fp);
279         if (attr_len <= 0)
280                 return -ENOENT;
281
282         attr[attr_len] = '\0';
283
284         snprintf(name, len, "%s", attr);
285         return 0;
286 }
287
288 #define MODEL_NAME      "http://tizen.org/system/model_name"
289 #define MODEL_EMULATOR  "Emulator"
290
291 bool is_emulator(void)
292 {
293         int ret;
294         char *model_name = NULL;
295         static bool emul = false;
296         static int set = 0;
297
298         if (set)
299                 return emul;
300
301         ret = system_info_get_platform_string(MODEL_NAME, &model_name);
302         if (ret < 0) {
303                 _E("Cannot get model name: %d", ret);
304                 return emul;
305         }
306
307         if (!strncmp(MODEL_EMULATOR, model_name, strlen(model_name) + 1))
308                 emul = true;
309
310         set = 1;
311         free(model_name);
312
313         return emul;
314 }
315
316 int do_mkdir(const char *path, mode_t mode)
317 {
318         char d[PATH_MAX];
319         size_t s, l;
320         int r, p;
321
322         assert(path);
323
324         l = strlen(path);
325
326         for (p = 0, s = 0; p < l; p += s + 1) {
327                 s = strcspn(path + p, "/");
328                 if (!s)
329                         continue;
330
331                 assert(PATH_MAX > p + s + 1);
332
333                 r = snprintf(d, p + s + 1, "%s", path);
334                 if (r < 0)
335                         return r;
336
337                 r = mkdir(d, mode);
338                 if (r < 0 && errno != EEXIST)
339                         return -errno;
340         }
341
342         return 0;
343 }
344
345 static int do_copy_internal(const char *src, const char *dst, mode_t mode, bool force)
346 {
347         _cleanup_close_ int rfd = -1, wfd = -1;
348         char buf[1024];
349         ssize_t red;
350         int r;
351
352         assert(src);
353         assert(dst);
354
355         if (!force) {
356                 r = access(dst, F_OK);
357                 if (r == 0)
358                         return -EALREADY;
359                 else if (errno != ENOENT)
360                         return -errno;
361         }
362
363         wfd = open(dst, O_CREAT | O_WRONLY | O_TRUNC, mode);
364         if (wfd < 0)
365                 return -errno;
366
367         rfd = open(src, O_RDONLY);
368         if (rfd < 0)
369                 return -errno;
370
371         while ((red = read(rfd, buf, 1024)) > 0)
372                 if (write(wfd, buf, red) != red)
373                         return -errno;
374
375         if (red < 0)
376                 return -errno;
377
378         return 0;
379 }
380
381 int do_copy_force(const char *src, const char *dst)
382 {
383         assert(src);
384         assert(dst);
385
386         return do_copy_internal(src, dst, 0644, true);
387 }
388
389 int get_command(pid_t pid, char *comm, size_t len)
390 {
391         FILE *fp;
392         char path[PATH_MAX];
393         char name[NAME_MAX];
394         char *tmp;
395         int ret;
396
397         snprintf(path, sizeof(path), "/proc/%d/comm", pid);
398
399         fp = fopen(path, "r");
400         if (!fp) {
401                 _E("Failed to open file %s, errno:%d", path, errno);
402                 return -errno;
403         }
404
405         ret = fread(name, 1, sizeof(name) - 1, fp);
406         name[ret] = '\0';
407         fclose(fp);
408
409         tmp = name;
410         while (*tmp != '\0') {
411                 if (*tmp == '\n' ||
412                                 *tmp == '\r') {
413                         *tmp = '\0';
414                         break;
415                 }
416                 tmp++;
417         }
418
419         snprintf(comm, len, "%s", name);
420
421         return 0;
422 }
423