diff options
-rw-r--r-- | src/basic/process-util.c | 27 | ||||
-rw-r--r-- | src/coredump/coredump.c | 23 | ||||
-rw-r--r-- | src/test/test-process-util.c | 48 |
3 files changed, 72 insertions, 26 deletions
diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 20b2441468..14259ea8df 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -643,20 +643,23 @@ int get_process_environ(pid_t pid, char **env) { return 0; } -int get_process_ppid(pid_t pid, pid_t *_ppid) { - int r; +int get_process_ppid(pid_t pid, pid_t *ret) { _cleanup_free_ char *line = NULL; long unsigned ppid; const char *p; + int r; assert(pid >= 0); - assert(_ppid); if (pid == 0 || pid == getpid_cached()) { - *_ppid = getppid(); + if (ret) + *ret = getppid(); return 0; } + if (pid == 1) /* PID 1 has no parent, shortcut this case */ + return -EADDRNOTAVAIL; + p = procfs_file_alloca(pid, "stat"); r = read_one_line_file(p, &line); if (r == -ENOENT) @@ -664,9 +667,8 @@ int get_process_ppid(pid_t pid, pid_t *_ppid) { if (r < 0) return r; - /* Let's skip the pid and comm fields. The latter is enclosed - * in () but does not escape any () in its value, so let's - * skip over it manually */ + /* Let's skip the pid and comm fields. The latter is enclosed in () but does not escape any () in its + * value, so let's skip over it manually */ p = strrchr(line, ')'); if (!p) @@ -680,10 +682,17 @@ int get_process_ppid(pid_t pid, pid_t *_ppid) { &ppid) != 1) return -EIO; - if ((long unsigned) (pid_t) ppid != ppid) + /* If ppid is zero the process has no parent. Which might be the case for PID 1 but also for + * processes originating in other namespaces that are inserted into a pidns. Return a recognizable + * error in this case. */ + if (ppid == 0) + return -EADDRNOTAVAIL; + + if ((pid_t) ppid < 0 || (long unsigned) (pid_t) ppid != ppid) return -ERANGE; - *_ppid = (pid_t) ppid; + if (ret) + *ret = (pid_t) ppid; return 0; } diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index c6c232c7e7..444b9ec374 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -668,8 +668,7 @@ static int get_process_ns(pid_t pid, const char *namespace, ino_t *ns) { return 0; } -static int get_mount_namespace_leader(pid_t pid, pid_t *container_pid) { - pid_t cpid = pid, ppid = 0; +static int get_mount_namespace_leader(pid_t pid, pid_t *ret) { ino_t proc_mntns; int r; @@ -679,8 +678,12 @@ static int get_mount_namespace_leader(pid_t pid, pid_t *container_pid) { for (;;) { ino_t parent_mntns; + pid_t ppid; - r = get_process_ppid(cpid, &ppid); + r = get_process_ppid(pid, &ppid); + if (r == -EADDRNOTAVAIL) /* Reached the top (i.e. typically PID 1, but could also be a process + * whose parent is not in our pidns) */ + return -ENOENT; if (r < 0) return r; @@ -688,17 +691,13 @@ static int get_mount_namespace_leader(pid_t pid, pid_t *container_pid) { if (r < 0) return r; - if (proc_mntns != parent_mntns) - break; - - if (ppid == 1) - return -ENOENT; + if (proc_mntns != parent_mntns) { + *ret = ppid; + return 0; + } - cpid = ppid; + pid = ppid; } - - *container_pid = ppid; - return 0; } /* Returns 1 if the parent was found. diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 576a9a8753..8c76392ae9 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -14,9 +14,9 @@ #include "alloc-util.h" #include "architecture.h" -#include "errno-util.h" -#include "errno-list.h" #include "dirent-util.h" +#include "errno-list.h" +#include "errno-util.h" #include "fd-util.h" #include "log.h" #include "macro.h" @@ -24,6 +24,7 @@ #include "missing_syscall.h" #include "parse-util.h" #include "process-util.h" +#include "procfs-util.h" #include "rlimit-util.h" #include "signal-util.h" #include "stdio-util.h" @@ -65,9 +66,12 @@ static void test_get_process_comm(pid_t pid) { assert_se(get_process_cmdline(pid, 1, 0, &d) >= 0); log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d); - assert_se(get_process_ppid(pid, &e) >= 0); - log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e); - assert_se(pid == 1 ? e == 0 : e > 0); + r = get_process_ppid(pid, &e); + assert_se(pid == 1 ? r == -EADDRNOTAVAIL : r >= 0); + if (r >= 0) { + log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e); + assert_se(e > 0); + } assert_se(is_kernel_thread(pid) == 0 || pid != 1); @@ -837,6 +841,39 @@ static void test_setpriority_closest(void) { } } +static void test_get_process_ppid(void) { + uint64_t limit; + int r; + + log_info("/* %s */", __func__); + + assert_se(get_process_ppid(1, NULL) == -EADDRNOTAVAIL); + + /* the process with the PID above the global limit definitely doesn't exist. Verify that */ + assert_se(procfs_tasks_get_limit(&limit) >= 0); + assert_se(limit >= INT_MAX || get_process_ppid(limit+1, NULL) == -ESRCH); + + for (pid_t pid = 0;;) { + _cleanup_free_ char *c1 = NULL, *c2 = NULL; + pid_t ppid; + + r = get_process_ppid(pid, &ppid); + if (r == -EADDRNOTAVAIL) { + log_info("No further parent PID"); + break; + } + + assert_se(r >= 0); + + assert_se(get_process_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1) >= 0); + assert_se(get_process_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2) >= 0); + + log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pid, c1, ppid, c2); + + pid = ppid; + } +} + int main(int argc, char *argv[]) { log_show_color(true); test_setup_logging(LOG_INFO); @@ -866,6 +903,7 @@ int main(int argc, char *argv[]) { test_pid_to_ptr(); test_ioprio_class_from_to_string(); test_setpriority_closest(); + test_get_process_ppid(); return 0; } |