3 * Copyright (c) 2012-2019 Samsung Electronics Co., Ltd.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <sys/types.h>
25 #include <sys/sendfile.h>
42 int write_fd(int fd, const void *buf, int len)
48 count = write(fd, buf, len);
57 buf = ((const char *)buf) + count;
63 static int copy_bytes_sendfile(int destfd, int srcfd, off_t *ncopied)
69 nsent = sendfile(destfd, srcfd, NULL, INT32_MAX);
72 else if (nsent < 0 && errno == EAGAIN)
81 return nsent == -1 ? -1 : 0;
84 static int copy_bytes_rw(int destfd, int srcfd, off_t *ncopied)
91 n = read(srcfd, buf, sizeof buf);
93 if (errno == EAGAIN || errno == EINTR)
99 int m = write_fd(destfd, buf, n);
101 _E("failed to write data to destination fd: %m");
113 int copy_bytes(int destfd, int srcfd, off_t *ncopied)
115 int r = copy_bytes_sendfile(destfd, srcfd, ncopied);
116 return r == 0 ? r : copy_bytes_rw(destfd, srcfd, ncopied);
119 int copy_file(char *dst, char *src)
126 _E("Invalid argument\n");
129 sfd = open(src, O_RDONLY);
131 _E("Failed to open (%s)\n", src);
134 dfd = open(dst, O_WRONLY|O_CREAT|O_EXCL, 0644);
137 _SE("Failed to open (%s)\n", dst);
141 res = copy_bytes(dfd, sfd, NULL);
148 int move_file(char *dst, char *src)
150 if (copy_file(dst, src) < 0)
157 int dump_file_write_fd(int dfd, char *src)
163 _E("Invalid argument\n");
166 sfd = open(src, O_RDONLY);
168 _SE("Failed to open (%s)\n", src);
172 res = copy_bytes(dfd, sfd, NULL);
178 int fsync_path(char *const path)
182 ret = fd = open(path, O_RDONLY);
189 _E("Unable to fsync %s: %m", path);
194 int make_dir(const char *path, const char *name, int mode)
198 DIR *dir = opendir(path);
200 int dfd = dirfd(dir);
201 r = mkdirat(dfd, name, mode);
205 return r == 0 || (r == -1 && errno == EEXIST) ? 0 : -1;
208 static int remove_dir_internal(int fd)
218 while ((de = readdir(dir))) {
219 if (de->d_type == DT_DIR) {
220 if (!strncmp(de->d_name, ".", 2) || !strncmp(de->d_name, "..", 3))
222 subfd = openat(fd, de->d_name, O_RDONLY | O_DIRECTORY);
224 _SE("Couldn't openat %s: %d\n", de->d_name, errno);
228 if (remove_dir_internal(subfd))
231 if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
232 _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
236 if (unlinkat(fd, de->d_name, 0) < 0) {
237 _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
246 int remove_dir(const char *path, int del_dir)
252 fd = open(path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
254 _SE("Couldn't opendir %s: %d\n", path, errno);
257 ret = remove_dir_internal(fd);
262 _SE("Couldn't rmdir %s: %d\n", path, errno);
269 int get_exec_pid(const char *execpath)
272 struct dirent *dentry;
279 dp = opendir("/proc");
281 _E("FAIL: open /proc");
285 len = strlen(execpath) + 1;
287 while ((dentry = readdir(dp))) {
288 if (!isdigit(dentry->d_name[0]))
291 pid = atoi(dentry->d_name);
293 snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid);
294 fd = open(buf, O_RDONLY);
297 ret = read(fd, buf2, PATH_MAX);
300 if (ret < 0 || ret >= PATH_MAX)
305 if (!strncmp(buf2, execpath, len)) {
316 int get_file_count(char *path)
326 while ((dp = readdir(dir))) {
327 const char *name = dp->d_name;
328 /* always skip "." and ".." */
329 if (name[0] == '.') {
332 if ((name[1] == '.') && (name[2] == 0))
341 off_t get_directory_usage(char *path)
349 fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
358 while ((de = readdir(dir))) {
359 if (!strncmp(de->d_name, ".", 2) || !strncmp(de->d_name, "..", 3))
361 if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
362 _SE("Failed to fstatat %s: %d\n", de->d_name, errno);
372 int log_kmsg(char *fmt, ...)
378 file = fopen("/dev/kmsg", "w");
380 _E("Open /dev/kmsg error: %m");
385 if (vfprintf(file, fmt, ap) < 0) {
386 _E("Write to /dev/kmsg error: %m");
395 * @brief Check wchan of thread
397 * @param pid PID of the inspected process
398 * @param tid TID of the thread to check
400 static int check_thread_wchan(int pid, int tid)
403 char path[PATH_MAX], buf[100];
405 snprintf(path, sizeof(path), "/proc/%d/task/%d/wchan", pid, tid);
406 fd = open(path, O_RDONLY);
408 _E("cannot open %s: %m\n", path);
411 cnt = read(fd, buf, sizeof(buf));
412 if (cnt == -1 || cnt == sizeof(buf)) {
413 _E("read %s error: %m\n", path);
420 if (strncmp("do_coredump", buf, sizeof(buf)) == 0 || strncmp("pipe_wait", buf, sizeof(buf)) == 0)
427 * @brief Find crashed tid if tid was not offered
429 * @param pid PID of the inspected process
431 int find_crash_tid(int pid)
436 struct dirent *entry;
437 char task_path[PATH_MAX];
440 snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
441 if (stat(task_path, &sb) == -1) {
442 _E("no such file: %s", task_path);
446 threadnum = sb.st_nlink - 2;
449 dir = opendir(task_path);
451 _E("cannot open %s\n", task_path);
454 while ((entry = readdir(dir)) != NULL) {
455 if (strcmp(entry->d_name, ".") == 0 ||
456 strcmp(entry->d_name, "..") == 0)
458 crash_tid = check_thread_wchan(pid,
459 atoi(entry->d_name));
466 } else if (threadnum == 1) {
472 bool filter_drop_trailing_whitespace(char *buf, int size, int datalen)
475 assert(datalen <= size);
477 bool filtered = false;
479 for (int i = datalen; i >= 0 && isspace(buf[i]); --i) {
487 bool read_proc_file(pid_t pid, const char * const file, char *outbuf, size_t bufsize, charp0filter filter)
495 snprintf(path, sizeof(path), "/proc/%d/%s", pid, file);
497 int fd = open(path, O_RDONLY);
499 _E("Failed to open %s: %m\n", path);
503 ssize_t ret = read(fd, outbuf, bufsize - 1);
505 _E("Failed to read %s: %m\n", path);
512 if (ret > 0 && filter)
513 (void)filter(outbuf, bufsize, ret - 1);
522 bool get_exe_path(pid_t pid, char *outbuf, size_t outbuf_len)
525 assert(outbuf_len > 0);
527 char exe_link[PATH_MAX];
529 snprintf(exe_link, sizeof(exe_link), "/proc/%d/exe", pid);
531 ssize_t ret = readlink(exe_link, outbuf, outbuf_len - 1);
533 _E("Failed to read link %s: %m", exe_link);
538 if (access(outbuf, F_OK) == -1) {
539 _E("Unable to access %s: %m", outbuf);
545 /* This function is supposed to accept same data as passed to execve
546 * (argv and envp), which can be arrays of strings as well as NULL
549 char* concatenate(char *const vec[])
552 for (char *const *p = vec; p && *p; p++)
553 length += strlen(*p) + 1;
558 char *str = (char *)malloc(length);
563 char *const *vecp = vec;
565 destp = stpcpy(destp, *(vecp++));
567 destp = stpcpy(destp, " ");
573 bool string_ends_with(const char *string, const char *suffix)
575 const size_t string_len = strlen(string);
576 const size_t suffix_len = strlen(suffix);
578 return (string_len >= suffix_len) && !strcmp(string + string_len - suffix_len, suffix);
581 bool file_exists(const char *path)
584 return stat(path, &buf) == 0;
587 bool write_to_file(const char *content, const char *base_dir, const char *file_name)
592 if (asprintf(&path, "%s/%s", base_dir, file_name) == -1) {
593 _E("Failed to asprintf for path: %m");
597 int fd = open(path, O_WRONLY | O_CREAT, 0600);
600 _E("Failed to open %s: %m", path);
604 if (dprintf(fd, "%s", content) < 0) {
605 _E("Failed to write to file %s: %m", path);