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