diff options
author | jraynard <jraynard@FreeBSD.org> | 1996-06-05 00:08:54 +0000 |
---|---|---|
committer | jraynard <jraynard@FreeBSD.org> | 1996-06-05 00:08:54 +0000 |
commit | f12d02958af4923cccf62583718f39baa06fa941 (patch) | |
tree | 10283a97de8afbdc5464824310abeebd04f2f5f2 /lib/libc/stdlib/system.c | |
parent | 01b73f855a2b4735f46664d4ccf4d1319aad3e54 (diff) | |
download | FreeBSD-src-f12d02958af4923cccf62583718f39baa06fa941.zip FreeBSD-src-f12d02958af4923cccf62583718f39baa06fa941.tar.gz |
Submitted by: (based on code in "Advanced Programming in the Unix Environment"
by W.Richard Ste vens. EINTR handling suggested by bde@freebsd.org).
Code cleanup:
1. Add missing return type.
2. Replace 'union wait' by int.
3. Use Posix-style signal handling instead of signal().
4. Use fork() instead of deprecated vfork().
5. Block signals before fork()'ing, instead of after.
6. Return -1 if fork() fails, instead of 0.
7. Add EINTR handling for waitpid() call.
Also add claim of Posix conformance to man page.
Diffstat (limited to 'lib/libc/stdlib/system.c')
-rw-r--r-- | lib/libc/stdlib/system.c | 51 |
1 files changed, 33 insertions, 18 deletions
diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c index c438f17..3bae36a 100644 --- a/lib/libc/stdlib/system.c +++ b/lib/libc/stdlib/system.c @@ -42,35 +42,50 @@ static char sccsid[] = "@(#)system.c 8.1 (Berkeley) 6/4/93"; #include <stddef.h> #include <unistd.h> #include <paths.h> +#include <errno.h> -system(command) +int system(command) const char *command; { - union wait pstat; pid_t pid; - int omask; - sig_t intsave, quitsave; + int pstat; + struct sigaction ign, intact, quitact; + sigset_t newsigblock, oldsigblock; if (!command) /* just checking... */ return(1); - omask = sigblock(sigmask(SIGCHLD)); - switch(pid = vfork()) { + /* + * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save + * existing signal dispositions. + */ + ign.sa_handler = SIG_IGN; + (void)sigemptyset(&ign.sa_mask); + ign.sa_flags = 0; + (void)sigaction(SIGINT, &ign, &intact); + (void)sigaction(SIGQUIT, &ign, &quitact); + (void)sigemptyset(&newsigblock); + sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); + switch(pid = fork()) { case -1: /* error */ - (void)sigsetmask(omask); - pstat.w_status = 0; - pstat.w_retcode = 127; - return(pstat.w_status); + break; case 0: /* child */ - (void)sigsetmask(omask); + /* + * Restore original signal dispositions and exec the command. + */ + (void)sigaction(SIGINT, &intact, NULL); + (void)sigaction(SIGQUIT, &quitact, NULL); + (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL); execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); _exit(127); + default: /* parent */ + do { + pid = waitpid(pid, &pstat, 0); + } while (pid == -1 && errno == EINTR); + break; } - intsave = signal(SIGINT, SIG_IGN); - quitsave = signal(SIGQUIT, SIG_IGN); - pid = waitpid(pid, (int *)&pstat, 0); - (void)sigsetmask(omask); - (void)signal(SIGINT, intsave); - (void)signal(SIGQUIT, quitsave); - return(pid == -1 ? -1 : pstat.w_status); + (void)sigaction(SIGINT, &intact, NULL); + (void)sigaction(SIGQUIT, &quitact, NULL); + (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + return(pid == -1 ? -1 : pstat); } |