Not portable, but Linux allows for not-init
reparenting of processes, see PR_SET_CHILD_SUBREAPER
in prctl(2).
PR_SET_CHILD_SUBREAPER
(since Linux 3.4)
If arg2 is nonzero,
set the "child subreaper" attribute of the calling process;
if arg2 is zero, unset the attribute.
When a process is marked as a child subreaper,
all of the children that it creates, and their descendants,
will be marked as having a subreaper.
In effect,
a subreaper fulfills the role of init(1) for its descendant processes.
…
However your subreaper could also die (accidentally). Another option, again on Linux, may be a PID namespace or container. The more usual solution is to make the parent process as simple and robust as possible, so that it is less likely to be kicked over or die.
More complicated would be to link the child processes to the parent, though this may not be possible if the child processes execs something else, or if the child processes cannot be complicated with async I/O as the child will have to check the pipe for EOF to notice that the parent has gone away:
#include <err.h>
#include <errno.h>
#include <unistd.h>
int main(void)
{
int fd[2];
char ch;
ssize_t ret;
pipe(fd);
switch (fork()) {
case -1:
err(1, "fork failed");
case 0:
close(fd[1]);
warnx("child %d start", getpid());
/* this would really need to be done in an event loop so the
* child can do other things meanwhile */
ret = read(fd[0], &ch, 1);
if (ret == 0)
errx(1, "EOF from parent (child %d)", getpid());
break;
default:
/* and another child process... */
switch (fork()) {
case -1:
err(1, "fork failed");
case 0:
close(fd[1]);
warnx("child %d start", getpid());
ret = read(fd[0], &ch, 1);
if (ret == 0)
errx(1, "EOF from parent (child %d)", getpid());
break;
default:
sleep(9);
}
}
return 0;
}
init
. At that point, there's no way to know which process was the original parent. Moving forward, however, you can update the parent process to ask its children to die when it terminates gracefully.setpgrp
command, or do you start the parent from an interactive shell?