diff options
Diffstat (limited to 'newlib/libc/stdlib/system.c')
-rw-r--r-- | newlib/libc/stdlib/system.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/newlib/libc/stdlib/system.c b/newlib/libc/stdlib/system.c new file mode 100644 index 0000000..4584ae1 --- /dev/null +++ b/newlib/libc/stdlib/system.c @@ -0,0 +1,179 @@ +/* +FUNCTION +<<system>>---execute command string + +INDEX + system +INDEX + _system_r + +ANSI_SYNOPSIS + #include <stdlib.h> + int system(char *<[s]>); + + int _system_r(void *<[reent]>, char *<[s]>); + +TRAD_SYNOPSIS + #include <stdlib.h> + int system(<[s]>) + char *<[s]>; + + int _system_r(<[reent]>, <[s]>) + char *<[reent]>; + char *<[s]>; + +DESCRIPTION + +Use <<system>> to pass a command string <<*<[s]>>> to <</bin/sh>> on +your system, and wait for it to finish executing. + +Use `<<system(NULL)>>' to test whether your system has <</bin/sh>> +available. + +The alternate function <<_system_r>> is a reentrant version. The +extra argument <[reent]> is a pointer to a reentrancy structure. + +RETURNS +<<system(NULL)>> returns a non-zero value if <</bin/sh>> is available, and +<<0>> if it is not. + +With a command argument, the result of <<system>> is the exit status +returned by <</bin/sh>>. + +PORTABILITY +ANSI C requires <<system>>, but leaves the nature and effects of a +command processor undefined. ANSI C does, however, specify that +<<system(NULL)>> return zero or nonzero to report on the existence of +a command processor. + +POSIX.2 requires <<system>>, and requires that it invoke a <<sh>>. +Where <<sh>> is found is left unspecified. + +Supporting OS subroutines required: <<_exit>>, <<_execve>>, <<_fork_r>>, +<<_wait_r>>. +*/ + +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <_syslist.h> + +#if defined (unix) || defined (__CYGWIN32__) +static int do_system (); +#endif + +int +_system_r (ptr, s) + struct _reent *ptr; + _CONST char *s; +{ +#ifdef NO_EXEC + if (s == NULL) + return 0; + errno = ENOSYS; + return -1; +#else + + /* ??? How to handle (s == NULL) here is not exactly clear. + If _fork_r fails, that's not really a justification for returning 0. + For now we always return 0 and leave it to each target to explicitly + handle otherwise (this can always be relaxed in the future). */ + +#if defined (unix) || defined (__CYGWIN32__) + if (s == NULL) + return 1; + return do_system (ptr, s); +#else + if (s == NULL) + return 0; + errno = ENOSYS; + return -1; +#endif + +#endif +} + +#ifndef _REENT_ONLY + +int +system (s) + _CONST char *s; +{ + return _system_r (_REENT, s); +} + +#endif + +#if defined (unix) && !defined (__CYGWIN32__) +static int +do_system (ptr, s) + struct _reent *ptr; + _CONST char *s; +{ + char *argv[4]; + int pid, status; + extern char *environ[]; + + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = (char *) s; + argv[3] = NULL; + + if ((pid = _fork_r (ptr)) == 0) + { + _execve ("/bin/sh", argv, environ); + exit (100); + } + else if (pid == -1) + return -1; + else + { + int rc = _wait_r (ptr, &status); + if (rc == -1) + return -1; + status = (status >> 8) & 0xff; + return status; + } +} +#endif + +#if defined (__CYGWIN32__) +static int +do_system (ptr, s) + struct _reent *ptr; + _CONST char *s; +{ + char *argv[4]; + int pid, status; + extern char *environ[]; + + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = (char *) s; + argv[3] = NULL; + + if ((pid = vfork ()) == 0) + { + /* ??? It's not clear what's the right path to take (pun intended :-). + There won't be an "sh" in any fixed location so we need each user + to be able to say where to find "sh". That suggests using an + environment variable, but after a few more such situations we may + have too many of them. */ + char *sh = getenv ("SH_PATH"); + if (sh == NULL) + sh = "/bin/sh"; + _execve (sh, argv, environ); + exit (100); + } + else if (pid == -1) + return -1; + else + { + int rc = _wait (&status); + if (rc == -1) + return -1; + status = (status >> 8) & 0xff; + return status; + } +} +#endif |