git: 8eaa6be80d6a - main - daemon(8): handle case of waitpid() returning without exited child

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 20 Mar 2024 01:07:13 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=8eaa6be80d6aef6a118fa854a860bfdaeb7ed753

commit 8eaa6be80d6aef6a118fa854a860bfdaeb7ed753
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-03-18 08:44:39 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-03-20 01:07:00 +0000

    daemon(8): handle case of waitpid() returning without exited child
    
    Not checking for either WIFEXITED(status) or zero result results in
    never finishing the loop.
    
    PR:     277764
    Reviewed by:    kevans (previous version)
    Discussed with: Daniel Tameling
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D44401
---
 usr.sbin/daemon/daemon.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/usr.sbin/daemon/daemon.c b/usr.sbin/daemon/daemon.c
index 6cde194cf16e..bce215af75d1 100644
--- a/usr.sbin/daemon/daemon.c
+++ b/usr.sbin/daemon/daemon.c
@@ -755,18 +755,22 @@ daemon_terminate(struct daemon_state *state)
 }
 
 /*
- * Returns true if SIGCHILD came from state->pid
- * This function could hang if SIGCHILD was emittied for a reason other than
- * child dying (e.g., ptrace attach).
+ * Returns true if SIGCHILD came from state->pid due to its exit.
  */
 static bool
 daemon_is_child_dead(struct daemon_state *state)
 {
+	int status;
+
 	for (;;) {
-		int who = waitpid(-1, NULL, WNOHANG);
-		if (state->pid == who) {
+		int who = waitpid(-1, &status, WNOHANG);
+		if (state->pid == who && (WIFEXITED(status) ||
+		    WIFSIGNALED(status))) {
 			return true;
 		}
+		if (who == 0) {
+			return false;
+		}
 		if (who == -1 && errno != EINTR) {
 			warn("waitpid");
 			return false;