system.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
  3. *
  4. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  5. */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <stddef.h>
  9. #include <signal.h>
  10. #include <unistd.h>
  11. #include <sys/wait.h>
  12. #include <stdlib.h>
  13. #ifdef __UCLIBC_HAS_THREADS_NATIVE__
  14. #include <sched.h>
  15. #include <errno.h>
  16. #include <bits/libc-lock.h>
  17. #include <sysdep-cancel.h>
  18. #endif
  19. extern __typeof(system) __libc_system;
  20. /* TODO: the cancellable version breaks on sparc currently,
  21. * need to figure out why still
  22. */
  23. #if !defined __UCLIBC_HAS_THREADS_NATIVE__ || defined __sparc__
  24. /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
  25. #include <sys/syscall.h>
  26. #ifndef __NR_vfork
  27. # define vfork fork
  28. #endif
  29. int __libc_system(const char *command)
  30. {
  31. int wait_val, pid;
  32. struct sigaction sa, save_quit, save_int;
  33. sigset_t save_mask;
  34. if (command == 0)
  35. return 1;
  36. memset(&sa, 0, sizeof(sa));
  37. sa.sa_handler = SIG_IGN;
  38. /* __sigemptyset(&sa.sa_mask); - done by memset() */
  39. /* sa.sa_flags = 0; - done by memset() */
  40. sigaction(SIGQUIT, &sa, &save_quit);
  41. sigaction(SIGINT, &sa, &save_int);
  42. __sigaddset(&sa.sa_mask, SIGCHLD);
  43. sigprocmask(SIG_BLOCK, &sa.sa_mask, &save_mask);
  44. if ((pid = vfork()) < 0) {
  45. wait_val = -1;
  46. goto out;
  47. }
  48. if (pid == 0) {
  49. sigaction(SIGQUIT, &save_quit, NULL);
  50. sigaction(SIGINT, &save_int, NULL);
  51. sigprocmask(SIG_SETMASK, &save_mask, NULL);
  52. execl("/bin/sh", "sh", "-c", command, (char *) 0);
  53. _exit(127);
  54. }
  55. #if 0
  56. __printf("Waiting for child %d\n", pid);
  57. #endif
  58. if (wait4(pid, &wait_val, 0, 0) == -1)
  59. wait_val = -1;
  60. out:
  61. sigaction(SIGQUIT, &save_quit, NULL);
  62. sigaction(SIGINT, &save_int, NULL);
  63. sigprocmask(SIG_SETMASK, &save_mask, NULL);
  64. return wait_val;
  65. }
  66. #else
  67. /* We have to and actually can handle cancelable system(). The big
  68. problem: we have to kill the child process if necessary. To do
  69. this a cleanup handler has to be registered and is has to be able
  70. to find the PID of the child. The main problem is to reliable have
  71. the PID when needed. It is not necessary for the parent thread to
  72. return. It might still be in the kernel when the cancellation
  73. request comes. Therefore we have to use the clone() calls ability
  74. to have the kernel write the PID into the user-level variable. */
  75. libc_hidden_proto(sigaction)
  76. libc_hidden_proto(waitpid)
  77. #if defined __ia64__
  78. # define FORK() \
  79. INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
  80. &pid, NULL, NULL)
  81. #elif defined __sparc__
  82. # define FORK() \
  83. INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
  84. #elif defined __s390__
  85. # define FORK() \
  86. INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid)
  87. #else
  88. # define FORK() \
  89. INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
  90. #endif
  91. static void cancel_handler (void *arg);
  92. # define CLEANUP_HANDLER \
  93. __libc_cleanup_region_start (1, cancel_handler, &pid)
  94. # define CLEANUP_RESET \
  95. __libc_cleanup_region_end (0)
  96. static struct sigaction intr, quit;
  97. static int sa_refcntr;
  98. __libc_lock_define_initialized (static, lock);
  99. # define DO_LOCK() __libc_lock_lock (lock)
  100. # define DO_UNLOCK() __libc_lock_unlock (lock)
  101. # define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
  102. # define ADD_REF() sa_refcntr++
  103. # define SUB_REF() --sa_refcntr
  104. /* Execute LINE as a shell command, returning its status. */
  105. static int
  106. do_system (const char *line)
  107. {
  108. int status, save;
  109. pid_t pid;
  110. struct sigaction sa;
  111. sigset_t omask;
  112. memset(&sa, 0, sizeof(sa));
  113. sa.sa_handler = SIG_IGN;
  114. /*sa.sa_flags = 0; - done by memset */
  115. /*__sigemptyset (&sa.sa_mask); - done by memset */
  116. DO_LOCK ();
  117. if (ADD_REF () == 0)
  118. {
  119. if (sigaction (SIGINT, &sa, &intr) < 0)
  120. {
  121. SUB_REF ();
  122. goto out;
  123. }
  124. if (sigaction (SIGQUIT, &sa, &quit) < 0)
  125. {
  126. save = errno;
  127. SUB_REF ();
  128. goto out_restore_sigint;
  129. }
  130. }
  131. DO_UNLOCK ();
  132. /* We reuse the bitmap in the 'sa' structure. */
  133. __sigaddset (&sa.sa_mask, SIGCHLD);
  134. save = errno;
  135. if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
  136. {
  137. {
  138. DO_LOCK ();
  139. if (SUB_REF () == 0)
  140. {
  141. save = errno;
  142. (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
  143. out_restore_sigint:
  144. (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
  145. __set_errno (save);
  146. }
  147. out:
  148. DO_UNLOCK ();
  149. return -1;
  150. }
  151. }
  152. CLEANUP_HANDLER;
  153. pid = FORK ();
  154. if (pid == (pid_t) 0)
  155. {
  156. /* Child side. */
  157. const char *new_argv[4];
  158. new_argv[0] = "/bin/sh";
  159. new_argv[1] = "-c";
  160. new_argv[2] = line;
  161. new_argv[3] = NULL;
  162. /* Restore the signals. */
  163. (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
  164. (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
  165. (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
  166. INIT_LOCK ();
  167. /* Exec the shell. */
  168. (void) execve ("/bin/sh", (char *const *) new_argv, __environ);
  169. _exit (127);
  170. }
  171. else if (pid < (pid_t) 0)
  172. /* The fork failed. */
  173. status = -1;
  174. else
  175. /* Parent side. */
  176. {
  177. /* Note the system() is a cancellation point. But since we call
  178. waitpid() which itself is a cancellation point we do not
  179. have to do anything here. */
  180. if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
  181. status = -1;
  182. }
  183. CLEANUP_RESET;
  184. save = errno;
  185. DO_LOCK ();
  186. if ((SUB_REF () == 0
  187. && (sigaction (SIGINT, &intr, (struct sigaction *) NULL)
  188. | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
  189. || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
  190. {
  191. status = -1;
  192. }
  193. DO_UNLOCK ();
  194. return status;
  195. }
  196. int
  197. __libc_system (const char *line)
  198. {
  199. if (line == NULL)
  200. /* Check that we have a command processor available. It might
  201. not be available after a chroot(), for example. */
  202. return do_system ("exit 0") == 0;
  203. if (SINGLE_THREAD_P)
  204. return do_system (line);
  205. int oldtype = LIBC_CANCEL_ASYNC ();
  206. int result = do_system (line);
  207. LIBC_CANCEL_RESET (oldtype);
  208. return result;
  209. }
  210. /* The cancellation handler. */
  211. static void
  212. cancel_handler (void *arg)
  213. {
  214. pid_t child = *(pid_t *) arg;
  215. INTERNAL_SYSCALL_DECL (err);
  216. INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
  217. TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
  218. DO_LOCK ();
  219. if (SUB_REF () == 0)
  220. {
  221. (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
  222. (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
  223. }
  224. DO_UNLOCK ();
  225. }
  226. #endif
  227. #ifdef IS_IN_libc
  228. weak_alias(__libc_system,system)
  229. #endif