Le 21/02/2022 à 01:36, Steve Litt a écrit :
> Florian Zieboll via Dng said on Sat, 19 Feb 2022 18:51:54 +0100
>
>
>> Back to the keyboard, I just discovered, that every (GUI) program I
>> run, is spawned from PID 1.
> This is not precisely true. Even though ps ax lists the PPID of the
> programs you run is 1, PID1 didn't spawn them. Here's the explanation...
>
> When there's a desire to background a program in such a way that you
> can close the parent program without closing the "spawned" program,
> without using the problematic nohup, the iconic way to do it is called
> "doublefork", which *assigns* the PPID to PID1.
>
> As a doublefork example, the following is the C code my qownbackup
> system uses to background the `qownbackup backup` command:
>
> ==============================================================
> #include<unistd.h>
> #include<stdio.h>
>
> int main(int argc, char *argv[]){
> pid_t pid = fork();
> if(pid < 0){
> printf("First fork failed.\n");
> perror("First fork failed!");
> } else if(pid == 0){
> pid = fork();
> if(pid < 0){
> printf("Second fork failed.\n");
> perror("Second fork failed!");
> } else if(pid == 0){
> execl("./qownbackup.sh", "./qownbackup.sh", "backup", NULL);
> }
> }
> }
> ==============================================================
>
> Aitor can correct any misunderstandings I have, but here goes my
> explanation...
>
> First, understand that the fork() function produces a second process,
> called "the child", almost completely identical to the first. The
> child's program counter is the same as the parent's, so both process
> proceed from the point immediately after the fork() function.
>
> The fork() function returns one of three ranges of integers:
>
> * Less than 1 on error.
> * Zero if the current process is the child.
> * Greater than zero, and in fact the child's PID, if the process is
> the parent.
>
> The child of a child is assigned a PPID of 1.
>
> So the first thing is to do one fork, test the return code for error,
> and abort if so. If the return code is positive, indicating that this
> is the parent, do nothing, so that the parent finishes normally.
>
> But if the return code is zero, this is the first child, so do another
> fork. Once again, run the fork() function, and if the return indicate's
> that you're a child (of the child the child the original created), do
> an exec function to replace yourself with the command you want to
> background, in this case "qownbackup backup".
>
> Because it's the child of a child, its PPID is 1. Aitor, I don't think
> I've given the complete story, I think there's a dependency on which
> process finishes first, and as such I might have a race condition in my
> code.
>
> Also, I think I should have done a setsid() after the second fork, and
> I should have done something to close stdin, and redirect stdout and
> stderr, to a log file or to /dev/null.
>
> The following is the (Python3) doublefork used in my UMENU2 software:
>
> ==============================================================
> #!/usr/bin/python
>
> import sys
> import os
>
> if os.fork():
> sys.exit(0)
> if os.fork():
> sys.exit(0)
> os.setsid() ### New to 1.9.3, guarantees complete fork
> sys.argv.pop(0)
> executable = sys.argv[0]
> os.execvp(executable, sys.argv)
> ==============================================================
>
> In the preceding, errors aren't handled, so it just does two straight
> forks and proceeds only if both return zero. Then it does a setsid(),
> which I think my C implementation should have done too, and then exec's
> the desired command, just like my C implementation does.
>
> Doubleforking works in pretty much any computer language with the
> fork(). You can even do it in bash or dash, but it's not so
> straightforward.
>
> SteveT
Note that this double-fork has not to be implemented in processes
launched from sysv-rc scripts, since the launching script already
performs one of the forks and then dies. In a daemon you launch by hand,
the critical thing is to detach from the controlling terminal (closing
stdin is not enough), and start a new session (setsid). Then you don't
care who is the parent of the daemon; when the parent dies, the daemon
becomes a child of init, but who cares?
-- Didier