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 <errno.h>
52 #include <stddef.h>
53 #include <stdlib.h>
54 #include <unistd.h>
55 #include <_syslist.h>
56 #include <sys/wait.h>
57 
58 #if defined (unix) || defined (__CYGWIN__)
59 static int do_system (const char *s);
60 #endif
61 
62 #ifndef _REENT_ONLY
63 
64 int
system(const char * s)65 system (const char *s)
66 {
67 #if defined(HAVE_SYSTEM)
68   return _system (s);
69 #elif defined(NO_EXEC)
70   if (s == NULL)
71     return 0;
72   errno = ENOSYS;
73   return -1;
74 #else
75 
76   /* ??? How to handle (s == NULL) here is not exactly clear.
77      If _fork_r fails, that's not really a justification for returning 0.
78      For now we always return 0 and leave it to each target to explicitly
79      handle otherwise (this can always be relaxed in the future).  */
80 
81 #if defined (unix) || defined (__CYGWIN__)
82   if (s == NULL)
83     return 1;
84   return do_system (s);
85 #else
86   if (s == NULL)
87     return 0;
88   errno = ENOSYS;
89   return -1;
90 #endif
91 
92 #endif
93 }
94 
95 #endif
96 
97 #if defined (unix) && !defined (__CYGWIN__) && !defined(__rtems__)
98 extern char **environ;
99 
100 /* Only deal with a pointer to environ, to work around subtle bugs with shared
101    libraries and/or small data systems where the user declares his own
102    'environ'.  */
103 static char ***p_environ = &environ;
104 
105 static int
do_system(const char * s)106 do_system (const char *s)
107 {
108   char *argv[4];
109   int pid, status;
110 
111   argv[0] = "sh";
112   argv[1] = "-c";
113   argv[2] = (char *) s;
114   argv[3] = NULL;
115 
116   if ((pid = fork ()) == 0)
117     {
118       execve ("/bin/sh", argv, *p_environ);
119       exit (100);
120     }
121   else if (pid == -1)
122     return -1;
123   else
124     {
125       int rc = wait (&status);
126       if (rc == -1)
127 	return -1;
128       status = (status >> 8) & 0xff;
129       return status;
130     }
131 }
132 #endif
133 
134