105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Guts of POSIX spawn interface.  Generic POSIX.1 version.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2000-2006, 2008-2012 Free Software Foundation, Inc.
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This file is part of the GNU C Library.
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software: you can redistribute it and/or modify
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   it under the terms of the GNU General Public License as published by
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3 of the License, or
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   (at your option) any later version.
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   GNU General Public License for more details.
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification.  */
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <spawn.h>
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "spawn_int.h"
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <alloca.h>
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <errno.h>
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <fcntl.h>
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef O_LARGEFILE
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define O_LARGEFILE 0
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if _LIBC || HAVE_PATHS_H
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <paths.h>
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define _PATH_BSHELL "/bin/sh"
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <signal.h>
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdlib.h>
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <string.h>
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <unistd.h>
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if _LIBC
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <not-cancel.h>
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define close_not_cancel close
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define open_not_cancel open
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if _LIBC
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <local-setxid.h>
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if !HAVE_SETEUID
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define seteuid(id) setresuid (-1, id, -1)
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if !HAVE_SETEGID
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define setegid(id) setresgid (-1, id, -1)
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define local_seteuid(id) seteuid (id)
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define local_setegid(id) setegid (id)
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if _LIBC
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define alloca __alloca
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define execve __execve
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define dup2 __dup2
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define fork __fork
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define getgid __getgid
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define getuid __getuid
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define sched_setparam __sched_setparam
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define sched_setscheduler __sched_setscheduler
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define setpgid __setpgid
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define sigaction __sigaction
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define sigismember __sigismember
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define sigprocmask __sigprocmask
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define strchrnul __strchrnul
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define vfork __vfork
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# undef internal_function
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define internal_function /* empty */
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* The Unix standard contains a long explanation of the way to signal
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   an error after the fork() was successful.  Since no new wait status
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   was wanted there is no way to signal an error using one of the
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   available methods.  The committee chose to signal an error by a
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   normal program exit with the exit code 127.  */
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define SPAWN_ERROR     127
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Native Windows API.  */
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang__spawni (pid_t *pid, const char *file,
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          const posix_spawn_file_actions_t *file_actions,
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          const posix_spawnattr_t *attrp, char *const argv[],
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          char *const envp[], int use_path)
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Not yet implemented.  */
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return ENOSYS;
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* The file is accessible but it is not an executable file.  Invoke
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the shell to interpret it as a script.  */
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic void
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wanginternal_function
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wangscript_execute (const char *file, char *const argv[], char *const envp[])
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Count the arguments.  */
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int argc = 0;
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  while (argv[argc++])
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    ;
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Construct an argument list for the shell.  */
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  {
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    char **new_argv = (char **) alloca ((argc + 1) * sizeof (char *));
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    new_argv[0] = (char *) _PATH_BSHELL;
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    new_argv[1] = (char *) file;
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    while (argc > 1)
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        new_argv[argc] = argv[argc - 1];
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        --argc;
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* Execute the shell.  */
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    execve (new_argv[0], new_argv, envp);
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  }
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Before running the process perform the actions described in FILE-ACTIONS. */
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang__spawni (pid_t *pid, const char *file,
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          const posix_spawn_file_actions_t *file_actions,
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          const posix_spawnattr_t *attrp, char *const argv[],
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          char *const envp[], int use_path)
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  pid_t new_pid;
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  char *path, *p, *name;
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t len;
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t pathlen;
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Do this once.  */
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  short int flags = attrp == NULL ? 0 : attrp->_flags;
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Avoid gcc warning
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang       "variable 'flags' might be clobbered by 'longjmp' or 'vfork'"  */
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  (void) &flags;
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Generate the new process.  */
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_VFORK
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if ((flags & POSIX_SPAWN_USEVFORK) != 0
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* If no major work is done, allow using vfork.  Note that we
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang         might perform the path searching.  But this would be done by
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang         a call to execvp(), too, and such a call must be OK according
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang         to POSIX.  */
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
16505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          && file_actions == NULL))
16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    new_pid = vfork ();
16805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
16905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    new_pid = fork ();
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (new_pid != 0)
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (new_pid < 0)
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        return errno;
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* The call was successful.  Store the PID if necessary.  */
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (pid != NULL)
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        *pid = new_pid;
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return 0;
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Set signal mask.  */
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
18605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    _exit (SPAWN_ERROR);
18805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
18905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Set signal default action.  */
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* We have to iterate over all signals.  This could possibly be
19305436638acc7c010349a69c3395f1a57c642dc62Ying Wang         done better but it requires system specific solutions since
19405436638acc7c010349a69c3395f1a57c642dc62Ying Wang         the sigset_t data type can be very different on different
19505436638acc7c010349a69c3395f1a57c642dc62Ying Wang         architectures.  */
19605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int sig;
19705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      struct sigaction sa;
19805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
19905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      memset (&sa, '\0', sizeof (sa));
20005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      sa.sa_handler = SIG_DFL;
20105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      for (sig = 1; sig <= NSIG; ++sig)
20305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (sigismember (&attrp->_sd, sig) != 0
20405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            && sigaction (sig, &sa, NULL) != 0)
20505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          _exit (SPAWN_ERROR);
20605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
20805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
21005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Set the scheduling algorithm and parameters.  */
21105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
21205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      == POSIX_SPAWN_SETSCHEDPARAM)
21305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
21405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (sched_setparam (0, &attrp->_sp) == -1)
21505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        _exit (SPAWN_ERROR);
21605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
21705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
21805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
21905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (sched_setscheduler (0, attrp->_policy,
22005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
22105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                              ? &attrp->_sp : NULL) == -1)
22205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        _exit (SPAWN_ERROR);
22305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
22405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
22505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
22605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Set the process group ID.  */
22705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if ((flags & POSIX_SPAWN_SETPGROUP) != 0
22805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      && setpgid (0, attrp->_pgrp) != 0)
22905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    _exit (SPAWN_ERROR);
23005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
23105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Set the effective user and group IDs.  */
23205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if ((flags & POSIX_SPAWN_RESETIDS) != 0
23305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      && (local_seteuid (getuid ()) != 0
23405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || local_setegid (getgid ()) != 0))
23505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    _exit (SPAWN_ERROR);
23605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
23705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Execute the file actions.  */
23805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (file_actions != NULL)
23905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
24005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int cnt;
24105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
24205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      for (cnt = 0; cnt < file_actions->_used; ++cnt)
24305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
24405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          struct __spawn_action *action = &file_actions->_actions[cnt];
24505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
24605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          switch (action->tag)
24705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
24805436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case spawn_do_close:
24905436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (close_not_cancel (action->action.close_action.fd) != 0)
25005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                /* Signal the error.  */
25105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                _exit (SPAWN_ERROR);
25205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              break;
25305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
25405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case spawn_do_open:
25505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              {
25605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                int new_fd = open_not_cancel (action->action.open_action.path,
25705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                              action->action.open_action.oflag
25805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                              | O_LARGEFILE,
25905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                              action->action.open_action.mode);
26005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
26105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                if (new_fd == -1)
26205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* The 'open' call failed.  */
26305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  _exit (SPAWN_ERROR);
26405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
26505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                /* Make sure the desired file descriptor is used.  */
26605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                if (new_fd != action->action.open_action.fd)
26705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  {
26805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    if (dup2 (new_fd, action->action.open_action.fd)
26905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        != action->action.open_action.fd)
27005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      /* The 'dup2' call failed.  */
27105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      _exit (SPAWN_ERROR);
27205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
27305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    if (close_not_cancel (new_fd) != 0)
27405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      /* The 'close' call failed.  */
27505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      _exit (SPAWN_ERROR);
27605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  }
27705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              }
27805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              break;
27905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
28005436638acc7c010349a69c3395f1a57c642dc62Ying Wang            case spawn_do_dup2:
28105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (dup2 (action->action.dup2_action.fd,
28205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        action->action.dup2_action.newfd)
28305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  != action->action.dup2_action.newfd)
28405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                /* The 'dup2' call failed.  */
28505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                _exit (SPAWN_ERROR);
28605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              break;
28705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
28805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
28905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
29005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
29105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (! use_path || strchr (file, '/') != NULL)
29205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
29305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* The FILE parameter is actually a path.  */
29405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      execve (file, argv, envp);
29505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
29605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (errno == ENOEXEC)
29705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        script_execute (file, argv, envp);
29805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
29905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Oh, oh.  'execve' returns.  This is bad.  */
30005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      _exit (SPAWN_ERROR);
30105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
30205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
30305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* We have to search for FILE on the path.  */
30405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  path = getenv ("PATH");
30505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (path == NULL)
30605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
30705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_CONFSTR
30805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* There is no 'PATH' in the environment.
30905436638acc7c010349a69c3395f1a57c642dc62Ying Wang         The default search path is the current directory
31005436638acc7c010349a69c3395f1a57c642dc62Ying Wang         followed by the path 'confstr' returns for '_CS_PATH'.  */
31105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      len = confstr (_CS_PATH, (char *) NULL, 0);
31205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      path = (char *) alloca (1 + len);
31305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      path[0] = ':';
31405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      (void) confstr (_CS_PATH, path + 1, len);
31505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
31605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Pretend that the PATH contains only the current directory.  */
31705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      path = "";
31805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
31905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
32005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
32105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  len = strlen (file) + 1;
32205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  pathlen = strlen (path);
32305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  name = alloca (pathlen + len + 1);
32405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Copy the file name at the top.  */
32505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  name = (char *) memcpy (name + pathlen + 1, file, len);
32605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* And add the slash.  */
32705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  *--name = '/';
32805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
32905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  p = path;
33005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  do
33105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
33205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      char *startp;
33305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
33405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      path = p;
33505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      p = strchrnul (path, ':');
33605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
33705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (p == path)
33805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Two adjacent colons, or a colon at the beginning or the end
33905436638acc7c010349a69c3395f1a57c642dc62Ying Wang           of 'PATH' means to search the current directory.  */
34005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        startp = name + 1;
34105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
34205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        startp = (char *) memcpy (name - (p - path), path, p - path);
34305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
34405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Try to execute this name.  If it works, execv will not return.  */
34505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      execve (startp, argv, envp);
34605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
34705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (errno == ENOEXEC)
34805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        script_execute (startp, argv, envp);
34905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
35005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      switch (errno)
35105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
35205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        case EACCES:
35305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        case ENOENT:
35405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        case ESTALE:
35505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        case ENOTDIR:
35605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Those errors indicate the file is missing or not executable
35705436638acc7c010349a69c3395f1a57c642dc62Ying Wang             by us, in which case we want to just try the next path
35805436638acc7c010349a69c3395f1a57c642dc62Ying Wang             directory.  */
35905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          break;
36005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
36105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        default:
36205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Some other error means we found an executable file, but
36305436638acc7c010349a69c3395f1a57c642dc62Ying Wang             something went wrong executing it; return the error to our
36405436638acc7c010349a69c3395f1a57c642dc62Ying Wang             caller.  */
36505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          _exit (SPAWN_ERROR);
36605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
36705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
36805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  while (*p++ != '\0');
36905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
37005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Return with an error.  */
37105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  _exit (SPAWN_ERROR);
37205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
37305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
37405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
375