1 /*
2 Copyright (c) 1990 Regents of the University of California.
3 All rights reserved.
4  */
5 /*
6 FUNCTION
7 <<system>>---execute command string
8 
9 INDEX
10 	system
11 INDEX
12 	_system_r
13 
14 SYNOPSIS
15 	#include <stdlib.h>
16 	int system(char *<[s]>);
17 
18 	int _system_r(void *<[reent]>, char *<[s]>);
19 
20 DESCRIPTION
21 
22 Use <<system>> to pass a command string <<*<[s]>>> to <</bin/sh>> on
23 your system, and wait for it to finish executing.
24 
25 Use ``<<system(NULL)>>'' to test whether your system has <</bin/sh>>
26 available.
27 
28 The alternate function <<_system_r>> is a reentrant version.  The
29 extra argument <[reent]> is a pointer to a reentrancy structure.
30 
31 RETURNS
32 <<system(NULL)>> returns a non-zero value if <</bin/sh>> is available, and
33 <<0>> if it is not.
34 
35 With a command argument, the result of <<system>> is the exit status
36 returned by <</bin/sh>>.
37 
38 PORTABILITY
39 ANSI C requires <<system>>, but leaves the nature and effects of a
40 command processor undefined.  ANSI C does, however, specify that
41 <<system(NULL)>> return zero or nonzero to report on the existence of
42 a command processor.
43 
44 POSIX.2 requires <<system>>, and requires that it invoke a <<sh>>.
45 Where <<sh>> is found is left unspecified.
46 
47 Supporting OS subroutines required: <<_exit>>, <<_execve>>, <<_fork_r>>,
48 <<_wait_r>>.
49 */
50 
51 #include <_ansi.h>
52 #include <errno.h>
53 #include <stddef.h>
54 #include <stdlib.h>
55 #include <unistd.h>
56 #include <_syslist.h>
57 #include <sys/wait.h>
58 
59 #if defined (unix) || defined (__CYGWIN__)
60 static int do_system (const char *s);
61 #endif
62 
63 #ifndef _REENT_ONLY
64 
65 int
system(const char * s)66 system (const char *s)
67 {
68 #if defined(HAVE_SYSTEM)
69   return _system (s);
70 #elif defined(NO_EXEC)
71   if (s == NULL)
72     return 0;
73   errno = ENOSYS;
74   return -1;
75 #else
76 
77   /* ??? How to handle (s == NULL) here is not exactly clear.
78      If _fork_r fails, that's not really a justification for returning 0.
79      For now we always return 0 and leave it to each target to explicitly
80      handle otherwise (this can always be relaxed in the future).  */
81 
82 #if defined (unix) || defined (__CYGWIN__)
83   if (s == NULL)
84     return 1;
85   return do_system (s);
86 #else
87   if (s == NULL)
88     return 0;
89   errno = ENOSYS;
90   return -1;
91 #endif
92 
93 #endif
94 }
95 
96 #endif
97 
98 #if defined (unix) && !defined (__CYGWIN__) && !defined(__rtems__)
99 extern char **environ;
100 
101 /* Only deal with a pointer to environ, to work around subtle bugs with shared
102    libraries and/or small data systems where the user declares his own
103    'environ'.  */
104 static char ***p_environ = &environ;
105 
106 static int
do_system(const char * s)107 do_system (const char *s)
108 {
109   char *argv[4];
110   int pid, status;
111 
112   argv[0] = "sh";
113   argv[1] = "-c";
114   argv[2] = (char *) s;
115   argv[3] = NULL;
116 
117   if ((pid = fork ()) == 0)
118     {
119       execve ("/bin/sh", argv, *p_environ);
120       exit (100);
121     }
122   else if (pid == -1)
123     return -1;
124   else
125     {
126       int rc = wait (&status);
127       if (rc == -1)
128 	return -1;
129       status = (status >> 8) & 0xff;
130       return status;
131     }
132 }
133 #endif
134 
135 #if defined (__CYGWIN__)
136 static int
do_system(const char * s)137 do_system (const char *s)
138 {
139   char *argv[4];
140   int pid, status;
141 
142   argv[0] = "sh";
143   argv[1] = "-c";
144   argv[2] = (char *) s;
145   argv[3] = NULL;
146 
147   if ((pid = vfork ()) == 0)
148     {
149       /* ??? It's not clear what's the right path to take (pun intended :-).
150 	 There won't be an "sh" in any fixed location so we need each user
151 	 to be able to say where to find "sh".  That suggests using an
152 	 environment variable, but after a few more such situations we may
153 	 have too many of them.  */
154       char *sh = getenv ("SH_PATH");
155       if (sh == NULL)
156 	sh = "/bin/sh";
157       _execve (sh, argv, environ);
158       exit (100);
159     }
160   else if (pid == -1)
161     return -1;
162   else
163     {
164       extern int _wait (int *);
165       int rc = _wait (&status);
166       if (rc == -1)
167 	return -1;
168       status = (status >> 8) & 0xff;
169       return status;
170     }
171 }
172 #endif
173