util: Add fsync_path to selectively flush file buffer to disk
[platform/core/system/crash-worker.git] / src / shared / util.c
1 /*
2  * crash-manager
3  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <sys/sendfile.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <unistd.h>
28 #include <limits.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <time.h>
32 #include <errno.h>
33 #include <wait.h>
34 #include <ctype.h>
35 #include <grp.h>
36
37 #include "util.h"
38 #include "log.h"
39
40 #define READ_BUFF_SIZE 4096
41 #define SELECT_TIMEOUT_US 100000
42
43 int system_command_parallel(char *command)
44 {
45         int pid = 0;
46         const char *environ[] = { NULL };
47
48         if (command == NULL)
49                 return -1;
50         pid = fork();
51         if (pid == -1)
52                 return -1;
53         if (pid == 0) {
54                 char *argv[4];
55                 argv[0] = "sh";
56                 argv[1] = "-c";
57                 argv[2] = (char *)command;
58                 argv[3] = 0;
59                 execve("/bin/sh", argv, (char **)environ);
60                 exit(127);
61         }
62
63         return pid;
64 }
65
66 int wait_system_command(int pid)
67 {
68         int status = 0;
69
70         if (pid < 0)
71                 return -1;
72
73         do {
74                 if (waitpid(pid, &status, 0) == -1) {
75                         if (errno != EINTR)
76                                 return -1;
77                 } else {
78                         if (WIFEXITED(status))
79                                 return WEXITSTATUS(status);
80                         else if (WIFSIGNALED(status))
81                                 return WTERMSIG(status);
82                         else if (WIFSTOPPED(status))
83                                 return WSTOPSIG(status);
84                 }
85         } while (!WIFEXITED(status) && !WIFSIGNALED(status));
86
87         return 0;
88 }
89
90 int system_command(char *command)
91 {
92         int pid = 0;
93
94         pid = system_command_parallel(command);
95
96         return wait_system_command(pid);
97 }
98
99 int system_command_with_timeout(int timeout_seconds, char *command)
100 {
101         const char *environ[] = { NULL };
102
103         if (command == NULL)
104                 return -1;
105         clock_t start = clock();
106         pid_t pid = fork();
107         /* handle error case */
108         if (pid < 0) {
109                 _E("fork: %d\n", errno);
110                 return pid;
111         }
112         /* handle child case */
113         if (pid == 0) {
114                 char *argv[4];
115                 argv[0] = "sh";
116                 argv[1] = "-c";
117                 argv[2] = (char *)command;
118                 argv[3] = 0;
119
120                 execve("/bin/sh", argv, (char **)environ);
121                 _SI("exec(%s): %d\n", command, errno);
122                 _exit(-1);
123         }
124         /* handle parent case */
125         for (;;) {
126                 int status;
127                 pid_t p = waitpid(pid, &status, WNOHANG);
128                 float elapsed = (float) (clock() - start) / CLOCKS_PER_SEC;
129                 if (p == pid) {
130                         if (WIFSIGNALED(status))
131                                 _SI("%s: Killed by signal %d\n", command, WTERMSIG(status));
132                         else if (WIFEXITED(status) && WEXITSTATUS(status) > 0)
133                                 _SI("%s: Exit code %d\n", command, WEXITSTATUS(status));
134                         return WEXITSTATUS(status);
135                 }
136                 if (timeout_seconds && elapsed > timeout_seconds) {
137                         _SI("%s: Timed out after %.1fs (killing pid %d)\n",
138                                         command, elapsed, pid);
139                         kill(pid, SIGTERM);
140                         return -1;
141                 }
142                 /* poll every 0.1 sec */
143                 usleep(100000);
144         }
145 }
146
147 int write_fd(int fd, const void *buf, int len)
148 {
149         int count;
150         int total;
151         total = 0;
152         while (len) {
153                 count = write(fd, buf, len);
154                 if (count < 0) {
155                         if (errno == EINTR)
156                                 continue;
157                         if (total)
158                                 return total;
159                         return count;
160                 }
161                 total += count;
162                 buf = ((const char *)buf) + count;
163                 len -= count;
164         }
165         return total;
166 }
167
168 static int copy_bytes_sendfile(int destfd, int srcfd, off_t *ncopied)
169 {
170         ssize_t nsent;
171         off_t total = 0;
172
173         do {
174                 nsent = sendfile(destfd, srcfd, NULL, INT32_MAX);
175                 if (nsent > 0)
176                         total += nsent;
177                 else if (nsent < 0 && errno == EAGAIN)
178                         continue;
179                 else
180                         break;
181         } while (1);
182
183         if (ncopied)
184                 *ncopied = total;
185
186         return nsent == -1 ? -1 : 0;
187 }
188
189 static int copy_bytes_rw(int destfd, int srcfd, off_t *ncopied)
190 {
191         ssize_t n;
192         char buf[4096];
193         off_t total = 0;
194
195         do {
196                 n = read(srcfd, buf, sizeof buf);
197                 if (n < 0) {
198                         if (errno == EAGAIN || errno == EINTR)
199                                 continue;
200                         _E("read: %m");
201                         return -1;
202                 }
203
204                 int m = write_fd(destfd, buf, n);
205                 if (m != n) {
206                         _E("failed to write data to destination fd: %m");
207                         return -1;
208                 }
209                 total += m;
210         } while (n > 0);
211
212         if (ncopied)
213                 *ncopied = total;
214
215         return 0;
216 }
217
218 int copy_bytes(int destfd, int srcfd, off_t *ncopied)
219 {
220         int r = copy_bytes_sendfile(destfd, srcfd, ncopied);
221         return r == 0 ? r : copy_bytes_rw(destfd, srcfd, ncopied);
222 }
223
224 int copy_file(char *dst, char *src)
225 {
226         int res;
227         int sfd;
228         int dfd;
229
230         if (!src || !dst) {
231                 _E("Invalid argument\n");
232                 return -1;
233         }
234         sfd = open(src, O_RDONLY);
235         if (sfd < 0) {
236                 _E("Failed to open (%s)\n", src);
237                 return -1;
238         }
239         dfd = open(dst, O_WRONLY|O_CREAT|O_EXCL, 0644);
240         if (dfd < 0) {
241                 close(sfd);
242                 _SE("Failed to open (%s)\n", dst);
243                 return -1;
244         }
245
246         res = copy_bytes(dfd, sfd, NULL);
247
248         close(sfd);
249         close(dfd);
250         return res;
251 }
252
253 int move_file(char *dst, char *src)
254 {
255         if (copy_file(dst, src) < 0)
256                 return -1;
257         if (unlink(src) < 0)
258                 return -1;
259         return 1;
260 }
261
262 int dump_file_write_fd(int dfd, char *src)
263 {
264         int res;
265         int sfd;
266
267         if (!src) {
268                 _E("Invalid argument\n");
269                 return -1;
270         }
271         sfd = open(src, O_RDONLY);
272         if (sfd < 0) {
273                 _SE("Failed to open (%s)\n", src);
274                 return -1;
275         }
276
277         res = copy_bytes(dfd, sfd, NULL);
278
279         close(sfd);
280         return res;
281 }
282
283 static int run_command(char *path, char *args[], char *env[], int fd[])
284 {
285         if (dup2(fd[1], STDOUT_FILENO) == -1) {
286                 _E("dup2 error: %m");
287                 return -1;
288         }
289
290         if (close(fd[1]) == -1) {
291                 _E("close fd error: %m");
292                 return -1;
293         }
294
295         if (close(fd[0]) == -1) {
296                 _E("close fd error: %m");
297                 return -1;
298         }
299
300         if (execvpe(path, args, env) == -1) {
301                 _E("run command %s error: %m", path);
302                 return -1;
303         }
304         return -1;
305 }
306
307 static int wait_for_child(pid_t pid, int *exit_code, int timeout)
308 {
309         for (int i = 0; i < 10*timeout; i++) {
310                 int status;
311                 pid_t p = waitpid(pid, &status, WNOHANG);
312                 if (p == pid) {
313                         if (WIFSIGNALED(status)) {
314                                 _I("Killed by signal %d\n", WTERMSIG(status));
315                                 return -1;
316                         } else if (WIFEXITED(status)) {
317                                 *exit_code = WEXITSTATUS(status);
318                                 return 0;
319                         }
320                 } else if (p == -1) {
321                         _E("waitpid error: %m");
322                         return -1;
323                 }
324                 usleep(100000);
325         }
326         return -1;
327 }
328
329 static int read_into_buff(int fd, char *buff, int size, int timeout_us, int *eof)
330 {
331         struct timeval tout;
332         int sel_ret;
333         fd_set set;
334
335         FD_ZERO(&set);
336         FD_SET(fd, &set);
337
338         tout.tv_sec = timeout_us / 1000000;
339         tout.tv_usec = timeout_us % 1000000;
340         *eof = 0;
341
342         int buff_pos = 0;
343         if ((sel_ret = select(fd+1, &set, NULL, NULL, &tout)) >= 0) {
344                 if (sel_ret > 0) {
345                         // we can do nonblocking read
346                         int readed = read(fd, &buff[buff_pos], size);
347
348                         if (readed > 0) {
349                                 buff_pos += readed;
350                                 size -= readed;
351                         } else if (readed == 0) {
352                                 // no more data to read
353                                 *eof = 1;
354                         } else {
355                                 // error
356                                 _E("read data from the pipe error: %m");
357                                 return -1;
358                         }
359                 }
360         } else
361                 _E("select() error: %m");
362         return buff_pos;
363 }
364
365 // Usage:
366 // if buff is not NULL then 'size' bytes of the result is written the buffer,
367 // otherwise result is written to the dfd descriptor
368 int run_command_write_fd_timeout(char *path, char *args[], char *env[], int dfd, char *buff, int size, int timeout)
369 {
370         char BUFF[READ_BUFF_SIZE];
371         int fd[2];
372         struct timeval start, end;
373         int write_to_fd = buff == NULL ? 1 : 0;
374
375         if (!write_to_fd && size <= 0) {
376                 _E("buffer size must be greather than zero");
377                 return -1;
378         }
379
380         if (pipe(fd)) {
381                 _E("pipe create error: %m");
382                 return -1;
383         }
384
385         pid_t pid = fork();
386
387         if (pid == 0) {
388                 return run_command(path, args, env, fd);
389         } else if (pid > 0) {
390                 if (close(fd[1]) == -1) {
391                         _E("close fd error: %m");
392                         return -1;
393                 }
394
395                 if (gettimeofday(&start, NULL) == -1) {
396                         _E("gettimeofday error: %m");
397                         return -1;
398                 }
399
400                 int readed;
401                 int eof = 0;
402                 int outdated = 0;
403                 int count = 0;
404
405                 int act_size;
406                 char *act_buff;
407
408                 if (write_to_fd) {
409                         act_size = READ_BUFF_SIZE;
410                         act_buff = BUFF;
411                 } else {
412                         act_size = size;
413                         act_buff = buff;
414                 }
415
416                 while ((readed = read_into_buff(fd[0], act_buff, act_size, 1000000, &eof)) >= 0) {
417                         if (readed > 0) {
418                                 // we have some data
419                                 if (count < (INT_MAX - readed))
420                                         count += readed;
421                                 else
422                                         count = INT_MAX;
423
424                                 if (write_to_fd) {
425                                         if (write_fd(dfd, act_buff, readed) == -1) {
426                                                 _E("write data to pipe error: %m");
427                                                 break;
428                                         }
429                                 } else {
430                                         act_buff += readed;
431                                         act_size -= readed;
432
433                                         if (act_size == 0) {
434                                                 // buff is full, we can return
435                                                 eof = 1;
436                                         }
437                                 }
438                         }
439
440                         if (eof)
441                                 break;
442
443                         if (gettimeofday(&end, NULL) == -1) {
444                                 _E("gettimeofday error: %m");
445                                 break;
446                         }
447
448                         if ((end.tv_sec - start.tv_sec) > timeout) {
449                                 outdated = 1;
450                                 break;
451                         }
452
453                         if (readed == 0)
454                                 usleep(100000);
455                 }
456
457                 if (outdated) {
458                         _E("command timeout: %s", path);
459                         if (kill(pid, 0) == 0) {
460                                 // we can kill a child because we don't
461                                 // need it anymore
462                                 if (kill(pid, SIGTERM) == -1)
463                                         _E("kill child %d error: %m", pid);
464                         }
465                 }
466
467                 if (close(fd[0]) == -1) {
468                         _E("close fd error: %m");
469                         return -1;
470                 }
471
472                 // let's wait a second for a child
473                 int exit_code = -1;
474                 int wait_res = wait_for_child(pid, &exit_code, 1);
475
476                 if (wait_res != 0)
477                         _I("wait_for_child for \%s\" returns non-zero value\n", path);
478                 else if (exit_code != 0)
479                         _I("\"%s\" exit code: %d\n", path, exit_code);
480
481                 return (eof == 1 && exit_code == 0) ? count : -abs(exit_code);
482         } else {
483                 _E("fork() error: %m");
484                 return -1;
485         }
486
487         return -1;
488 }
489
490 int run_command_timeout(char *path, char *args[], char *env[], int timeout)
491 {
492         int fd = open("/dev/null", O_WRONLY);
493         if (fd < 0) {
494                 _E("open /dev/null error: %m");
495                 return -1;
496         }
497
498         int res = run_command_write_fd_timeout(path, args, env, fd, NULL, 0, timeout);
499
500         close(fd);
501
502         return res;
503 }
504
505 int fsync_path(char *const path)
506 {
507         int fd, ret;
508
509         ret = fd = open(path, O_RDONLY);
510         if (fd >= 0) {
511                 ret = fsync(fd);
512                 close(fd);
513         }
514
515         if (ret < 0)
516                 _E("Unable to fsync %s: %m", path);
517
518         return ret;
519 }
520
521 static int remove_dir_internal(int fd)
522 {
523         DIR *dir;
524         struct dirent *de;
525         int subfd, ret = 0;
526
527         dir = fdopendir(fd);
528         if (!dir)
529                 return -1;
530
531         while ((de = readdir(dir))) {
532                 if (de->d_type == DT_DIR) {
533                         if (!strncmp(de->d_name, ".", 2) || !strncmp(de->d_name, "..", 3))
534                                 continue;
535                         subfd = openat(fd, de->d_name, O_RDONLY | O_DIRECTORY);
536                         if (subfd < 0) {
537                                 _SE("Couldn't openat %s: %d\n", de->d_name, errno);
538                                 ret = -1;
539                                 continue;
540                         }
541                         if (remove_dir_internal(subfd))
542                                 ret = -1;
543                         close(subfd);
544                         if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
545                                 _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
546                                 ret = -1;
547                         }
548                 } else {
549                         if (unlinkat(fd, de->d_name, 0) < 0) {
550                                 _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
551                                 ret = -1;
552                         }
553                 }
554         }
555         closedir(dir);
556         return ret;
557 }
558
559 int remove_dir(const char *path, int del_dir)
560 {
561         int fd, ret = 0;
562
563         if (!path)
564                 return -1;
565         fd = open(path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
566         if (fd < 0) {
567                 _SE("Couldn't opendir %s: %d\n", path, errno);
568                 return -errno;
569         }
570         ret = remove_dir_internal(fd);
571         close(fd);
572
573         if (del_dir) {
574                 if (rmdir(path)) {
575                         _SE("Couldn't rmdir %s: %d\n", path, errno);
576                         ret = -1;
577                 }
578         }
579         return ret;
580 }
581
582 int get_exec_pid(const char *execpath)
583 {
584         DIR *dp;
585         struct dirent *dentry;
586         int pid = -1, fd;
587         int ret;
588         char buf[PATH_MAX];
589         char buf2[PATH_MAX];
590         int len;
591
592         dp = opendir("/proc");
593         if (!dp) {
594                 _E("FAIL: open /proc");
595                 return -1;
596         }
597
598         len = strlen(execpath) + 1;
599
600         while ((dentry = readdir(dp))) {
601                 if (!isdigit(dentry->d_name[0]))
602                         continue;
603
604                 pid = atoi(dentry->d_name);
605
606                 snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid);
607                 fd = open(buf, O_RDONLY);
608                 if (fd < 0)
609                         continue;
610                 ret = read(fd, buf2, PATH_MAX);
611                 close(fd);
612
613                 if (ret < 0 || ret >= PATH_MAX)
614                         continue;
615
616                 buf2[ret] = '\0';
617
618                 if (!strncmp(buf2, execpath, len)) {
619                         closedir(dp);
620                         return pid;
621                 }
622         }
623
624         errno = ESRCH;
625         closedir(dp);
626         return -1;
627 }
628
629 int get_file_count(char *path)
630 {
631         DIR *dir;
632         struct dirent *dp;
633         int count = 0;
634
635         dir = opendir(path);
636         if (!dir)
637                 return 0;
638
639         while ((dp = readdir(dir))) {
640                 const char *name = dp->d_name;
641                 /* always skip "." and ".." */
642                 if (name[0] == '.') {
643                         if (name[1] == 0)
644                                 continue;
645                         if ((name[1] == '.') && (name[2] == 0))
646                                 continue;
647                 }
648                 count++;
649         }
650         closedir(dir);
651         return count;
652 }
653
654 int get_directory_usage(char *path)
655 {
656         DIR *dir;
657         struct dirent *de;
658         struct stat st;
659         size_t usage = 0;
660         int fd = -1;
661
662         fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
663         if (fd < 0)
664                 return -1;
665         dir = fdopendir(fd);
666         if (!dir) {
667                 close(fd);
668                 return -1;
669         }
670
671         while ((de = readdir(dir))) {
672                 if (!strncmp(de->d_name, ".", 2) || !strncmp(de->d_name, "..", 3))
673                         continue;
674                 if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
675                         _SE("Failed to fstatat  %s: %d\n", de->d_name, errno);
676                         continue;
677                 }
678                 usage += st.st_size;
679         }
680         closedir(dir);
681         close(fd);
682         return usage;
683 }
684
685 int log_kmsg(char *fmt, ...)
686 {
687         int result = 1;
688         va_list ap;
689         FILE *file;
690
691         file = fopen("/dev/kmsg", "w");
692         if (file == NULL) {
693                 _E("Open /dev/kmsg error: %m");
694                 return 0;
695         }
696
697         va_start(ap, fmt);
698         if (vfprintf(file, fmt, ap) < 0) {
699                 _E("Write to /dev/kmsg error: %m");
700                 result = 0;
701         }
702         va_end(ap);
703         fclose(file);
704         return result;
705 }
706
707 /**
708  * @brief Check wchan of thread
709  *
710  * @param pid PID of the inspected process
711  * @param tid TID of the thread to check
712  */
713 static int check_thread_wchan(int pid, int tid)
714 {
715         int fd, cnt;
716         char path[PATH_MAX], buf[100];
717
718         snprintf(path, sizeof(path), "/proc/%d/task/%d/wchan", pid, tid);
719         fd = open(path, O_RDONLY);
720         if (fd == -1) {
721                 _E("cannot open %s: %m\n", path);
722                 return -errno;
723         }
724         cnt = read(fd, buf, sizeof(buf));
725         if (cnt == -1 || cnt == sizeof(buf)) {
726                 _E("read %s error: %m\n", path);
727                 close(fd);
728                 return -errno;
729         }
730         buf[cnt] = 0;
731         close(fd);
732
733         if (strncmp("do_coredump", buf, sizeof(buf)) == 0 || strncmp("pipe_wait", buf, sizeof(buf)) == 0)
734                 return tid;
735         else
736                 return 0;
737 }
738
739 /**
740  * @brief Find crashed tid if tid was not offered
741  *
742  * @param pid PID of the inspected process
743  */
744 int find_crash_tid(int pid)
745 {
746         int threadnum = 1;
747         int crash_tid = -1;
748         DIR *dir;
749         struct dirent *entry;
750         char task_path[PATH_MAX];
751         struct stat sb;
752
753         snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
754         if (stat(task_path, &sb) == -1) {
755                 _E("no such file: %s", task_path);
756                 return -1;
757         }
758
759         threadnum = sb.st_nlink - 2;
760
761         if (threadnum > 1) {
762                 dir = opendir(task_path);
763                 if (!dir) {
764                         _E("cannot open %s\n", task_path);
765                         return -1;
766                 } else {
767                         while ((entry = readdir(dir)) != NULL) {
768                                 if (strcmp(entry->d_name, ".") == 0 ||
769                                     strcmp(entry->d_name, "..") == 0)
770                                         continue;
771                                 crash_tid = check_thread_wchan(pid,
772                                                                atoi(entry->d_name));
773                                 if (crash_tid > 0)
774                                         break;
775                         }
776                         closedir(dir);
777                         return crash_tid;
778                 }
779         } else if (threadnum == 1) {
780                 return pid;
781         }
782         return -1;
783 }
784
785 char* get_cmd_line(pid_t pid)
786 {
787         char cmdline_path[PATH_MAX];
788
789         snprintf(cmdline_path, sizeof(cmdline_path),
790                         "/proc/%d/cmdline", pid);
791
792         int fd = open(cmdline_path, O_RDONLY);
793         if (fd < 0) {
794                 _E("Failed to open %s: %m\n", cmdline_path);
795                 return NULL;
796         }
797
798         char buffer[PATH_MAX];
799         ssize_t ret = read(fd, buffer, sizeof(buffer) - 1);
800         close(fd);
801
802         if (ret <= 0) {
803                 _E("Failed to read %s: %m\n", cmdline_path);
804                 return NULL;
805         }
806         buffer[ret] = '\0';
807
808         char *result;
809         if (asprintf(&result, "%s", buffer) == -1) {
810                 _E("asprintf() error: %m\n");
811                 return NULL;
812         }
813
814         return result;
815 }
816
817 char* get_exe_path(pid_t pid)
818 {
819         char exe_link[PATH_MAX];
820         char buffer[PATH_MAX];
821
822         snprintf(exe_link, sizeof(exe_link),
823                 "/proc/%d/exe", pid);
824
825         ssize_t ret = readlink(exe_link, buffer, sizeof(buffer) - 1);
826
827         if (ret <= 0) {
828                 _E("Failed to read link %s: %m", exe_link);
829                 return NULL;
830         }
831         buffer[ret] = '\0';
832
833         if (access(buffer, F_OK) == -1) {
834                 _E("Invalid path %s", buffer);
835                 return NULL;
836         }
837
838         char *result;
839         if (asprintf(&result, "%s", buffer) == -1) {
840                 _E("asprintf() error: %m\n");
841                 return NULL;
842         }
843
844         return result;
845 }
846
847 /* This function is supposed to accept same data as passed to execve
848  * (argv and envp), which can be arrays of strings as well as NULL
849  * pointer.
850  */
851 char* concatenate(char *const vec[])
852 {
853         size_t length = 0;
854         for (char *const *p = vec; p && *p; p++)
855                 length += strlen(*p) + 1;
856
857         if (length == 0)
858                 return strdup("");
859
860         char *str = (char *)malloc(length);
861         if (!str)
862                 return NULL;
863
864         char *destp = str;
865         char *const *vecp = vec;
866         while (*vecp) {
867                 destp = stpcpy(destp, *(vecp++));
868                 if (*vecp)
869                         destp = stpcpy(destp, " ");
870         }
871
872         return str;
873 }
874
875 /**
876  * @}
877  */