Formerly posix/system.c.~9~
[kopensolaris-gnu/glibc.git] / sysdeps / posix / system.c
1 /* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <stddef.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/wait.h>
24 #include <signal.h>
25 #include <sys/types.h>
26
27
28 #ifndef HAVE_GNU_LD
29 #define __environ       environ
30 #endif
31
32 #define SHELL_PATH      "/bin/sh"       /* Path of the shell.  */
33 #define SHELL_NAME      "sh"            /* Name to give it.  */
34
35 /* Execute LINE as a shell command, returning its status.  */
36 int
37 DEFUN(system, (line), register CONST char *line)
38 {
39   int status, save;
40   pid_t pid;
41   struct sigaction sa, intr, quit;
42   sigset_t block, omask;
43
44   if (line == NULL)
45     return 1;
46
47   sa.sa_handler = SIG_IGN;
48   sa.sa_flags = 0;
49   __sigemptyset (&sa.sa_mask);
50
51   if (__sigaction (SIGINT, &sa, &intr) < 0)
52     return -1;
53   if (__sigaction (SIGQUIT, &sa, &quit) < 0)
54     {
55       save = errno;
56       (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
57       errno = save;
58       return -1;
59     }
60
61   __sigemptyset (&block);
62   __sigaddset (&block, SIGCHLD);
63   save = errno;
64   if (__sigprocmask(SIG_BLOCK, &block, &omask) < 0)
65     {
66       if (errno == ENOSYS)
67         errno = save;
68       else
69         {
70           save = errno;
71           (void) __sigaction(SIGINT, &intr, (struct sigaction *) NULL);
72           (void) __sigaction(SIGQUIT, &quit, (struct sigaction *) NULL);
73           errno = save;
74           return -1;
75         }
76     }
77
78   pid = __vfork ();
79   if (pid == (pid_t) 0)
80     {
81       /* Child side.  */
82       CONST char *new_argv[4];
83       new_argv[0] = SHELL_NAME;
84       new_argv[1] = "-c";
85       new_argv[2] = line;
86       new_argv[3] = NULL;
87
88       /* Restore the signals.  */
89       (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
90       (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
91       (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
92
93       /* Exec the shell.  */
94       (void) __execve (SHELL_PATH, (char *CONST *) new_argv, __environ);
95       _exit (127);
96     }
97   else if (pid < (pid_t) 0)
98     /* The fork failed.  */
99     status = -1;
100   else
101     /* Parent side.  */
102 #ifdef  NO_WAITPID
103     {
104       pid_t child;
105       do
106         {
107           child = __wait (&status);
108           if (child <= -1)
109             {
110               status = -1;
111               break;
112             }
113         } while (child != pid);
114     }
115 #else
116     if (__waitpid (pid, &status, 0) != pid)
117       status = -1;
118 #endif
119
120   save = errno;
121   if ((__sigaction (SIGINT, &intr, (struct sigaction *) NULL) |
122        __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL) |
123        __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL)) != 0)
124     {
125       if (errno == ENOSYS)
126         errno = save;
127       else
128         return -1;
129     }
130
131   return status;
132 }