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",
}
}
+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;