]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
process-util: add helper that detects if we are a reaper process
authorLennart Poettering <lennart@poettering.net>
Thu, 22 Jun 2023 09:52:06 +0000 (11:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 23 Jun 2023 08:00:30 +0000 (10:00 +0200)
src/basic/process-util.c
src/basic/process-util.h
src/test/test-process-util.c

index 0f642fdf1bb3f469567f2607009488e6966723e2..6373909bc770db4f4e898e9ccfd88f66498ebc4b 100644 (file)
@@ -1623,6 +1623,21 @@ int get_process_threads(pid_t pid) {
         return n;
 }
 
+int is_reaper_process(void) {
+        int b = 0;
+
+        /* Checks if we are running in a reaper process, i.e. if we are expected to deal with processes
+         * reparented to us. This simply checks if we are PID 1 or if PR_SET_CHILD_SUBREAPER was called. */
+
+        if (getpid_cached() == 1)
+                return true;
+
+        if (prctl(PR_GET_CHILD_SUBREAPER, (unsigned long) &b, 0UL, 0UL, 0UL) < 0)
+                return -errno;
+
+        return b != 0;
+}
+
 static const char *const sigchld_code_table[] = {
         [CLD_EXITED] = "exited",
         [CLD_KILLED] = "killed",
index 230a0edb0934da1086850644fd7f98b18955d63d..6ad4316614d9013c35baa6e8c762271cec528fe9 100644 (file)
@@ -199,3 +199,5 @@ int setpriority_closest(int priority);
 _noreturn_ void freeze(void);
 
 int get_process_threads(pid_t pid);
+
+int is_reaper_process(void);
index e915207e8c777d7fc3ef36ef3d103395d00a20d9..6de09c3c11f8a5d5fa6fd0375a34cf43ecd0a386 100644 (file)
@@ -891,6 +891,53 @@ TEST(get_process_threads) {
         }
 }
 
+TEST(is_reaper_process) {
+        int r;
+
+        r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
+        assert_se(r >= 0);
+        if (r == 0) {
+                /* child */
+
+                assert_se(is_reaper_process() == 0);
+                _exit(EXIT_SUCCESS);
+        }
+
+        r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
+        assert_se(r >= 0);
+        if (r == 0) {
+                /* child */
+
+                if (unshare(CLONE_NEWPID) < 0) {
+                        if (ERRNO_IS_PRIVILEGE(errno) || ERRNO_IS_NOT_SUPPORTED(errno)) {
+                                log_notice("Skipping CLONE_NEWPID reaper check, lacking privileges/support");
+                                _exit(EXIT_SUCCESS);
+                        }
+                }
+
+                r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
+                assert_se(r >= 0);
+                if (r == 0) {
+                        /* grandchild, which is PID1 in a pidns */
+                        assert_se(getpid_cached() == 1);
+                        assert_se(is_reaper_process() > 0);
+                        _exit(EXIT_SUCCESS);
+                }
+
+                _exit(EXIT_SUCCESS);
+        }
+
+        r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
+        assert_se(r >= 0);
+        if (r == 0) {
+                /* child */
+                assert_se(prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) >= 0);
+
+                assert_se(is_reaper_process() > 0);
+                _exit(EXIT_SUCCESS);
+        }
+}
+
 static int intro(void) {
         log_show_color(true);
         return EXIT_SUCCESS;