[PATCH] libc: make system() block SIGCHLD

Richard Braun rbraun at sceen.net
Sat Jan 14 13:03:45 UTC 2012


When built with an old thread implementation (or for a sparc target),
the implementation of the system() function doesn't conform to its
specification. Namely, it resets the SIGCHLD handler to its default
instead of blocking the signal, which may result in "lost" signals
if a custom handler was installed. Replace this by appropriate calls
to sigprocmask().

Signed-off-by: Richard Braun <rbraun at sceen.net>
---
 libc/stdlib/system.c |   34 ++++++++++++++++++++++------------
 1 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/libc/stdlib/system.c b/libc/stdlib/system.c
index a0ff726..7fd9568 100644
--- a/libc/stdlib/system.c
+++ b/libc/stdlib/system.c
@@ -32,26 +32,33 @@ extern __typeof(system) __libc_system;
 
 int __libc_system(const char *command)
 {
-	int wait_val, pid;
-	__sighandler_t save_quit, save_int, save_chld;
+	int ret_val, pid;
+	__sighandler_t save_quit, save_int;
+	sigset_t smask, omask;
 
 	if (command == 0)
 		return 1;
 
 	save_quit = signal(SIGQUIT, SIG_IGN);
 	save_int = signal(SIGINT, SIG_IGN);
-	save_chld = signal(SIGCHLD, SIG_DFL);
+
+	sigemptyset(&smask);
+	sigaddset(&smask, SIGCHLD);
+
+	if (sigprocmask(SIG_BLOCK, &smask, &omask) != 0) {
+		ret_val = -1;
+		goto error_block;
+	}
 
 	if ((pid = vfork()) < 0) {
-		signal(SIGQUIT, save_quit);
-		signal(SIGINT, save_int);
-		signal(SIGCHLD, save_chld);
-		return -1;
+		ret_val = -1;
+		goto error_vfork;
 	}
+
 	if (pid == 0) {
 		signal(SIGQUIT, SIG_DFL);
 		signal(SIGINT, SIG_DFL);
-		signal(SIGCHLD, SIG_DFL);
+		sigprocmask(SIG_SETMASK, &omask, NULL);
 
 		execl("/bin/sh", "sh", "-c", command, (char *) 0);
 		_exit(127);
@@ -64,13 +71,16 @@ int __libc_system(const char *command)
 	__printf("Waiting for child %d\n", pid);
 #endif
 
-	if (wait4(pid, &wait_val, 0, 0) == -1)
-		wait_val = -1;
+	if (wait4(pid, &ret_val, 0, 0) == -1)
+		ret_val = -1;
 
+error_vfork:
+	if (sigprocmask(SIG_SETMASK, &omask, NULL) != 0)
+		ret_val = -1;
+error_block:
 	signal(SIGQUIT, save_quit);
 	signal(SIGINT, save_int);
-	signal(SIGCHLD, save_chld);
-	return wait_val;
+	return ret_val;
 }
 #else
 /* We have to and actually can handle cancelable system().  The big
-- 
1.7.2.5



More information about the uClibc mailing list