spawni.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /* Guts of POSIX spawn interface. Generic POSIX.1 version.
  2. Copyright (C) 2000-2006, 2008-2013 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #include <config.h>
  15. /* Specification. */
  16. #include <spawn.h>
  17. #include "spawn_int.h"
  18. #include "palloca.h"
  19. #include <errno.h>
  20. #include <fcntl.h>
  21. #ifndef O_LARGEFILE
  22. # define O_LARGEFILE 0
  23. #endif
  24. #if _LIBC || HAVE_PATHS_H
  25. # include <paths.h>
  26. #else
  27. # define _PATH_BSHELL "/bin/sh"
  28. #endif
  29. #include <signal.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <unistd.h>
  33. #if _LIBC
  34. # include <not-cancel.h>
  35. #else
  36. # define close_not_cancel close
  37. # define open_not_cancel open
  38. #endif
  39. #if _LIBC
  40. # include <local-setxid.h>
  41. #else
  42. # if !HAVE_SETEUID
  43. # define seteuid(id) setresuid (-1, id, -1)
  44. # endif
  45. # if !HAVE_SETEGID
  46. # define setegid(id) setresgid (-1, id, -1)
  47. # endif
  48. # define local_seteuid(id) seteuid (id)
  49. # define local_setegid(id) setegid (id)
  50. #endif
  51. #if _LIBC
  52. # define alloca __alloca
  53. # define execve __execve
  54. # define dup2 __dup2
  55. # define fork __fork
  56. # define getgid __getgid
  57. # define getuid __getuid
  58. # define sched_setparam __sched_setparam
  59. # define sched_setscheduler __sched_setscheduler
  60. # define setpgid __setpgid
  61. # define sigaction __sigaction
  62. # define sigismember __sigismember
  63. # define sigprocmask __sigprocmask
  64. # define strchrnul __strchrnul
  65. # define vfork __vfork
  66. #else
  67. # undef internal_function
  68. # define internal_function /* empty */
  69. #endif
  70. /* The Unix standard contains a long explanation of the way to signal
  71. an error after the fork() was successful. Since no new wait status
  72. was wanted there is no way to signal an error using one of the
  73. available methods. The committee chose to signal an error by a
  74. normal program exit with the exit code 127. */
  75. #define SPAWN_ERROR 127
  76. #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
  77. /* Native Windows API. */
  78. int
  79. __spawni (pid_t *pid, const char *file,
  80. const posix_spawn_file_actions_t *file_actions,
  81. const posix_spawnattr_t *attrp, char *const argv[],
  82. char *const envp[], int use_path)
  83. {
  84. /* Not yet implemented. */
  85. return ENOSYS;
  86. }
  87. #else
  88. /* The file is accessible but it is not an executable file. Invoke
  89. the shell to interpret it as a script. */
  90. static void
  91. internal_function
  92. script_execute (const char *file, char *const argv[], char *const envp[])
  93. {
  94. /* Count the arguments. */
  95. int argc = 0;
  96. while (argv[argc++])
  97. ;
  98. /* Construct an argument list for the shell. */
  99. {
  100. char **new_argv = (char **) alloca ((argc + 1) * sizeof (char *));
  101. new_argv[0] = (char *) _PATH_BSHELL;
  102. new_argv[1] = (char *) file;
  103. while (argc > 1)
  104. {
  105. new_argv[argc] = argv[argc - 1];
  106. --argc;
  107. }
  108. /* Execute the shell. */
  109. execve (new_argv[0], new_argv, envp);
  110. }
  111. }
  112. /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
  113. Before running the process perform the actions described in FILE-ACTIONS. */
  114. int
  115. __spawni (pid_t *pid, const char *file,
  116. const posix_spawn_file_actions_t *file_actions,
  117. const posix_spawnattr_t *attrp, char *const argv[],
  118. char *const envp[], int use_path)
  119. {
  120. pid_t new_pid;
  121. char *path, *p, *name;
  122. size_t len;
  123. size_t pathlen;
  124. /* Do this once. */
  125. short int flags = attrp == NULL ? 0 : attrp->_flags;
  126. /* Avoid gcc warning
  127. "variable 'flags' might be clobbered by 'longjmp' or 'vfork'" */
  128. (void) &flags;
  129. /* Generate the new process. */
  130. #if HAVE_VFORK
  131. if ((flags & POSIX_SPAWN_USEVFORK) != 0
  132. /* If no major work is done, allow using vfork. Note that we
  133. might perform the path searching. But this would be done by
  134. a call to execvp(), too, and such a call must be OK according
  135. to POSIX. */
  136. || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
  137. | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
  138. | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
  139. && file_actions == NULL))
  140. new_pid = vfork ();
  141. else
  142. #endif
  143. new_pid = fork ();
  144. if (new_pid != 0)
  145. {
  146. if (new_pid < 0)
  147. return errno;
  148. /* The call was successful. Store the PID if necessary. */
  149. if (pid != NULL)
  150. *pid = new_pid;
  151. return 0;
  152. }
  153. /* Set signal mask. */
  154. if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
  155. && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
  156. _exit (SPAWN_ERROR);
  157. /* Set signal default action. */
  158. if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
  159. {
  160. /* We have to iterate over all signals. This could possibly be
  161. done better but it requires system specific solutions since
  162. the sigset_t data type can be very different on different
  163. architectures. */
  164. int sig;
  165. struct sigaction sa;
  166. memset (&sa, '\0', sizeof (sa));
  167. sa.sa_handler = SIG_DFL;
  168. for (sig = 1; sig <= NSIG; ++sig)
  169. if (sigismember (&attrp->_sd, sig) != 0
  170. && sigaction (sig, &sa, NULL) != 0)
  171. _exit (SPAWN_ERROR);
  172. }
  173. #if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
  174. /* Set the scheduling algorithm and parameters. */
  175. if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
  176. == POSIX_SPAWN_SETSCHEDPARAM)
  177. {
  178. if (sched_setparam (0, &attrp->_sp) == -1)
  179. _exit (SPAWN_ERROR);
  180. }
  181. else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
  182. {
  183. if (sched_setscheduler (0, attrp->_policy,
  184. (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
  185. ? &attrp->_sp : NULL) == -1)
  186. _exit (SPAWN_ERROR);
  187. }
  188. #endif
  189. /* Set the process group ID. */
  190. if ((flags & POSIX_SPAWN_SETPGROUP) != 0
  191. && setpgid (0, attrp->_pgrp) != 0)
  192. _exit (SPAWN_ERROR);
  193. /* Set the effective user and group IDs. */
  194. if ((flags & POSIX_SPAWN_RESETIDS) != 0
  195. && (local_seteuid (getuid ()) != 0
  196. || local_setegid (getgid ()) != 0))
  197. _exit (SPAWN_ERROR);
  198. /* Execute the file actions. */
  199. if (file_actions != NULL)
  200. {
  201. int cnt;
  202. for (cnt = 0; cnt < file_actions->_used; ++cnt)
  203. {
  204. struct __spawn_action *action = &file_actions->_actions[cnt];
  205. switch (action->tag)
  206. {
  207. case spawn_do_close:
  208. if (close_not_cancel (action->action.close_action.fd) != 0)
  209. /* Signal the error. */
  210. _exit (SPAWN_ERROR);
  211. break;
  212. case spawn_do_open:
  213. {
  214. int new_fd = open_not_cancel (action->action.open_action.path,
  215. action->action.open_action.oflag
  216. | O_LARGEFILE,
  217. action->action.open_action.mode);
  218. if (new_fd == -1)
  219. /* The 'open' call failed. */
  220. _exit (SPAWN_ERROR);
  221. /* Make sure the desired file descriptor is used. */
  222. if (new_fd != action->action.open_action.fd)
  223. {
  224. if (dup2 (new_fd, action->action.open_action.fd)
  225. != action->action.open_action.fd)
  226. /* The 'dup2' call failed. */
  227. _exit (SPAWN_ERROR);
  228. if (close_not_cancel (new_fd) != 0)
  229. /* The 'close' call failed. */
  230. _exit (SPAWN_ERROR);
  231. }
  232. }
  233. break;
  234. case spawn_do_dup2:
  235. if (dup2 (action->action.dup2_action.fd,
  236. action->action.dup2_action.newfd)
  237. != action->action.dup2_action.newfd)
  238. /* The 'dup2' call failed. */
  239. _exit (SPAWN_ERROR);
  240. break;
  241. }
  242. }
  243. }
  244. if (! use_path || strchr (file, '/') != NULL)
  245. {
  246. /* The FILE parameter is actually a path. */
  247. execve (file, argv, envp);
  248. if (errno == ENOEXEC)
  249. script_execute (file, argv, envp);
  250. /* Oh, oh. 'execve' returns. This is bad. */
  251. _exit (SPAWN_ERROR);
  252. }
  253. /* We have to search for FILE on the path. */
  254. path = getenv ("PATH");
  255. if (path == NULL)
  256. {
  257. #if HAVE_CONFSTR
  258. /* There is no 'PATH' in the environment.
  259. The default search path is the current directory
  260. followed by the path 'confstr' returns for '_CS_PATH'. */
  261. len = confstr (_CS_PATH, (char *) NULL, 0);
  262. path = (char *) alloca (1 + len);
  263. path[0] = ':';
  264. (void) confstr (_CS_PATH, path + 1, len);
  265. #else
  266. /* Pretend that the PATH contains only the current directory. */
  267. path = "";
  268. #endif
  269. }
  270. len = strlen (file) + 1;
  271. pathlen = strlen (path);
  272. name = alloca (pathlen + len + 1);
  273. /* Copy the file name at the top. */
  274. name = (char *) memcpy (name + pathlen + 1, file, len);
  275. /* And add the slash. */
  276. *--name = '/';
  277. p = path;
  278. do
  279. {
  280. char *startp;
  281. path = p;
  282. p = strchrnul (path, ':');
  283. if (p == path)
  284. /* Two adjacent colons, or a colon at the beginning or the end
  285. of 'PATH' means to search the current directory. */
  286. startp = name + 1;
  287. else
  288. startp = (char *) memcpy (name - (p - path), path, p - path);
  289. /* Try to execute this name. If it works, execv will not return. */
  290. execve (startp, argv, envp);
  291. if (errno == ENOEXEC)
  292. script_execute (startp, argv, envp);
  293. switch (errno)
  294. {
  295. case EACCES:
  296. case ENOENT:
  297. case ESTALE:
  298. case ENOTDIR:
  299. /* Those errors indicate the file is missing or not executable
  300. by us, in which case we want to just try the next path
  301. directory. */
  302. break;
  303. default:
  304. /* Some other error means we found an executable file, but
  305. something went wrong executing it; return the error to our
  306. caller. */
  307. _exit (SPAWN_ERROR);
  308. }
  309. }
  310. while (*p++ != '\0');
  311. /* Return with an error. */
  312. _exit (SPAWN_ERROR);
  313. }
  314. #endif