[FIX] wrong pack size of system memory total/used
[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 <pthread.h>
38 #include <unistd.h>             // for unlink
39 #include <dirent.h>             // for opendir, readdir
40 #include <sys/types.h>  // for open
41 #include <sys/stat.h>   // for open
42 #include <fcntl.h>              // for open
43 #include <grp.h>                // for setgroups
44 #ifndef LOCALTEST
45 #include <sys/smack.h>
46 #endif
47 #include "daemon.h"
48 #include "utils.h"
49 #include "debug.h"
50
51 #define BUFFER_MAX                      1024
52 #define APP_GROUPS_MAX          100
53 #define APP_GROUP_LIST          "/usr/share/privilege-control/app_group_list"
54 #define SELF_LABEL_FILE         "/proc/self/attr/current"
55
56 #ifndef LOCALTEST
57 #define SMACK_LABEL_LEN         255
58 #endif
59
60 #define SID_APP                         5000
61 #define MANIFEST_PATH           "/info/manifest.xml"
62
63 #define APPDIR1                         "/opt/apps/"
64 #define APPDIR2                         "/opt/usr/apps/"
65
66 uint64_t str_to_uint64(char* str)
67 {
68         uint64_t res = 0;
69
70         if(str != NULL)
71         {
72                 while(*str >= '0' && *str <= '9')
73                 {
74                         res = res * 10 + (*str - '0');
75                         str++;
76                 }
77         }
78
79         return res;
80 }
81
82 int64_t str_to_int64(char* str)
83 {
84         int64_t res = 0;
85         int64_t factor = 1;
86
87         if(str != NULL)
88         {
89                 if(*str == '-')
90                 {
91                         factor = -1;
92                         str++;
93                 }
94                 else if(*str == '+')
95                 {
96                         factor = 1;
97                         str++;
98                 }
99
100                 while(*str >= '0' && *str <= '9')
101                 {
102                         res = res * 10 + (*str - '0');
103                         str++;
104                 }
105         }
106
107         return (res * factor);
108 }
109
110 int read_line(const int fd, char* ptr, const unsigned int maxlen)
111 {
112         unsigned int n = 0;
113         char c[2];
114         int rc;
115
116         while(n != maxlen)
117         {
118                 if((rc = read(fd, c, 1)) != 1)
119                         return -1; // eof or read err
120
121                 if(*c == '\n')
122                 {
123                         ptr[n] = 0;
124                         return n;
125                 }
126                 ptr[n++] = *c;
127         }
128         return -1; // no space
129 }
130
131 #ifndef LOCALTEST
132 int smack_set_label_for_self(const char *label)
133 {
134         int len;
135         int fd;
136         int ret;
137
138         len = strnlen(label, SMACK_LABEL_LEN + 1);
139         if (len > SMACK_LABEL_LEN)
140                 return -1;
141
142         fd = open(SELF_LABEL_FILE, O_WRONLY);
143         if (fd < 0)
144                 return -1;
145
146         ret = write(fd, label, len);
147         close(fd);
148
149         return (ret < 0) ? -1 : 0;
150 }
151 #endif
152
153 void set_appuser_groups(void)
154 {
155         int fd = 0;
156         char buffer[5];
157         gid_t t_gid = -1;
158         gid_t groups[APP_GROUPS_MAX] = {0, };
159         int cnt = 0;
160
161         // groups[cnt++] = SID_DEVELOPER;
162         fd = open(APP_GROUP_LIST, O_RDONLY);
163         if(fd < 0)
164         {
165                 LOGE("cannot get app's group lists from %s", APP_GROUP_LIST);
166                 return;
167         }
168
169         for(;;)
170         {
171                 if(read_line(fd, buffer, sizeof buffer) < 0)
172                 {
173                         break;
174                 }
175
176                 t_gid = strtoul(buffer, 0, 10);
177                 errno = 0;
178                 if(errno != 0)
179                 {
180                         LOGE("cannot change string to integer: [%s]\n", buffer);
181                         continue;
182                 }
183
184                 if(t_gid)
185                 {
186                         if(cnt < APP_GROUPS_MAX)
187                         {
188                                 groups[cnt++] = t_gid;
189                         }
190                         else
191                         {
192                                 LOGE("cannot add groups more than %d", APP_GROUPS_MAX);
193                                 break;
194                         }
195                 }
196         }
197
198         if(cnt > 0)
199         {
200                 if(setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0)
201                 {
202                         fprintf(stderr, "set groups failed errno: %d\n", errno);
203                         close(fd);
204                         exit(1);
205                 }
206         }
207         close(fd);
208 }
209
210 #ifndef LOCALTEST
211 int get_smack_label(const char* execpath, char* buffer, int buflen)
212 {
213         char* appid = NULL;
214         int rc;
215
216         rc = smack_lgetlabel(execpath, &appid, SMACK_LABEL_ACCESS);
217         if(rc == 0 && appid != NULL)
218         {
219                 strncpy(buffer, appid, (buflen < strlen(appid))? buflen:strlen(appid));
220                 free(appid);
221                 return 0;
222         }
223         else
224                 return -1;
225 }
226 #endif
227
228 int get_appid(const char* execpath, char* buffer, int buflen)
229 {
230         int i, ret = 0;
231         char* temp;
232         if(strncmp(execpath, APPDIR1, strlen(APPDIR1)) == 0)
233         {
234                 execpath = execpath + strlen(APPDIR1);
235                 temp = strchr(execpath, '/');
236                 for(i = 0; i < strlen(execpath); i++)
237                 {
238                         if(execpath + i == temp)
239                                 break;
240                         buffer[i] = execpath[i];
241                 }
242                 buffer[i] = '.';
243                 buffer[i+1] = '\0';
244                 temp = strrchr(execpath, '/');
245                 if(temp != NULL)
246                 {
247                         temp++;
248                         strcat(buffer, temp);
249                 }
250         }
251         else if(strncmp(execpath, APPDIR2, strlen(APPDIR2)) == 0)
252         {
253                 execpath = execpath + strlen(APPDIR2);
254                 temp = strchr(execpath, '/');
255                 for(i = 0; i < strlen(execpath); i++)
256                 {
257                         if(execpath + i == temp)
258                                 break;
259                         buffer[i] = execpath[i];
260                 }
261                 buffer[i] = '.';
262                 buffer[i+1] = '\0';
263                 temp = strrchr(execpath, '/');
264                 if(temp != NULL)
265                 {
266                         temp++;
267                         strcat(buffer, temp);
268                 }
269         }
270         else
271         {
272                 ret = -1;
273         }
274
275         return ret;
276 }
277
278 // return 0 if succeed
279 // return -1 if error occured
280 int remove_indir(const char *dirname)
281 {
282         DIR *dir;
283         struct dirent *entry;
284         char path[PATH_MAX];
285
286         dir = opendir(dirname);
287         if(dir == NULL)
288         {
289                 return -1;
290         }
291
292         while((entry = readdir(dir)) != NULL)
293         {
294                 if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
295                 {
296                         snprintf(path, (size_t) PATH_MAX, "%s/%s", dirname, entry->d_name);
297                         if (entry->d_type != DT_DIR)    // file
298                         {
299                                 unlink(path);
300                         }
301                         else { }        // directory
302                 }
303         }
304         closedir(dir);
305
306         return 0;
307 }
308
309 // get application name from executable binary path
310 char* get_app_name(char* binary_path)
311 {
312         char* pos;
313
314         pos = strrchr(binary_path, '/');
315         if(pos != NULL)
316                 pos++;
317
318         return pos;
319 }
320
321 // return 0 to normal case
322 // return non-zero to error case
323 int get_manifest_path(const char* exec_path, char* buf, int buflen)
324 {
325         char* chr;
326
327         strcpy(buf, exec_path);
328
329         chr = strrchr(buf, '/');
330         if(chr == NULL)
331                 return -1;
332
333         *chr = '\0';
334
335         chr = strrchr(buf, '/');
336         if(chr == NULL)
337                 return -1;
338
339         *chr = '\0';
340
341         strcat(buf, MANIFEST_PATH);
342         return 0;
343 }
344
345 // execute applcation with executable binary path
346 // return 0 to fail to execute
347 // return 1 to succeed to execute
348 int exec_app_tizen(const char *app_id, const char *exec_path)
349 {
350         LOGI("exec %s\n", exec_path);
351         pid_t pid;
352         //char command[PATH_MAX];
353         //char appid[PATH_MAX];
354
355         if (exec_path == NULL || !strlen(exec_path)) {
356                 LOGE("Executable path is not correct\n");
357                 return 0;
358         }
359
360         pid = fork();
361         if (pid == -1)
362                 return 1;
363         else if (pid > 0)
364                 return 0; // exit parent process with success
365
366         LOGI("launch app path is %s, executable path is %s\n"
367              "launch app name (%s), app_id (%s)\n",
368              LAUNCH_APP_PATH, exec_path,
369              LAUNCH_APP_NAME, app_id);
370         execl(LAUNCH_APP_PATH, LAUNCH_APP_NAME, app_id, LAUNCH_APP_SDK,
371               DA_PRELOAD_EXEC, NULL);
372
373         return 0;
374 }
375
376 int exec_app_common(const char* exec_path)
377 {
378         LOGI("kill %s\n", exec_path);
379
380         pid_t pid;
381         int hw_acc = 0;
382         char manifest[PATH_MAX];
383         char command[PATH_MAX];
384 #ifndef LOCALTEST
385         // TODO: check if this makes sense
386         /* char appid[SMACK_LABEL_LEN]; */
387 #endif
388         if (exec_path == NULL || !strlen(exec_path))  {
389                 LOGE("Executable path is not correct\n");
390                 return 1;
391         }
392
393         pid = fork();
394         if (pid == -1)
395                 return 1;
396         else if (pid > 0)
397                 return 0; // exit parent process with success
398
399         if (get_manifest_path(exec_path, manifest, PATH_MAX) == 0) {
400                 FILE* fp;
401                 char buffer[BUFFER_MAX];
402                 char* res;
403
404                 // grep for manifest
405                 sprintf(command, "grep \"HwAcceleration=\\\"On\\\"\" %s",
406                         manifest);
407                 fp = popen(command, "r");
408                 if (fp != NULL) {
409                         buffer[0] = '\0';
410                         res = fgets(buffer, BUFFER_MAX, fp);
411                         if (res != NULL && strlen(buffer) != 0) {
412                                 hw_acc = 1;
413                         }
414                         pclose(fp);
415                 }
416         }
417
418         // FIXME: I think the followin does not make sense
419 /* #ifndef LOCALTEST */
420 /*      if (get_smack_label(exec_path, appid, SMACK_LABEL_LEN - 1) < 0) { */
421 /*              LOGE("failed to get smack label\n"); */
422 /*              return 1; */
423 /*      } else */
424 /* #endif */
425 /*      { */
426 /* #ifndef LOCALTEST */
427 /*              LOGI("smack lable is %s\n", appid); */
428 /*              if(smack_set_label_for_self(appid) < 0) { */
429 /*                      LOGE("failed to set label for self\n"); */
430 /*              } */
431 /* #endif */
432 /*              set_appuser_groups(); */
433 /*              if (setgid(SID_APP) < 0) { */
434 /*                      LOGE("failed to setgid\n"); */
435 /*              } */
436 /*              if (setuid(SID_APP) < 0) { */
437 /*                      LOGE("failed to setuid\n"); */
438 /*              } */
439
440 /*              pid = getpid(); */
441 /*              if (setpgid(pid, pid) < 0) { */
442 /*                      LOGE("failed to setpgid\n"); */
443 /*              } */
444
445 /*              if (hw_acc != 0) { */
446 /*                      sprintf(command, "HWACC=USE %s %s", DA_PRELOAD(app_type), exec_path); */
447 /*              } else { */
448 /*                      sprintf(command, "%s %s", DA_PRELOAD(app_type), exec_path); */
449 /*              } */
450
451 /*              LOGI("launch app path is %s, executable path is %s\n", LAUNCH_APP_PATH, exec_path); */
452 /*              execl(SHELL_CMD, SHELL_CMD, "-c", command, NULL); */
453 /*              return 0; */
454 /*      } */
455         // TODO:
456         /* if (hw_acc) */
457         /*      sprintf(command, "HWACC=USE %s %s", */
458         /*              DA_PRELOAD(app_type), exec_path); */
459         /* else */
460         /*      sprintf(command, "%s %s", */
461         /*              DA_PRELOAD(app_type), exec_path); */
462 #ifndef LOCALTEST
463         sprintf(command, "%s %s",
464                 DA_PRELOAD_OSP, exec_path);
465 #else /* LOCALTEST */
466         sprintf(command, "%s", exec_path);
467 #endif /* LOCALTEST */
468
469         LOGI("cmd: %s\n", command);
470         execl(SHELL_CMD, SHELL_CMD, "-c", command, NULL);
471
472         return 0;
473 }
474
475 // find process id from executable binary path
476 pid_t find_pid_from_path(const char* path)
477 {
478         pid_t status = -1;
479
480         char buffer [BUFFER_MAX];
481         char command [BUFFER_MAX];
482
483         sprintf(command, "/bin/pidof %s", path);
484
485         FILE *fp = popen(command, "r");
486         if (!fp)
487         {
488                 LOGW("Getting pidof %s is failed\n", path);
489                 return status;
490         }
491
492         while (fgets(buffer, BUFFER_MAX, fp) != NULL)
493         {
494                 LOGI("result of 'pidof' is %s\n", buffer);
495         }
496
497         pclose(fp);
498
499         if (strlen(buffer) > 0)
500         {
501                 if (sscanf(buffer,"%d\n", &status) != 1)
502                 {
503                         LOGW("Failed to read result buffer of 'pidof',"
504                                  " status(%d) with cmd '%s'\n", status, command);
505                         return -1;
506                 }
507         }
508
509         return status;
510 }
511
512 void kill_app(const char* binary_path)
513 {
514         LOGI("kill %s\n", binary_path);
515
516         pid_t pkg_pid;
517         char command[PATH_MAX];
518
519         pkg_pid = find_pid_from_path(binary_path);
520         if (pkg_pid > 0) {
521                 sprintf(command, "kill -9 %d", pkg_pid);
522                 system(command);
523         }
524 }
525
526 int get_executable(char* appPath, char* buf, int buflen)
527 {
528         int fd;
529
530         sprintf(buf, "%s.exe", appPath);
531         fd = open(buf, O_RDONLY);
532         if(fd != -1)
533         {
534                 close(fd);
535         }
536         else
537         {
538                 strcpy(buf, appPath);
539         }
540         return 0;
541 }
542
543 int get_app_install_path(char *strAppInstall, int length)
544 {
545         FILE *fp;
546         char buf[BUFFER_MAX];
547         char *p;
548         int i;
549
550         if ((fp = fopen(DA_INSTALL_PATH, "r")) == NULL)
551         {
552                 LOGE("Failed to open %s\n", DA_INSTALL_PATH);
553                 return -1;
554         }
555
556         /*ex : <15>   DW_AT_comp_dir    : (indirect string, offset: 0x25f): /home/yt/workspace/templatetest/Debug-Tizen-Emulator        */
557         while (fgets(buf, BUFFER_MAX, fp) != NULL)
558         {
559                 //name
560                 p = buf;
561                 for (i = 0; i < BUFFER_MAX; i++)
562                 {
563                         if (*p == ':')
564                                 break;
565                         p++;
566                 }
567
568                 if (*p != ':')
569                         break;
570                 else
571                         p++;
572
573                 //(...,offset:...)
574                 for (; i < BUFFER_MAX; i++)
575                 {
576                         if (*p == '(')
577                         {
578                                 while (*p != ')')
579                                 {
580                                         p++;
581                                 }
582                         }
583                         if (*p == ':')
584                                 break;
585                         p++;
586                 }
587
588                 //find
589                 if (*p != ':')
590                         break;
591                 for (; i < BUFFER_MAX - 1; i++)
592                 {
593                         if (*p == ':' || *p == ' ' || *p == '\t')
594                                 p++;
595                         else
596                                 break;
597                 }
598
599                 //name
600                 if (strlen(p) <= length)
601                 {
602                         sprintf(strAppInstall, "%s", p);
603                         for (i = 0; i < strlen(p); i++)
604                         {
605                                 if (strAppInstall[i] == '\n' || strAppInstall[i] == '\t')
606                                 {
607                                         strAppInstall[i] = '\0';
608                                         break;
609                                 }
610                         }
611                         fclose(fp);
612                         return 1;
613                 }
614         }
615         fclose(fp);
616         return -1;
617 }
618
619 int is_app_built_pie(void)
620 {
621         int result;
622         FILE *fp;
623         char buf[BUFFER_MAX];
624
625         if((fp = fopen(DA_BUILD_OPTION, "r")) == NULL)
626         {
627                 LOGE("Failed to open %s\n", DA_BUILD_OPTION);
628                 return -1;
629         }
630
631         if(fgets(buf, BUFFER_MAX, fp) != NULL)
632         {
633                 if(strcmp(buf, "DYN\n") == 0)
634                         result = 1;
635                 else if(strcmp(buf, "EXEC\n") == 0)
636                         result = 0;
637                 else
638                         result = -1;
639         }
640         else
641         {
642                 result = -1;
643         }
644         fclose(fp);
645
646         return result;
647 }
648
649 int get_app_base_address(int *baseAddress)
650 {
651         int res;
652         FILE *fp;
653         char buf[BUFFER_MAX];
654
655         if((fp = fopen(DA_BASE_ADDRESS, "r")) == NULL)
656         {
657                 LOGE("Failed to open %s\n", DA_BASE_ADDRESS);
658                 return -1;
659         }
660
661         if(fgets(buf, BUFFER_MAX, fp) != NULL)
662         {
663                 res = sscanf(buf, "%x", baseAddress);
664         }
665         else
666         {
667                 res = -1;
668         }
669         fclose(fp);
670
671         return res;
672 }
673
674 int is_same_app_process(char* appPath, int pid)
675 {
676         int ret = 0;
677         int tlen;
678         FILE *fp;
679         char buf[BUFFER_MAX];
680         char cmdPath[PATH_MAX];
681         char tPath[PATH_MAX];
682         char buf_res[PATH_MAX];
683         char tPath_res[PATH_MAX];
684
685         strcpy(tPath, appPath);
686         tlen = strlen(tPath);
687         if(strcmp(tPath + tlen - 4, ".exe") == 0)
688         {
689                 // remove .exe from tPath
690                 tPath[tlen - 4] = '\0';
691         }
692
693         sprintf(cmdPath, "/proc/%d/cmdline", pid);
694
695         if((fp = fopen(cmdPath, "r")) == NULL)
696         {
697                 return 0;
698         }
699
700         if(fgets(buf, BUFFER_MAX, fp) != NULL)
701         {
702                 tlen = strlen(buf);
703                 if(strcmp(buf + tlen - 4, ".exe") == 0)
704                 {
705                         // remove .exe from tPath
706                         buf[tlen - 4] = '\0';
707                 }
708
709                 dereference_tizen_exe_path(buf, buf_res);
710                 dereference_tizen_exe_path(tPath, tPath_res);
711
712                 if(strcmp(buf_res, tPath_res) == 0)
713                         ret = 1;
714                 else
715                         ret = 0;
716         }
717         fclose(fp);
718
719         return ret;
720 }
721
722 char *dereference_tizen_exe_path(const char *path, char *resolved)
723 {
724         char *res = NULL;
725         char tmp_path[PATH_MAX];
726
727         resolved[0] = 0;
728         //try resolve <path>.exe
729         sprintf(tmp_path, "%s.exe", path);
730         if ((res = realpath(tmp_path, resolved)) == NULL) {
731                 //try to resolve path <path>
732                 res = realpath(path, resolved);
733         }
734
735         return res;
736 }