Module Name: src Committed By: riastradh Date: Mon Mar 14 22:06:28 UTC 2022
Modified Files: src/lib/libc/stdlib: system.c Log Message: system(3): Switch from vfork/execve to posix_spawn. Changes by me: - Minor style nits. - Set errno on posix_spawn failure. - Handle edge cases of SIGINT/SIGQUIT set to SIG_IGN by caller. Author: Nikita Ronja Gillmann <nik...@netbsd.org> Committer: Taylor R Campbell <riastr...@netbsd.org> To generate a diff of this commit: cvs rdiff -u -r1.26 -r1.27 src/lib/libc/stdlib/system.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/stdlib/system.c diff -u src/lib/libc/stdlib/system.c:1.26 src/lib/libc/stdlib/system.c:1.27 --- src/lib/libc/stdlib/system.c:1.26 Fri Oct 29 19:27:06 2021 +++ src/lib/libc/stdlib/system.c Mon Mar 14 22:06:28 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: system.c,v 1.26 2021/10/29 19:27:06 kre Exp $ */ +/* $NetBSD: system.c,v 1.27 2022/03/14 22:06:28 riastradh Exp $ */ /* * Copyright (c) 1988, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)system.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: system.c,v 1.26 2021/10/29 19:27:06 kre Exp $"); +__RCSID("$NetBSD: system.c,v 1.27 2022/03/14 22:06:28 riastradh Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -46,6 +46,7 @@ __RCSID("$NetBSD: system.c,v 1.26 2021/1 #include <stdlib.h> #include <unistd.h> #include <paths.h> +#include <spawn.h> #include "env.h" @@ -54,9 +55,12 @@ system(const char *command) { pid_t pid; struct sigaction intsa, quitsa, sa; - sigset_t nmask, omask; + sigset_t nmask, omask, sigdefault; int pstat; const char *argp[] = {"sh", "-c", "--", NULL, NULL}; + posix_spawnattr_t attr; + int error; + argp[3] = command; /* @@ -88,22 +92,41 @@ system(const char *command) return -1; } + /* + * We arrange to inherit all signal handlers from the caller by + * default, except possibly SIGINT and SIGQUIT. These we have + * overridden internally for system(3) to be SIG_IGN. + * + * - If the caller had SIGINT or SIGQUIT at SIG_IGN, then we + * inherit them as is -- caller had SIG_IGN, child will too. + * + * - Otherwise, they are SIG_DFL or a signal handler, and we + * must reset them to SIG_DFL in the child, rather than + * SIG_IGN in system(3) in the parent, by including them in + * the sigdefault set. + */ + sigemptyset(&sigdefault); + if (intsa.sa_handler != SIG_IGN) + sigaddset(&sigdefault, SIGINT); + if (quitsa.sa_handler != SIG_IGN) + sigaddset(&sigdefault, SIGQUIT); + + posix_spawnattr_init(&attr); + posix_spawnattr_setsigdefault(&attr, &sigdefault); + posix_spawnattr_setsigmask(&attr, &omask); + posix_spawnattr_setflags(&attr, + POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK); (void)__readlockenv(); - switch(pid = vfork()) { - case -1: /* error */ - (void)__unlockenv(); - sigaction(SIGINT, &intsa, NULL); - sigaction(SIGQUIT, &quitsa, NULL); - (void)sigprocmask(SIG_SETMASK, &omask, NULL); - return -1; - case 0: /* child */ - sigaction(SIGINT, &intsa, NULL); - sigaction(SIGQUIT, &quitsa, NULL); - (void)sigprocmask(SIG_SETMASK, &omask, NULL); - execve(_PATH_BSHELL, __UNCONST(argp), environ); - _exit(127); - } + error = posix_spawn(&pid, _PATH_BSHELL, NULL, &attr, __UNCONST(argp), + environ); (void)__unlockenv(); + posix_spawnattr_destroy(&attr); + + if (error) { + errno = error; + pstat = -1; + goto out; + } while (waitpid(pid, &pstat, 0) == -1) { if (errno != EINTR) { @@ -112,7 +135,7 @@ system(const char *command) } } - sigaction(SIGINT, &intsa, NULL); +out: sigaction(SIGINT, &intsa, NULL); sigaction(SIGQUIT, &quitsa, NULL); (void)sigprocmask(SIG_SETMASK, &omask, NULL);