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