source: trunk/libs/newlib/src/newlib/libc/stdlib/system.c @ 543

Last change on this file since 543 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

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