[FIX] stop profiling when children terminate (Tizen app)
[platform/core/system/swap-manager.git] / daemon / utils.c
1 /*
2  *  DA manager
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  *
8  * Jaewon Lim <jaewon81.lim@samsung.com>
9  * Woojin Jung <woojin2.jung@samsung.com>
10  * Juyoung Kim <j0.kim@samsung.com>
11  * Cherepanov Vitaliy <v.cherepanov@samsung.com>
12  * Nikita Kalyazin    <n.kalyazin@samsung.com>
13  *
14  * Licensed under the Apache License, Version 2.0 (the "License");
15  * you may not use this file except in compliance with the License.
16  * You may obtain a copy of the License at
17  *
18  * http://www.apache.org/licenses/LICENSE-2.0
19  *
20  * Unless required by applicable law or agreed to in writing, software
21  * distributed under the License is distributed on an "AS IS" BASIS,
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23  * See the License for the specific language governing permissions and
24  * limitations under the License.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  * - Samsung RnD Institute Russia
29  *
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36
37 #include <signal.h>                     // for signal
38 #include <pthread.h>
39 #include <unistd.h>             // for unlink
40 #include <dirent.h>             // for opendir, readdir
41 #include <sys/types.h>  // for open
42 #include <sys/stat.h>   // for open
43 #include <fcntl.h>              // for open
44 #include <grp.h>                // for setgroups
45 #include <sys/wait.h> /* waitpid */
46
47 #include "daemon.h"
48 #include "utils.h"
49 #include "smack.h"
50 #include "debug.h"
51
52 #define BUFFER_MAX                      1024
53 #define SID_APP                         5000
54 #define MANIFEST_PATH           "/info/manifest.xml"
55
56 #define PROC_FS                 "/proc"
57 #define PROC_CMDLINE            "/proc/%s/cmdline"
58
59 #define APPDIR1                         "/opt/apps/"
60 #define APPDIR2                         "/opt/usr/apps/"
61
62 uint64_t str_to_uint64(char* str)
63 {
64         uint64_t res = 0;
65
66         if(str != NULL)
67         {
68                 while(*str >= '0' && *str <= '9')
69                 {
70                         res = res * 10 + (*str - '0');
71                         str++;
72                 }
73         }
74
75         return res;
76 }
77
78 int64_t str_to_int64(char* str)
79 {
80         int64_t res = 0;
81         int64_t factor = 1;
82
83         if(str != NULL)
84         {
85                 if(*str == '-')
86                 {
87                         factor = -1;
88                         str++;
89                 }
90                 else if(*str == '+')
91                 {
92                         factor = 1;
93                         str++;
94                 }
95
96                 while(*str >= '0' && *str <= '9')
97                 {
98                         res = res * 10 + (*str - '0');
99                         str++;
100                 }
101         }
102
103         return (res * factor);
104 }
105
106 // return 0 if succeed
107 // return -1 if error occured
108 int remove_indir(const char *dirname)
109 {
110         DIR *dir;
111         struct dirent *entry;
112         char path[PATH_MAX];
113
114         dir = opendir(dirname);
115         if(dir == NULL)
116         {
117                 return -1;
118         }
119
120         while((entry = readdir(dir)) != NULL)
121         {
122                 if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
123                 {
124                         snprintf(path, (size_t) PATH_MAX, "%s/%s", dirname, entry->d_name);
125                         if (entry->d_type != DT_DIR)    // file
126                         {
127                                 unlink(path);
128                         }
129                         else { }        // directory
130                 }
131         }
132         closedir(dir);
133
134         return 0;
135 }
136
137 /* execute applcation with executable binary path */
138 int exec_app_tizen(const char *app_id, const char *exec_path)
139 {
140         pid_t pid;
141
142         LOGI("exec %s\n", exec_path);
143
144         if (exec_path == NULL || !strlen(exec_path)) {
145                 LOGE("Executable path is not correct\n");
146                 return -1;
147         }
148         LOGI("launch app path is %s, executable path is %s\n"
149              "launch app name (%s), app_id (%s)\n",
150              LAUNCH_APP_PATH, exec_path, LAUNCH_APP_NAME, app_id);
151         pid = fork();
152         if (pid == -1)
153                 return -1;
154
155         if (pid > 0) { /* parent */
156                 int status, ret;
157                 do
158                         ret = waitpid(pid, &status, 0);
159                 while (ret == -1 && errno == EINTR);
160                 return 0;
161         } else { /* child */
162                 execl(LAUNCH_APP_PATH, LAUNCH_APP_NAME, app_id, LAUNCH_APP_SDK,
163                       DA_PRELOAD_EXEC, NULL);
164                 /* FIXME: If code flows here, it deserves greater attention */
165                 _Exit(EXIT_FAILURE);
166         }
167 }
168
169 int exec_app_common(const char* exec_path)
170 {
171         pid_t pid;
172         char command[PATH_MAX];
173
174         LOGI("exec %s\n", exec_path);
175         if (exec_path == NULL || !strlen(exec_path)) {
176                 LOGE("Executable path is not correct\n");
177                 return -1;
178         }
179
180         sprintf(command, "%s %s", DA_PRELOAD_TIZEN, exec_path);
181         LOGI("cmd: %s\n", command);
182
183         pid = fork();
184         if (pid == -1)
185                 return -1;
186
187         if (pid > 0) { /* parent */
188                 return 0;
189         } else { /* child */
190                 execl(SHELL_CMD, SHELL_CMD, "-c", command, NULL);
191                 /* FIXME: Again, such case deserve much more attention */
192                 _Exit(EXIT_FAILURE);
193         }
194 }
195
196 int exec_app_web(const char *app_id)
197 {
198         pid_t pid;
199
200         LOGI("wrt-launcher path is %s,\n"
201              "wrt-launcher name (%s), app_id (%s)\n",
202              WRT_LAUNCHER_PATH, WRT_LAUNCHER_NAME, app_id);
203
204         pid = fork();
205         if (pid == -1)
206                 return -1;
207
208         if (pid > 0) { /* parent */
209                 int status, ret;
210                 do
211                         ret = waitpid(pid, &status, 0);
212                 while (ret == -1 && errno == EINTR);
213                 return 0;
214         } else { /* child */
215                 execl(WRT_LAUNCHER_PATH,
216                       WRT_LAUNCHER_NAME,
217                       WRT_LAUNCHER_START,
218                       app_id,
219                       NULL);
220                 /* FIXME: If code flows here, it deserves greater attention */
221                 LOGE("Cannot run exec!\n");
222                 _Exit(EXIT_FAILURE);
223         }
224 }
225
226 void kill_app_web(const char *app_id)
227 {
228         pid_t pid;
229
230         LOGI("wrt-launcher path is %s,\n"
231              "wrt-launcher name (%s), app_id (%s)\n",
232              WRT_LAUNCHER_PATH, WRT_LAUNCHER_NAME, app_id);
233
234         pid = fork();
235         if (pid == -1)
236                 return;
237
238         if (pid > 0) { /* parent */
239                 int status, ret;
240                 do
241                         ret = waitpid(pid, &status, 0);
242                 while (ret == -1 && errno == EINTR);
243                 return;
244         } else { /* child */
245                 execl(WRT_LAUNCHER_PATH,
246                       WRT_LAUNCHER_NAME,
247                       WRT_LAUNCHER_KILL,
248                       app_id,
249                       NULL);
250                 /* FIXME: If code flows here, it deserves greater attention */
251                 LOGE("Cannot run exec!\n");
252                 _Exit(EXIT_FAILURE);
253         }
254 }
255
256 // find process id from executable binary path
257 pid_t find_pid_from_path(const char *path)
258 {
259         char buf[BUFFER_MAX];
260         char cmdline[PATH_MAX];
261         DIR *proc;
262         FILE *fp;
263         struct dirent *entry;
264         int found, len = strlen(path);
265         pid_t pid = 0;
266
267         LOGI("look for <%s>\n", path);
268
269         proc = opendir(PROC_FS);
270         if (!proc)
271                 goto out;
272
273         while ((entry = readdir(proc)) != NULL) {
274                 pid = (pid_t)atoi(entry->d_name);
275                 if (pid == 0)
276                         continue;
277
278                 snprintf(cmdline, sizeof(cmdline), PROC_CMDLINE, entry->d_name);
279
280                 fp = fopen(cmdline, "r");
281                 if (fp == NULL)
282                         continue;
283
284                 found = 0;
285                 if (fscanf(fp, "%s", buf) != EOF) /* read only argv[0] */
286                         found = (strncmp(path, buf, len) == 0);
287
288                 fclose(fp);
289
290                 if (found)
291                         goto out_close_dir;
292         }
293
294         pid = 0;
295
296 out_close_dir:
297         closedir(proc);
298
299 out:
300         return pid;
301 }
302
303 static pid_t get_pid_by_path(const char *binary_path)
304 {
305         pid_t pkg_pid;
306         int len;
307         char *real_path;
308         static const char exe_line[] = ".exe";
309
310
311         pkg_pid = find_pid_from_path(binary_path);
312         if (pkg_pid == 0) {
313                 len = strlen(binary_path);
314                 real_path = malloc(len + sizeof(exe_line));
315                 if (real_path == NULL) {
316                         LOGE("cannot alloc memory\n");
317                         return -1;
318                 }
319                 memcpy(real_path, binary_path, len + 1);
320
321                 // try remove or add ".exe" and get pid
322                 if (strcmp(real_path + len - (sizeof(exe_line) - 1), exe_line) == 0)
323                         // remove .exe from tPath
324                         real_path[len - (sizeof(exe_line) - 1)] = '\0';
325                 else
326                         // add .exe
327                         memcpy(&real_path[len], exe_line, sizeof(exe_line));
328
329                 pkg_pid = find_pid_from_path(real_path);
330                 free(real_path);
331         }
332
333         return pkg_pid;
334 }
335
336 static int find_alternative_bin_path(const char *binary_path, char *alter_bin_path) {
337         // alternative path may be /opt/apps/... or /opt/usr/apps/...)
338         if (strncmp(binary_path, APPDIR1, strlen(APPDIR1)) == 0) {
339                 strcpy(alter_bin_path, APPDIR2);
340                 strcat(alter_bin_path, binary_path + strlen(APPDIR1));
341         } else if (strncmp(binary_path, APPDIR2, strlen(APPDIR2)) == 0) {
342                 strcpy(alter_bin_path, APPDIR1);
343                 strcat(alter_bin_path, binary_path + strlen(APPDIR2));
344         } else {
345                 return 1;
346         }
347         return 0;
348 }
349
350 int kill_app(const char *binary_path)
351 {
352         pid_t pkg_pid;
353         char alter_bin_path[PATH_MAX];
354
355         LOGI("kill %s (%d)\n", binary_path, SIGKILL);
356
357         pkg_pid = get_pid_by_path(binary_path);
358
359         if (pkg_pid == 0) {
360                 if (find_alternative_bin_path(binary_path, alter_bin_path) == 0)
361                         pkg_pid = get_pid_by_path(alter_bin_path);
362         }
363
364         if (pkg_pid != 0) {
365                 if (kill(pkg_pid, SIGTERM) == -1) {
366                         LOGE("cannot kill %d -%d err<%s>\n", pkg_pid, SIGKILL,
367                              strerror(errno));
368                         return -1;
369                 } else {
370                         // we need sleep up there because kill() function
371                         // returns control immediately after send signal
372                         // without it app_launch returns err on start app
373                         sleep(1);
374                         LOGI("killed %d -%d\n", pkg_pid, SIGKILL);
375                 }
376         } else
377                 LOGI("cannot kill <%s>; process not found\n", binary_path);
378
379         return 0;
380 }
381
382 int get_executable(char* appPath, char* buf, int buflen)
383 {
384         int fd;
385
386         sprintf(buf, "%s.exe", appPath);
387         fd = open(buf, O_RDONLY);
388         if(fd != -1)
389         {
390                 close(fd);
391         }
392         else
393         {
394                 strcpy(buf, appPath);
395         }
396         return 0;
397 }
398
399 int get_app_install_path(char *strAppInstall, int length)
400 {
401         FILE *fp;
402         char buf[BUFFER_MAX];
403         char *p;
404         int i;
405
406         if ((fp = fopen(DA_INSTALL_PATH, "r")) == NULL)
407         {
408                 LOGE("Failed to open %s\n", DA_INSTALL_PATH);
409                 return -1;
410         }
411
412         /*ex : <15>   DW_AT_comp_dir    : (indirect string, offset: 0x25f): /home/yt/workspace/templatetest/Debug-Tizen-Emulator        */
413         while (fgets(buf, BUFFER_MAX, fp) != NULL)
414         {
415                 //name
416                 p = buf;
417                 for (i = 0; i < BUFFER_MAX; i++)
418                 {
419                         if (*p == ':')
420                                 break;
421                         p++;
422                 }
423
424                 if (*p != ':')
425                         break;
426                 else
427                         p++;
428
429                 //(...,offset:...)
430                 for (; i < BUFFER_MAX; i++)
431                 {
432                         if (*p == '(')
433                         {
434                                 while (*p != ')')
435                                 {
436                                         p++;
437                                 }
438                         }
439                         if (*p == ':')
440                                 break;
441                         p++;
442                 }
443
444                 //find
445                 if (*p != ':')
446                         break;
447                 for (; i < BUFFER_MAX - 1; i++)
448                 {
449                         if (*p == ':' || *p == ' ' || *p == '\t')
450                                 p++;
451                         else
452                                 break;
453                 }
454
455                 //name
456                 if (strlen(p) <= length)
457                 {
458                         sprintf(strAppInstall, "%s", p);
459                         for (i = 0; i < strlen(p); i++)
460                         {
461                                 if (strAppInstall[i] == '\n' || strAppInstall[i] == '\t')
462                                 {
463                                         strAppInstall[i] = '\0';
464                                         break;
465                                 }
466                         }
467                         fclose(fp);
468                         return 1;
469                 }
470         }
471         fclose(fp);
472         return -1;
473 }
474
475 int is_app_built_pie(void)
476 {
477         int result;
478         FILE *fp;
479         char buf[BUFFER_MAX];
480
481         if((fp = fopen(DA_BUILD_OPTION, "r")) == NULL)
482         {
483                 LOGE("Failed to open %s\n", DA_BUILD_OPTION);
484                 return -1;
485         }
486
487         if(fgets(buf, BUFFER_MAX, fp) != NULL)
488         {
489                 if(strcmp(buf, "DYN\n") == 0)
490                         result = 1;
491                 else if(strcmp(buf, "EXEC\n") == 0)
492                         result = 0;
493                 else
494                         result = -1;
495         }
496         else
497         {
498                 result = -1;
499         }
500         fclose(fp);
501
502         return result;
503 }
504
505 int get_app_base_address(int *baseAddress)
506 {
507         int res;
508         FILE *fp;
509         char buf[BUFFER_MAX];
510
511         if((fp = fopen(DA_BASE_ADDRESS, "r")) == NULL)
512         {
513                 LOGE("Failed to open %s\n", DA_BASE_ADDRESS);
514                 return -1;
515         }
516
517         if(fgets(buf, BUFFER_MAX, fp) != NULL)
518         {
519                 res = sscanf(buf, "%x", baseAddress);
520         }
521         else
522         {
523                 res = -1;
524         }
525         fclose(fp);
526
527         return res;
528 }
529
530 int is_same_app_process(char* appPath, int pid)
531 {
532         int ret = 0;
533         int tlen;
534         FILE *fp;
535         char buf[BUFFER_MAX];
536         char cmdPath[PATH_MAX];
537         char tPath[PATH_MAX];
538         char buf_res[PATH_MAX];
539         char tPath_res[PATH_MAX];
540
541         strcpy(tPath, appPath);
542         tlen = strlen(tPath);
543         if(strcmp(tPath + tlen - 4, ".exe") == 0)
544         {
545                 // remove .exe from tPath
546                 tPath[tlen - 4] = '\0';
547         }
548
549         sprintf(cmdPath, "/proc/%d/cmdline", pid);
550
551         if((fp = fopen(cmdPath, "r")) == NULL)
552         {
553                 return 0;
554         }
555
556         if(fgets(buf, BUFFER_MAX, fp) != NULL)
557         {
558                 tlen = strlen(buf);
559                 if(strcmp(buf + tlen - 4, ".exe") == 0)
560                 {
561                         // remove .exe from tPath
562                         buf[tlen - 4] = '\0';
563                 }
564
565                 dereference_tizen_exe_path(buf, buf_res);
566                 dereference_tizen_exe_path(tPath, tPath_res);
567
568                 if(strcmp(buf_res, tPath_res) == 0)
569                         ret = 1;
570                 else
571                         ret = 0;
572         }
573         fclose(fp);
574
575         return ret;
576 }
577
578 char *dereference_tizen_exe_path(const char *path, char *resolved)
579 {
580         char *res = NULL;
581         char tmp_path[PATH_MAX];
582
583         resolved[0] = 0;
584         //try resolve <path>.exe
585         sprintf(tmp_path, "%s.exe", path);
586         if ((res = realpath(tmp_path, resolved)) == NULL) {
587                 //try to resolve path <path>
588                 res = realpath(path, resolved);
589         }
590
591         return res;
592 }
593
594 float get_uptime(void)
595 {
596         const char *LINUX_UPTIME_FILE = "/proc/uptime";
597         FILE *fp = fopen(LINUX_UPTIME_FILE, "r");
598         float uptime;
599         if (!fp)
600                 return 0.0;
601
602         if (fscanf(fp, "%f", &uptime) != 1)
603                 uptime = 0.0;
604
605         fclose(fp);
606         return uptime;
607 }