Back to index

glibc  2.9
spawni.c
Go to the documentation of this file.
00001 /* Guts of POSIX spawn interface.  Generic POSIX.1 version.
00002    Copyright (C) 2000-2005, 2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <fcntl.h>
00022 #include <paths.h>
00023 #include <spawn.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <unistd.h>
00027 #include "spawn_int.h"
00028 #include <not-cancel.h>
00029 #include <local-setxid.h>
00030 
00031 
00032 /* The Unix standard contains a long explanation of the way to signal
00033    an error after the fork() was successful.  Since no new wait status
00034    was wanted there is no way to signal an error using one of the
00035    available methods.  The committee chose to signal an error by a
00036    normal program exit with the exit code 127.  */
00037 #define SPAWN_ERROR  127
00038 
00039 
00040 /* The file is accessible but it is not an executable file.  Invoke
00041    the shell to interpret it as a script.  */
00042 static void
00043 internal_function
00044 script_execute (const char *file, char *const argv[], char *const envp[])
00045 {
00046   /* Count the arguments.  */
00047   int argc = 0;
00048   while (argv[argc++])
00049     ;
00050 
00051   /* Construct an argument list for the shell.  */
00052   {
00053     char *new_argv[argc + 1];
00054     new_argv[0] = (char *) _PATH_BSHELL;
00055     new_argv[1] = (char *) file;
00056     while (argc > 1)
00057       {
00058        new_argv[argc] = argv[argc - 1];
00059        --argc;
00060       }
00061 
00062     /* Execute the shell.  */
00063     __execve (new_argv[0], new_argv, envp);
00064   }
00065 }
00066 
00067 
00068 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
00069    Before running the process perform the actions described in FILE-ACTIONS. */
00070 int
00071 __spawni (pid_t *pid, const char *file,
00072          const posix_spawn_file_actions_t *file_actions,
00073          const posix_spawnattr_t *attrp, char *const argv[],
00074          char *const envp[], int use_path)
00075 {
00076   pid_t new_pid;
00077   char *path, *p, *name;
00078   size_t len;
00079   size_t pathlen;
00080 
00081   /* Do this once.  */
00082   short int flags = attrp == NULL ? 0 : attrp->__flags;
00083 
00084   /* Generate the new process.  */
00085   if ((flags & POSIX_SPAWN_USEVFORK) != 0
00086       /* If no major work is done, allow using vfork.  Note that we
00087         might perform the path searching.  But this would be done by
00088         a call to execvp(), too, and such a call must be OK according
00089         to POSIX.  */
00090       || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
00091                   | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
00092                   | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
00093          && file_actions == NULL))
00094     new_pid = __vfork ();
00095   else
00096     new_pid = __fork ();
00097 
00098   if (new_pid != 0)
00099     {
00100       if (new_pid < 0)
00101        return errno;
00102 
00103       /* The call was successful.  Store the PID if necessary.  */
00104       if (pid != NULL)
00105        *pid = new_pid;
00106 
00107       return 0;
00108     }
00109 
00110   /* Set signal mask.  */
00111   if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
00112       && __sigprocmask (SIG_SETMASK, &attrp->__ss, NULL) != 0)
00113     _exit (SPAWN_ERROR);
00114 
00115   /* Set signal default action.  */
00116   if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
00117     {
00118       /* We have to iterate over all signals.  This could possibly be
00119         done better but it requires system specific solutions since
00120         the sigset_t data type can be very different on different
00121         architectures.  */
00122       int sig;
00123       struct sigaction sa;
00124 
00125       memset (&sa, '\0', sizeof (sa));
00126       sa.sa_handler = SIG_DFL;
00127 
00128       for (sig = 1; sig <= _NSIG; ++sig)
00129        if (__sigismember (&attrp->__sd, sig) != 0
00130            && __sigaction (sig, &sa, NULL) != 0)
00131          _exit (SPAWN_ERROR);
00132 
00133     }
00134 
00135 #ifdef _POSIX_PRIORITY_SCHEDULING
00136   /* Set the scheduling algorithm and parameters.  */
00137   if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
00138       == POSIX_SPAWN_SETSCHEDPARAM)
00139     {
00140       if (__sched_setparam (0, &attrp->__sp) == -1)
00141        _exit (SPAWN_ERROR);
00142     }
00143   else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
00144     {
00145       if (__sched_setscheduler (0, attrp->__policy,
00146                             (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
00147                             ? &attrp->__sp : NULL) == -1)
00148        _exit (SPAWN_ERROR);
00149     }
00150 #endif
00151 
00152   /* Set the process group ID.  */
00153   if ((flags & POSIX_SPAWN_SETPGROUP) != 0
00154       && __setpgid (0, attrp->__pgrp) != 0)
00155     _exit (SPAWN_ERROR);
00156 
00157   /* Set the effective user and group IDs.  */
00158   if ((flags & POSIX_SPAWN_RESETIDS) != 0
00159       && (local_seteuid (__getuid ()) != 0
00160          || local_setegid (__getgid ()) != 0))
00161     _exit (SPAWN_ERROR);
00162 
00163   /* Execute the file actions.  */
00164   if (file_actions != NULL)
00165     {
00166       int cnt;
00167 
00168       for (cnt = 0; cnt < file_actions->__used; ++cnt)
00169        {
00170          struct __spawn_action *action = &file_actions->__actions[cnt];
00171 
00172          switch (action->tag)
00173            {
00174            case spawn_do_close:
00175              if (close_not_cancel (action->action.close_action.fd) != 0)
00176               /* Signal the error.  */
00177               _exit (SPAWN_ERROR);
00178              break;
00179 
00180            case spawn_do_open:
00181              {
00182               int new_fd = open_not_cancel (action->action.open_action.path,
00183                                          action->action.open_action.oflag
00184                                          | O_LARGEFILE,
00185                                          action->action.open_action.mode);
00186 
00187               if (new_fd == -1)
00188                 /* The `open' call failed.  */
00189                 _exit (SPAWN_ERROR);
00190 
00191               /* Make sure the desired file descriptor is used.  */
00192               if (new_fd != action->action.open_action.fd)
00193                 {
00194                   if (__dup2 (new_fd, action->action.open_action.fd)
00195                      != action->action.open_action.fd)
00196                     /* The `dup2' call failed.  */
00197                     _exit (SPAWN_ERROR);
00198 
00199                   if (close_not_cancel (new_fd) != 0)
00200                     /* The `close' call failed.  */
00201                     _exit (SPAWN_ERROR);
00202                 }
00203              }
00204              break;
00205 
00206            case spawn_do_dup2:
00207              if (__dup2 (action->action.dup2_action.fd,
00208                        action->action.dup2_action.newfd)
00209                 != action->action.dup2_action.newfd)
00210               /* The `dup2' call failed.  */
00211               _exit (SPAWN_ERROR);
00212              break;
00213            }
00214        }
00215     }
00216 
00217   if (! use_path || strchr (file, '/') != NULL)
00218     {
00219       /* The FILE parameter is actually a path.  */
00220       __execve (file, argv, envp);
00221 
00222       if (errno == ENOEXEC)
00223        script_execute (file, argv, envp);
00224 
00225       /* Oh, oh.  `execve' returns.  This is bad.  */
00226       _exit (SPAWN_ERROR);
00227     }
00228 
00229   /* We have to search for FILE on the path.  */
00230   path = getenv ("PATH");
00231   if (path == NULL)
00232     {
00233       /* There is no `PATH' in the environment.
00234         The default search path is the current directory
00235         followed by the path `confstr' returns for `_CS_PATH'.  */
00236       len = confstr (_CS_PATH, (char *) NULL, 0);
00237       path = (char *) __alloca (1 + len);
00238       path[0] = ':';
00239       (void) confstr (_CS_PATH, path + 1, len);
00240     }
00241 
00242   len = strlen (file) + 1;
00243   pathlen = strlen (path);
00244   name = __alloca (pathlen + len + 1);
00245   /* Copy the file name at the top.  */
00246   name = (char *) memcpy (name + pathlen + 1, file, len);
00247   /* And add the slash.  */
00248   *--name = '/';
00249 
00250   p = path;
00251   do
00252     {
00253       char *startp;
00254 
00255       path = p;
00256       p = __strchrnul (path, ':');
00257 
00258       if (p == path)
00259        /* Two adjacent colons, or a colon at the beginning or the end
00260           of `PATH' means to search the current directory.  */
00261        startp = name + 1;
00262       else
00263        startp = (char *) memcpy (name - (p - path), path, p - path);
00264 
00265       /* Try to execute this name.  If it works, execv will not return.  */
00266       __execve (startp, argv, envp);
00267 
00268       if (errno == ENOEXEC)
00269        script_execute (startp, argv, envp);
00270 
00271       switch (errno)
00272        {
00273        case EACCES:
00274        case ENOENT:
00275        case ESTALE:
00276        case ENOTDIR:
00277          /* Those errors indicate the file is missing or not executable
00278             by us, in which case we want to just try the next path
00279             directory.  */
00280          break;
00281 
00282        default:
00283          /* Some other error means we found an executable file, but
00284             something went wrong executing it; return the error to our
00285             caller.  */
00286          _exit (SPAWN_ERROR);
00287            }
00288     }
00289   while (*p++ != '\0');
00290 
00291   /* Return with an error.  */
00292   _exit (SPAWN_ERROR);
00293 }