Subversion Repositories Kolibri OS

Rev

Rev 4874 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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