]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/pager: Use async-signal safe signal handler
authorTobias Stoeckmann <tobias@stoeckmann.org>
Mon, 23 Feb 2026 18:51:25 +0000 (19:51 +0100)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Mon, 23 Feb 2026 19:08:38 +0000 (20:08 +0100)
Accessing pager_process.pid from within a signal handler is, by strict C
language interpretation, not signal safe.

Wait for all children (and thus for pager_process.pid as well) instead.
The current users dmesg and fdisk have no further children so this is a
good compromise here.

The signal handler is used for SIGINT, SIGHUP, SIGTERM, SIGQUIT. From a
terminal perspective, these are normally intercepted by the child, not
the parent.

Since wait_for_pager is never reached by a signal handler anymore, a
regular err() call is now possible. Just make sure that no exit function
handler could ever loop endlessly.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
lib/pager.c

index 3dc213dc964ab6d9757ec89c2d5c165a0996eaef..b6321d2b0d30ae3e14c23f3ffca2e0b7f7ad089c 100644 (file)
@@ -109,9 +109,12 @@ static int wait_for_pager(void)
 
        do {
                waiting = waitpid(pager_process.pid, &status, 0);
-               if (waiting == -1 && errno != EINTR)
-                       ul_sig_err(EXIT_FAILURE, "waitpid failed");
-       } while (waiting == -1);
+       } while (waiting == -1 && errno == EINTR);
+
+       pager_process.pid = 0;
+
+       if (waiting == -1)
+               err(EXIT_FAILURE, "waitpid failed");
 
        if (waiting == pager_process.pid && WIFEXITED(status))
                return WEXITSTATUS(status);
@@ -137,7 +140,10 @@ static void wait_for_pager_signal(int signo __attribute__ ((__unused__)))
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
 
-       wait_for_pager();
+       /* async-signal safe: wait for all children, including pager */
+       while (wait(NULL) != -1 || errno == EINTR)
+               ;
+
        _exit(EXIT_FAILURE);
 }