/* orphan: checks that init adopts and reaps orphans (boot contract v2). * * A process whose parent exits first is an "orphan". Unix hands orphans to * pid 1 (init), which must wait() for them when they exit; otherwise each * would stay a "zombie" forever. Rustbelt does this only when pid 1 is * named "init" -- Foundry OS's /sbin/init. * * orphan (this process) * `-- middle exits at once, leaving... * `-- grandchild ...an orphan: its parent becomes pid 1 * * Checks: the grandchild's getppid() becomes 1, and after it exits it is * gone completely (kill(pid, 0) fails with ESRCH): init reaped it. * Exit code = number of failed checks. Built static-PIE by foundry-cc. */ #include #include #include #include #include #include static int failed; static void check(int ok, const char *what) { printf("orphan: %-52s %s\n", what, ok ? "ok" : "FAILED"); if (!ok) failed++; } static void sleep_ms(int ms) { struct timespec ts = {ms / 1000, (ms % 1000) * 1000000L}; nanosleep(&ts, 0); } int main(void) { int fds[2]; if (pipe(fds) != 0) { perror("orphan: pipe"); return 1; } pid_t middle = fork(); if (middle == 0) { pid_t grandchild = fork(); if (grandchild == 0) { /* Wait (up to 3 s) for our parent to go and init to adopt us. */ pid_t ppid = getppid(); for (int i = 0; i < 300 && ppid != 1; i++) { sleep_ms(10); ppid = getppid(); } pid_t me = getpid(); write(fds[1], &me, sizeof me); write(fds[1], &ppid, sizeof ppid); _exit(0); } _exit(0); /* leave the grandchild behind */ } close(fds[1]); int st; check(middle > 0 && waitpid(middle, &st, 0) == middle && WIFEXITED(st), "the middle process exited"); pid_t grandchild = 0, ppid = 0; int got = read(fds[0], &grandchild, sizeof grandchild) == sizeof grandchild && read(fds[0], &ppid, sizeof ppid) == sizeof ppid; printf("orphan: grandchild %d reports parent %d\n", (int)grandchild, (int)ppid); check(got && ppid == 1, "orphaned grandchild adopted by pid 1 (init)"); /* It has exited now (or is about to); init must reap it. */ int gone = 0; for (int i = 0; i < 300 && !gone; i++) { gone = kill(grandchild, 0) == -1 && errno == ESRCH; if (!gone) sleep_ms(10); } check(got && gone, "init reaped it (kill(pid, 0) = ESRCH)"); check(waitpid(-1, &st, WNOHANG) == -1 && errno == ECHILD, "it is not our child (waitpid = ECHILD)"); if (failed) printf("orphan: %d check(s) FAILED\n", failed); else printf("orphan: all 4 checks passed\n"); return failed; }