home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * $Source: /unixb/home/unixlib/source/unixlib37/src/c/RCS/system,v $
- * $Date: 1996/10/30 21:58:59 $
- * $Revision: 1.4 $
- * $State: Rel $
- * $Author: unixlib $
- *
- * $Log: system,v $
- * Revision 1.4 1996/10/30 21:58:59 unixlib
- * Massive changes made by Nick Burret and Peter Burwood.
- *
- * Revision 1.3 1996/09/16 21:23:52 unixlib
- * CL_0002 Nick Burret
- * Minor changes to file handling
- * Change most error numbers, and use in assembler sources (SJC)
- * Various minor bug fixes and compatability changes.
- *
- * Revision 1.2 1996/05/06 09:03:13 unixlib
- * Updates to sources made by Nick Burrett, Peter Burwood and Simon Callan.
- * Saved for 3.7a release.
- *
- * Revision 1.1 1996/04/19 21:26:42 simon
- * Initial revision
- *
- ***************************************************************************/
-
- static const char rcs_id[] = "$Id: system,v 1.4 1996/10/30 21:58:59 unixlib Rel $";
-
- /* c.system: Written by Nick Burrett, 6 October 1996. */
-
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/wait.h>
- #include <signal.h>
- #include <sys/types.h>
-
-
- /* Execute LINE as a shell command, returning its status. */
- int system (const char *line)
- {
- int status, save;
- pid_t pid;
- struct sigaction sa, intr, quit;
- sigset_t block, omask;
-
- if (line == NULL)
- return 1;
-
- sa.sa_handler = SIG_IGN;
- sa.sa_flags = 0;
- sigemptyset (&sa.sa_mask);
-
- /* Ignore signals SIGINT and SIGQUIT. */
-
- if (sigaction (SIGINT, &sa, &intr))
- return -1;
-
- if (sigaction (SIGQUIT, &sa, &quit))
- {
- /* Bit of an error, restore SIGINT and preserve the errno. */
- save = errno;
- (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
- errno = save;
- return -1;
- }
-
- /* Block SIGCHLD. */
- sigemptyset (&block);
- sigaddset (&block, SIGCHLD);
- save = errno;
- if (sigprocmask (SIG_BLOCK, &block, &omask))
- {
- if (errno == ENOSYS)
- errno = save;
- else
- {
- /* Awkward error, so restore signal handlers and return. */
- save = errno;
- (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
- (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
- errno = save;
- return -1;
- }
- }
-
- /* vfork the process. */
- pid = vfork ();
- if (pid == (pid_t) 0)
- {
- char *shell, *path;
-
- /* Restore the signals. */
- sigaction (SIGINT, &intr, (struct sigaction *) NULL);
- sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
- /* Could deliver a few pending signals here. */
- sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
-
- /* Execute the shell. */
- if (!(path = getenv ("SHELL")))
- {
- if (*line == '*')
- execl ((char *) line, 0);
- else
- execl ("*", "", (char *) line, 0);
- _exit (1);
- }
-
- shell = strrchr (path, '/');
- if (shell)
- shell++;
- else
- shell = path;
- execl (path, shell, "-c", (char *)line, 0);
- _exit (1);
- }
- else if (pid < (pid_t) 0)
- /* The fork failed. */
- status = -1;
- else
- if (waitpid (pid, &status, 0) != pid)
- status = -1;
-
- /* Got here on a vfork failure. So restore signals and the blocking
- mask then exit. */
- save = errno;
- if ((sigaction (SIGINT, &intr, (struct sigaction *) NULL) |
- sigaction (SIGQUIT, &quit, (struct sigaction *) NULL) |
- sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL)) != 0)
- {
- if (errno == ENOSYS)
- errno = save;
- else
- return -1;
- }
-
- return status;
- }
-