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