]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
process-util: add new helper pidref_get_ppid_as_pidref()
authorLennart Poettering <lennart@poettering.net>
Tue, 7 Jan 2025 08:53:53 +0000 (09:53 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 10 Jan 2025 13:14:17 +0000 (14:14 +0100)
src/basic/process-util.c
src/basic/process-util.h
src/test/test-process-util.c

index 77045e6aa8e61390734c02fa91fb85b03dd9b690..f48285d3d52a36ab5a72ac3ce0579c61936a56fb 100644 (file)
@@ -742,6 +742,44 @@ int pidref_get_ppid(const PidRef *pidref, pid_t *ret) {
         return 0;
 }
 
+int pidref_get_ppid_as_pidref(const PidRef *pidref, PidRef *ret) {
+        pid_t ppid;
+        int r;
+
+        assert(ret);
+
+        r = pidref_get_ppid(pidref, &ppid);
+        if (r < 0)
+                return r;
+
+        for (unsigned attempt = 0; attempt < 16; attempt++) {
+                _cleanup_(pidref_done) PidRef parent = PIDREF_NULL;
+
+                r = pidref_set_pid(&parent, ppid);
+                if (r < 0)
+                        return r;
+
+                /* If we have a pidfd of the original PID, let's verify that the process we acquired really
+                 * is the parent still */
+                if (pidref->fd >= 0) {
+                        r = pidref_get_ppid(pidref, &ppid);
+                        if (r < 0)
+                                return r;
+
+                        /* Did the PPID change since we queried it? if so we might have pinned the wrong
+                         * process, if its PID got reused by now. Let's try again */
+                        if (parent.pid != ppid)
+                                continue;
+                }
+
+                *ret = TAKE_PIDREF(parent);
+                return 0;
+        }
+
+        /* Give up after 16 tries */
+        return -ENOTRECOVERABLE;
+}
+
 int pid_get_start_time(pid_t pid, usec_t *ret) {
         _cleanup_free_ char *line = NULL;
         const char *p;
index 8864472af64440e8e560e993d6e52f37776d9c9f..d4d7d87c06911b77c3f9503c6ed5516b075ab526 100644 (file)
@@ -54,6 +54,7 @@ int get_process_root(pid_t pid, char **ret);
 int get_process_environ(pid_t pid, char **ret);
 int pid_get_ppid(pid_t pid, pid_t *ret);
 int pidref_get_ppid(const PidRef *pidref, pid_t *ret);
+int pidref_get_ppid_as_pidref(const PidRef *pidref, PidRef *ret);
 int pid_get_start_time(pid_t pid, usec_t *ret);
 int pidref_get_start_time(const PidRef *pid, usec_t *ret);
 int get_process_umask(pid_t pid, mode_t *ret);
index 5a6bcdffcc0f92c09c1310e2868120a445ecf7ed..12bac656e20632bd5262a86c35890bd15b42d923 100644 (file)
@@ -848,6 +848,29 @@ TEST(pid_get_ppid) {
 
                 pid = ppid;
         }
+
+        /* the same via pidref */
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+        ASSERT_OK(pidref_set_self(&pidref));
+        for (;;) {
+                _cleanup_free_ char *c1 = NULL, *c2 = NULL;
+                _cleanup_(pidref_done) PidRef parent = PIDREF_NULL;
+                r = pidref_get_ppid_as_pidref(&pidref, &parent);
+                if (r == -EADDRNOTAVAIL) {
+                        log_info("No further parent PID");
+                        break;
+                }
+
+                ASSERT_OK(r);
+
+                ASSERT_OK(pidref_get_cmdline(&pidref, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
+                ASSERT_OK(pidref_get_cmdline(&parent, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
+
+                log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pidref.pid, c1, parent.pid, c2);
+
+                pidref_done(&pidref);
+                pidref = TAKE_PIDREF(parent);
+        }
 }
 
 TEST(set_oom_score_adjust) {