summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/basic/process-util.c27
-rw-r--r--src/coredump/coredump.c23
-rw-r--r--src/test/test-process-util.c48
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;
}