1 /* Copyright (C) 1991-1999, 2000 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 Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the 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 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
18
19 #include <stddef.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <sys/wait.h>
23 #include <signal.h>
24 #include <sys/types.h>
25 #include <errno.h>
26 #include <machine/weakalias.h>
27
28
29 #ifndef HAVE_GNU_LD
30 #define __environ environ
31 #endif
32
33 #define SHELL_PATH "/bin/sh" /* Path of the shell. */
34 #define SHELL_NAME "sh" /* Name to give it. */
35
36 /* Execute LINE as a shell command, returning its status. */
37 int
__libc_system(const char * line)38 __libc_system (const char *line)
39 {
40 int status, save;
41 pid_t pid;
42 struct sigaction sa, intr, quit;
43 #ifndef WAITPID_CANNOT_BLOCK_SIGCHLD
44 sigset_t block, omask;
45 #endif
46
47 if (line == NULL)
48 /* Check that we have a command processor available. It might
49 not be available after a chroot(), for example. */
50 return __libc_system ("exit 0") == 0;
51
52 sa.sa_handler = SIG_IGN;
53 sa.sa_flags = 0;
54 sigemptyset (&sa.sa_mask);
55
56 if (sigaction (SIGINT, &sa, &intr) < 0)
57 return -1;
58 if (sigaction (SIGQUIT, &sa, &quit) < 0)
59 {
60 save = errno;
61 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
62 errno = save;
63 return -1;
64 }
65
66 #ifndef WAITPID_CANNOT_BLOCK_SIGCHLD
67
68 /* SCO 3.2v4 has a bug where `waitpid' will never return if SIGCHLD is
69 blocked. This makes it impossible for `system' to be implemented in
70 compliance with POSIX.2-1992. They have acknowledged that this is a bug
71 but I have not seen nor heard of any forthcoming fix. */
72
73 sigemptyset (&block);
74 sigaddset (&block, SIGCHLD);
75 save = errno;
76 if (sigprocmask (SIG_BLOCK, &block, &omask) < 0)
77 {
78 if (errno == ENOSYS)
79 errno = save;
80 else
81 {
82 save = errno;
83 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
84 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
85 errno = save;
86 return -1;
87 }
88 }
89 # define UNBLOCK sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL)
90 #else
91 # define UNBLOCK 0
92 #endif
93
94 pid = fork ();
95 if (pid == (pid_t) 0)
96 {
97 /* Child side. */
98 const char *new_argv[4];
99 new_argv[0] = SHELL_NAME;
100 new_argv[1] = "-c";
101 new_argv[2] = line;
102 new_argv[3] = NULL;
103
104 /* Restore the signals. */
105 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
106 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
107 (void) UNBLOCK;
108
109 /* Exec the shell. */
110 (void) execve (SHELL_PATH, (char *const *) new_argv, __environ);
111 _exit (127);
112 }
113 else if (pid < (pid_t) 0)
114 /* The fork failed. */
115 status = -1;
116 else
117 /* Parent side. */
118 {
119 #ifdef NO_WAITPID
120 pid_t child;
121 do
122 {
123 child = wait (&status);
124 if (child <= -1 && errno != EINTR)
125 {
126 status = -1;
127 break;
128 }
129 /* Note that pid cannot be <= -1 and therefore the loop continues
130 when wait returned with EINTR. */
131 }
132 while (child != pid);
133 #else
134 int n;
135
136 do
137 n = waitpid (pid, &status, 0);
138 while (n == -1 && errno == EINTR);
139
140 if (n != pid)
141 status = -1;
142 #endif
143 }
144
145 save = errno;
146 if ((sigaction (SIGINT, &intr, (struct sigaction *) NULL) |
147 sigaction (SIGQUIT, &quit, (struct sigaction *) NULL) |
148 UNBLOCK) != 0)
149 {
150 if (errno == ENOSYS)
151 errno = save;
152 else
153 return -1;
154 }
155
156 return status;
157 }
158 weak_alias (__libc_system, system)
159