]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
login: improve comments for signal handling in fork_session()
authorKarel Zak <kzak@redhat.com>
Mon, 23 Feb 2026 10:00:20 +0000 (11:00 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 23 Feb 2026 10:00:20 +0000 (11:00 +0100)
Add more detailed comments explaining the signal blocking and
sigsuspend() pattern introduced by the previous commit. The key
insight is that sigsuspend() is the actual wait point where
SIGTERM/SIGHUP are forwarded to the child, while waitpid() with
WNOHANG only performs non-blocking checks for terminated children.

Signed-off-by: Karel Zak <kzak@redhat.com>
login-utils/login.c

index fa0eb41f476911a1efbba6f1dfe6c5713129f245..167975df03189339125438292242af01e6db5baa 100644 (file)
@@ -1168,20 +1168,31 @@ static void fork_session(struct login_context *cxt)
                sigaction(SIGQUIT, &sa, NULL);
                sigaction(SIGINT, &sa, NULL);
 
-               /* block SIGCHLD and sig_handler signals while checking children */
+               /*
+                * Block SIGCHLD, SIGHUP, and SIGTERM. These signals are
+                * only delivered during sigsuspend() below, ensuring that
+                * sig_handler() cannot use a stale child_pid between
+                * waitpid() reaping the child and child_pid being cleared.
+                */
                sigemptyset(&ourset);
                sigaddset(&ourset, SIGCHLD);
                sigaddset(&ourset, SIGHUP);
                sigaddset(&ourset, SIGTERM);
                sigprocmask(SIG_BLOCK, &ourset, &oldset);
 
-               /* let at least SIGCHLD, SIGHUP, and SIGTERM wake up sigsuspend */
+               /* sigsuspend() mask: unblock SIGCHLD, SIGHUP, SIGTERM */
                ourset = oldset;
                sigdelset(&ourset, SIGCHLD);
                sigdelset(&ourset, SIGHUP);
                sigdelset(&ourset, SIGTERM);
 
-               /* wait as long as any child is there */
+               /*
+                * Wait for all children to exit. The actual wait point is
+                * sigsuspend(), which atomically unblocks signals and
+                * sleeps -- this is where SIGTERM/SIGHUP are forwarded to
+                * the child via sig_handler(). waitpid() with WNOHANG only
+                * checks for already-terminated children without blocking.
+                */
                do {
                        waiting = waitpid(-1, NULL, WNOHANG);
                        if (waiting == 0)