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