Bump to m4 1.4.19
[platform/upstream/m4.git] / lib / spawni.c
1 /* Guts of POSIX spawn interface.  Generic POSIX.1 version.
2    Copyright (C) 2000-2006, 2008-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program 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
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
17
18 #include <config.h>
19
20 /* Specification.  */
21 #include <spawn.h>
22 #include "spawn_int.h"
23
24 #include <alloca.h>
25 #include <errno.h>
26
27 #include <fcntl.h>
28 #ifndef O_LARGEFILE
29 # define O_LARGEFILE 0
30 #endif
31
32 #if _LIBC || HAVE_PATHS_H
33 # include <paths.h>
34 #else
35 # define _PATH_BSHELL BOURNE_SHELL
36 #endif
37
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #if _LIBC
44 # include <not-cancel.h>
45 #else
46 # define close_not_cancel close
47 # define open_not_cancel open
48 #endif
49
50 #if _LIBC
51 # include <local-setxid.h>
52 #else
53 # if !HAVE_SETEUID
54 #  define seteuid(id) setresuid (-1, id, -1)
55 # endif
56 # if !HAVE_SETEGID
57 #  define setegid(id) setresgid (-1, id, -1)
58 # endif
59 # define local_seteuid(id) seteuid (id)
60 # define local_setegid(id) setegid (id)
61 #endif
62
63 #if _LIBC
64 # define alloca __alloca
65 # define execve __execve
66 # define dup2 __dup2
67 # define fork __fork
68 # define getgid __getgid
69 # define getuid __getuid
70 # define sched_setparam __sched_setparam
71 # define sched_setscheduler __sched_setscheduler
72 # define setpgid __setpgid
73 # define sigaction __sigaction
74 # define sigismember __sigismember
75 # define sigprocmask __sigprocmask
76 # define strchrnul __strchrnul
77 # define vfork __vfork
78 #endif
79
80
81 /* The Unix standard contains a long explanation of the way to signal
82    an error after the fork() was successful.  Since no new wait status
83    was wanted there is no way to signal an error using one of the
84    available methods.  The committee chose to signal an error by a
85    normal program exit with the exit code 127.  */
86 #define SPAWN_ERROR     127
87
88
89 #if defined _WIN32 && ! defined __CYGWIN__
90 /* Native Windows API.  */
91
92 /* Get declarations of the native Windows API functions.  */
93 # define WIN32_LEAN_AND_MEAN
94 # include <windows.h>
95
96 # include <stdbool.h>
97 # include <stdio.h>
98
99 # include "filename.h"
100 # include "concat-filename.h"
101 # include "findprog.h"
102 # include "malloca.h"
103 # include "windows-spawn.h"
104
105 /* Don't assume that UNICODE is not defined.  */
106 # undef CreateFile
107 # define CreateFile CreateFileA
108 # undef STARTUPINFO
109 # define STARTUPINFO STARTUPINFOA
110 # undef CreateProcess
111 # define CreateProcess CreateProcessA
112
113 /* Grows inh_handles->count so that it becomes > newfd.
114    Returns 0 upon success.  In case of failure, -1 is returned, with errno set.
115  */
116 static int
117 grow_inheritable_handles (struct inheritable_handles *inh_handles, int newfd)
118 {
119   if (inh_handles->allocated <= newfd)
120     {
121       size_t new_allocated = 2 * inh_handles->allocated + 1;
122       if (new_allocated <= newfd)
123         new_allocated = newfd + 1;
124       HANDLE *new_handles_array =
125         (HANDLE *)
126         realloc (inh_handles->handles, new_allocated * sizeof (HANDLE));
127       if (new_handles_array == NULL)
128         {
129           errno = ENOMEM;
130           return -1;
131         }
132       unsigned char *new_flags_array =
133         (unsigned char *)
134         realloc (inh_handles->flags, new_allocated * sizeof (unsigned char));
135       if (new_flags_array == NULL)
136         {
137           free (new_handles_array);
138           errno = ENOMEM;
139           return -1;
140         }
141       inh_handles->allocated = new_allocated;
142       inh_handles->handles = new_handles_array;
143       inh_handles->flags = new_flags_array;
144     }
145
146   HANDLE *handles = inh_handles->handles;
147
148   for (; inh_handles->count <= newfd; inh_handles->count++)
149     handles[inh_handles->count] = INVALID_HANDLE_VALUE;
150
151   return 0;
152 }
153
154 /* Reduces inh_handles->count to the minimum needed.  */
155 static void
156 shrink_inheritable_handles (struct inheritable_handles *inh_handles)
157 {
158   HANDLE *handles = inh_handles->handles;
159
160   while (inh_handles->count > 3
161          && handles[inh_handles->count - 1] == INVALID_HANDLE_VALUE)
162     inh_handles->count--;
163 }
164
165 /* Closes all handles in inh_handles.  */
166 static void
167 close_inheritable_handles (struct inheritable_handles *inh_handles)
168 {
169   HANDLE *handles = inh_handles->handles;
170   size_t handles_count = inh_handles->count;
171   unsigned int fd;
172
173   for (fd = 0; fd < handles_count; fd++)
174     {
175       HANDLE handle = handles[fd];
176
177       if (handle != INVALID_HANDLE_VALUE)
178         CloseHandle (handle);
179     }
180 }
181
182 /* Tests whether a memory region, starting at P and N bytes long, contains only
183    zeroes.  */
184 static bool
185 memiszero (const void *p, size_t n)
186 {
187   const char *cp = p;
188   for (; n > 0; cp++, n--)
189     if (*cp != 0)
190       return 0;
191   return 1;
192 }
193
194 /* Tests whether *S contains no signals.  */
195 static bool
196 sigisempty (const sigset_t *s)
197 {
198   return memiszero (s, sizeof (sigset_t));
199 }
200
201 /* Opens a HANDLE to a file.
202    Upon failure, returns INVALID_HANDLE_VALUE with errno set.  */
203 static HANDLE
204 open_handle (const char *name, int flags, mode_t mode)
205 {
206   /* To ease portability.  Like in open.c.  */
207   if (strcmp (name, "/dev/null") == 0)
208     name = "NUL";
209
210   /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>
211      specifies: "More than two leading <slash> characters shall be treated as
212      a single <slash> character."  */
213   if (ISSLASH (name[0]) && ISSLASH (name[1]) && ISSLASH (name[2]))
214     {
215       name += 2;
216       while (ISSLASH (name[1]))
217         name++;
218     }
219
220   size_t len = strlen (name);
221   size_t drive_prefix_len = (HAS_DEVICE (name) ? 2 : 0);
222
223   /* Remove trailing slashes (except the very first one, at position
224      drive_prefix_len), but remember their presence.  */
225   size_t rlen;
226   bool check_dir = false;
227
228   rlen = len;
229   while (rlen > drive_prefix_len && ISSLASH (name[rlen-1]))
230     {
231       check_dir = true;
232       if (rlen == drive_prefix_len + 1)
233         break;
234       rlen--;
235     }
236
237   /* Handle '' and 'C:'.  */
238   if (!check_dir && rlen == drive_prefix_len)
239     {
240       errno = ENOENT;
241       return INVALID_HANDLE_VALUE;
242     }
243
244   /* Handle '\\'.  */
245   if (rlen == 1 && ISSLASH (name[0]) && len >= 2)
246     {
247       errno = ENOENT;
248       return INVALID_HANDLE_VALUE;
249     }
250
251   const char *rname;
252   char *malloca_rname;
253   if (rlen == len)
254     {
255       rname = name;
256       malloca_rname = NULL;
257     }
258   else
259     {
260       malloca_rname = malloca (rlen + 1);
261       if (malloca_rname == NULL)
262         {
263           errno = ENOMEM;
264           return INVALID_HANDLE_VALUE;
265         }
266       memcpy (malloca_rname, name, rlen);
267       malloca_rname[rlen] = '\0';
268       rname = malloca_rname;
269     }
270
271   /* For the meaning of the flags, see
272      <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/open-wopen>  */
273   /* Open a handle to the file.
274      CreateFile
275      <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea>
276      <https://docs.microsoft.com/en-us/windows/desktop/FileIO/creating-and-opening-files>  */
277   HANDLE handle =
278     CreateFile (rname,
279                 ((flags & (O_WRONLY | O_RDWR)) != 0
280                  ? GENERIC_READ | GENERIC_WRITE
281                  : GENERIC_READ),
282                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
283                 NULL,
284                 ((flags & O_CREAT) != 0
285                  ? ((flags & O_EXCL) != 0
286                     ? CREATE_NEW
287                     : ((flags & O_TRUNC) != 0 ? CREATE_ALWAYS : OPEN_ALWAYS))
288                  : ((flags & O_TRUNC) != 0
289                     ? TRUNCATE_EXISTING
290                     : OPEN_EXISTING)),
291                 /* FILE_FLAG_BACKUP_SEMANTICS is useful for opening directories,
292                    which is out-of-scope here.  */
293                 /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only
294                    in case as different) makes sense only when applied to *all*
295                    filesystem operations.  */
296                 /* FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS */
297                 FILE_ATTRIBUTE_NORMAL
298                 | ((flags & O_TEMPORARY) != 0 ? FILE_FLAG_DELETE_ON_CLOSE : 0)
299                 | ((flags & O_SEQUENTIAL ) != 0 ? FILE_FLAG_SEQUENTIAL_SCAN : 0)
300                 | ((flags & O_RANDOM) != 0 ? FILE_FLAG_RANDOM_ACCESS : 0),
301                 NULL);
302   if (handle == INVALID_HANDLE_VALUE)
303     switch (GetLastError ())
304       {
305       /* Some of these errors probably cannot happen with the specific flags
306          that we pass to CreateFile.  But who knows...  */
307       case ERROR_FILE_NOT_FOUND: /* The last component of rname does not exist.  */
308       case ERROR_PATH_NOT_FOUND: /* Some directory component in rname does not exist.  */
309       case ERROR_BAD_PATHNAME:   /* rname is such as '\\server'.  */
310       case ERROR_BAD_NETPATH:    /* rname is such as '\\nonexistentserver\share'.  */
311       case ERROR_BAD_NET_NAME:   /* rname is such as '\\server\nonexistentshare'.  */
312       case ERROR_INVALID_NAME:   /* rname contains wildcards, misplaced colon, etc.  */
313       case ERROR_DIRECTORY:
314         errno = ENOENT;
315         break;
316
317       case ERROR_ACCESS_DENIED:  /* rname is such as 'C:\System Volume Information\foo'.  */
318       case ERROR_SHARING_VIOLATION: /* rname is such as 'C:\pagefile.sys'.  */
319                                     /* XXX map to EACCES or EPERM? */
320         errno = EACCES;
321         break;
322
323       case ERROR_OUTOFMEMORY:
324         errno = ENOMEM;
325         break;
326
327       case ERROR_WRITE_PROTECT:
328         errno = EROFS;
329         break;
330
331       case ERROR_WRITE_FAULT:
332       case ERROR_READ_FAULT:
333       case ERROR_GEN_FAILURE:
334         errno = EIO;
335         break;
336
337       case ERROR_BUFFER_OVERFLOW:
338       case ERROR_FILENAME_EXCED_RANGE:
339         errno = ENAMETOOLONG;
340         break;
341
342       case ERROR_DELETE_PENDING: /* XXX map to EACCES or EPERM? */
343         errno = EPERM;
344         break;
345
346       default:
347         errno = EINVAL;
348         break;
349       }
350
351   if (malloca_rname != NULL)
352     {
353       int saved_errno = errno;
354       freea (malloca_rname);
355       errno = saved_errno;
356     }
357   return handle;
358 }
359
360 /* Executes an 'open' action.
361    Returns 0 upon success.  In case of failure, -1 is returned, with errno set.
362  */
363 static int
364 do_open (struct inheritable_handles *inh_handles, int newfd,
365          const char *filename, const char *directory,
366          int flags, mode_t mode, HANDLE curr_process)
367 {
368   if (!(newfd >= 0 && newfd < _getmaxstdio ()))
369     {
370       errno = EBADF;
371       return -1;
372     }
373   if (grow_inheritable_handles (inh_handles, newfd) < 0)
374     return -1;
375   if (inh_handles->handles[newfd] != INVALID_HANDLE_VALUE
376       && !CloseHandle (inh_handles->handles[newfd]))
377     {
378       errno = EIO;
379       return -1;
380     }
381   if (filename == NULL)
382     {
383       errno = EINVAL;
384       return -1;
385     }
386   char *filename_to_free = NULL;
387   if (directory != NULL && IS_RELATIVE_FILE_NAME (filename))
388     {
389       char *real_filename = concatenated_filename (directory, filename, NULL);
390       if (real_filename == NULL)
391         {
392           errno = ENOMEM;
393           return -1;
394         }
395       filename = real_filename;
396       filename_to_free = real_filename;
397     }
398   HANDLE handle = open_handle (filename, flags, mode);
399   if (handle == INVALID_HANDLE_VALUE)
400     {
401       free (filename_to_free);
402       return -1;
403     }
404   free (filename_to_free);
405   /* Duplicate the handle, so that it becomes inheritable.  */
406   if (!DuplicateHandle (curr_process, handle,
407                         curr_process, &inh_handles->handles[newfd],
408                         0, TRUE,
409                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
410     {
411       errno = EBADF; /* arbitrary */
412       return -1;
413     }
414   inh_handles->flags[newfd] = ((flags & O_APPEND) != 0 ? 32 : 0);
415   return 0;
416 }
417
418 /* Executes a 'dup2' action.
419    Returns 0 upon success.  In case of failure, -1 is returned, with errno set.
420  */
421 static int
422 do_dup2 (struct inheritable_handles *inh_handles, int oldfd, int newfd,
423          HANDLE curr_process)
424 {
425   if (!(oldfd >= 0 && oldfd < inh_handles->count
426         && inh_handles->handles[oldfd] != INVALID_HANDLE_VALUE))
427     {
428       errno = EBADF;
429       return -1;
430     }
431   if (!(newfd >= 0 && newfd < _getmaxstdio ()))
432     {
433       errno = EBADF;
434       return -1;
435     }
436   if (newfd != oldfd)
437     {
438       if (grow_inheritable_handles (inh_handles, newfd) < 0)
439         return -1;
440       if (inh_handles->handles[newfd] != INVALID_HANDLE_VALUE
441           && !CloseHandle (inh_handles->handles[newfd]))
442         {
443           errno = EIO;
444           return -1;
445         }
446       /* Duplicate the handle, so that it a forthcoming do_close action on oldfd
447          has no effect on newfd.  */
448       if (!DuplicateHandle (curr_process, inh_handles->handles[oldfd],
449                             curr_process, &inh_handles->handles[newfd],
450                             0, TRUE, DUPLICATE_SAME_ACCESS))
451         {
452           errno = EBADF; /* arbitrary */
453           return -1;
454         }
455       inh_handles->flags[newfd] = 0;
456     }
457   return 0;
458 }
459
460 /* Executes a 'close' action.
461    Returns 0 upon success.  In case of failure, -1 is returned, with errno set.
462  */
463 static int
464 do_close (struct inheritable_handles *inh_handles, int fd)
465 {
466   if (!(fd >= 0 && fd < inh_handles->count
467         && inh_handles->handles[fd] != INVALID_HANDLE_VALUE))
468     {
469       errno = EBADF;
470       return -1;
471     }
472   if (!CloseHandle (inh_handles->handles[fd]))
473     {
474       errno = EIO;
475       return -1;
476     }
477   inh_handles->handles[fd] = INVALID_HANDLE_VALUE;
478   return 0;
479 }
480
481 int
482 __spawni (pid_t *pid, const char *prog_filename,
483           const posix_spawn_file_actions_t *file_actions,
484           const posix_spawnattr_t *attrp, const char *const prog_argv[],
485           const char *const envp[], int use_path)
486 {
487   /* Validate the arguments.  */
488   if (prog_filename == NULL
489       || (attrp != NULL
490           && ((attrp->_flags & ~POSIX_SPAWN_SETPGROUP) != 0
491               || attrp->_pgrp != 0
492               || ! sigisempty (&attrp->_sd)
493               || ! sigisempty (&attrp->_ss)
494               || attrp->_sp.sched_priority != 0
495               || attrp->_policy != 0)))
496     return EINVAL;
497
498   /* Process group handling:
499      Native Windows does not have the concept of process group, but it has the
500      concept of a console attached to a process.
501      So, we interpret the three cases as follows:
502        - Flag POSIX_SPAWN_SETPGROUP not set: Means, the child process is in the
503          same process group as the parent process.  We interpret this as a
504          request to reuse the same console.
505        - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp == 0: Means the child
506          process starts a process group of its own.  See
507          <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
508          <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgrp.html>
509          We interpret this as a request to detach from the current console.
510        - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp != 0: Means the child
511          process joins another, existing process group.  See
512          <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
513          <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html>
514          We don't support this case; it produces error EINVAL above.  */
515   /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags>  */
516   DWORD process_creation_flags =
517     (attrp != NULL && (attrp->_flags & POSIX_SPAWN_SETPGROUP) != 0 ? DETACHED_PROCESS : 0);
518
519   char *argv_mem_to_free;
520   const char **argv = prepare_spawn (prog_argv, &argv_mem_to_free);
521   if (argv == NULL)
522     return errno; /* errno is set here */
523   argv++;
524
525   /* Compose the command.  */
526   char *command = compose_command (argv);
527   if (command == NULL)
528     {
529       free (argv_mem_to_free);
530       return ENOMEM;
531     }
532
533   /* Copy *ENVP into a contiguous block of memory.  */
534   char *envblock;
535   if (envp == NULL)
536     envblock = NULL;
537   else
538     {
539       envblock = compose_envblock (envp);
540       if (envblock == NULL)
541         {
542           free (command);
543           free (argv_mem_to_free);
544           return ENOMEM;
545         }
546     }
547
548   /* Set up the array of handles to inherit.
549      Duplicate each handle, so that a spawn_do_close action (below) has no
550      effect on the file descriptors of the current process.  Alternatively,
551      we could store, for each handle, a bit that tells whether it is shared
552      with the current process.  But this is simpler.  */
553   struct inheritable_handles inh_handles;
554   if (init_inheritable_handles (&inh_handles, true) < 0)
555     goto failed_1;
556
557   /* Directory in which to execute the new process.  */
558   const char *directory = NULL;
559
560   /* Execute the file_actions, modifying the inh_handles instead of the
561      file descriptors of the current process.  */
562   if (file_actions != NULL)
563     {
564       HANDLE curr_process = GetCurrentProcess ();
565       int cnt;
566
567       for (cnt = 0; cnt < file_actions->_used; ++cnt)
568         {
569           struct __spawn_action *action = &file_actions->_actions[cnt];
570
571           switch (action->tag)
572             {
573             case spawn_do_close:
574               {
575                 int fd = action->action.close_action.fd;
576                 if (do_close (&inh_handles, fd) < 0)
577                   goto failed_2;
578               }
579               break;
580
581             case spawn_do_open:
582               {
583                 int newfd = action->action.open_action.fd;
584                 const char *filename = action->action.open_action.path;
585                 int flags = action->action.open_action.oflag;
586                 mode_t mode = action->action.open_action.mode;
587                 if (do_open (&inh_handles, newfd, filename, directory,
588                              flags, mode, curr_process)
589                     < 0)
590                   goto failed_2;
591               }
592               break;
593
594             case spawn_do_dup2:
595               {
596                 int oldfd = action->action.dup2_action.fd;
597                 int newfd = action->action.dup2_action.newfd;
598                 if (do_dup2 (&inh_handles, oldfd, newfd, curr_process) < 0)
599                   goto failed_2;
600               }
601               break;
602
603             case spawn_do_chdir:
604               {
605                 char *newdir = action->action.chdir_action.path;
606                 if (directory != NULL && IS_RELATIVE_FILE_NAME (newdir))
607                   {
608                     newdir = concatenated_filename (directory, newdir, NULL);
609                     if (newdir == NULL)
610                       {
611                         errno = ENOMEM;
612                         goto failed_2;
613                       }
614                   }
615                 directory = newdir;
616               }
617               break;
618
619             case spawn_do_fchdir:
620               /* Not supported in this implementation.  */
621               errno = EINVAL;
622               goto failed_2;
623             }
624         }
625     }
626
627   /* Reduce inh_handles.count to the minimum needed.  */
628   shrink_inheritable_handles (&inh_handles);
629
630   /* CreateProcess
631      <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa>  */
632   /* STARTUPINFO
633      <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa>  */
634   STARTUPINFO sinfo;
635   sinfo.cb = sizeof (STARTUPINFO);
636   sinfo.lpReserved = NULL;
637   sinfo.lpDesktop = NULL;
638   sinfo.lpTitle = NULL;
639   if (compose_handles_block (&inh_handles, &sinfo) < 0)
640     goto failed_2;
641
642   /* Perform the PATH search now, considering the final DIRECTORY.  */
643   char *resolved_prog_filename_to_free = NULL;
644   {
645     const char *resolved_prog_filename =
646       find_in_given_path (prog_filename, use_path ? getenv ("PATH") : "",
647                           directory, false);
648     if (resolved_prog_filename == NULL)
649       goto failed_3;
650     if (resolved_prog_filename != prog_filename)
651       resolved_prog_filename_to_free = (char *) resolved_prog_filename;
652     prog_filename = resolved_prog_filename;
653   }
654
655   PROCESS_INFORMATION pinfo;
656   if (!CreateProcess (prog_filename, command, NULL, NULL, TRUE,
657                       process_creation_flags, envblock, directory, &sinfo,
658                       &pinfo))
659     {
660       DWORD error = GetLastError ();
661
662       free (resolved_prog_filename_to_free);
663       free (sinfo.lpReserved2);
664       close_inheritable_handles (&inh_handles);
665       free_inheritable_handles (&inh_handles);
666       free (envblock);
667       free (command);
668       free (argv_mem_to_free);
669
670       return convert_CreateProcess_error (error);
671     }
672
673   if (pinfo.hThread)
674     CloseHandle (pinfo.hThread);
675
676   free (resolved_prog_filename_to_free);
677   free (sinfo.lpReserved2);
678   close_inheritable_handles (&inh_handles);
679   free_inheritable_handles (&inh_handles);
680   free (envblock);
681   free (command);
682   free (argv_mem_to_free);
683
684   if (pid != NULL)
685     *pid = (intptr_t) pinfo.hProcess;
686   return 0;
687
688  failed_3:
689   {
690     int saved_errno = errno;
691     free (sinfo.lpReserved2);
692     close_inheritable_handles (&inh_handles);
693     free_inheritable_handles (&inh_handles);
694     free (envblock);
695     free (command);
696     free (argv_mem_to_free);
697     return saved_errno;
698   }
699
700  failed_2:
701   {
702     int saved_errno = errno;
703     close_inheritable_handles (&inh_handles);
704     free_inheritable_handles (&inh_handles);
705     free (envblock);
706     free (command);
707     free (argv_mem_to_free);
708     return saved_errno;
709   }
710
711  failed_1:
712   free (envblock);
713   free (command);
714   free (argv_mem_to_free);
715   return errno;
716 }
717
718 #else
719
720
721 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
722    Before running the process perform the actions described in FILE-ACTIONS. */
723 int
724 __spawni (pid_t *pid, const char *file,
725           const posix_spawn_file_actions_t *file_actions,
726           const posix_spawnattr_t *attrp, const char *const argv[],
727           const char *const envp[], int use_path)
728 {
729   pid_t new_pid;
730   char *path, *p, *name;
731   size_t len;
732   size_t pathlen;
733
734   /* Do this once.  */
735   short int flags = attrp == NULL ? 0 : attrp->_flags;
736
737   /* Avoid gcc warning
738        "variable 'flags' might be clobbered by 'longjmp' or 'vfork'"  */
739   (void) &flags;
740
741   /* Generate the new process.  */
742 #if HAVE_VFORK
743   if ((flags & POSIX_SPAWN_USEVFORK) != 0
744       /* If no major work is done, allow using vfork.  Note that we
745          might perform the path searching.  But this would be done by
746          a call to execvp(), too, and such a call must be OK according
747          to POSIX.  */
748       || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
749                     | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
750                     | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
751           && file_actions == NULL))
752     new_pid = vfork ();
753   else
754 #endif
755     new_pid = fork ();
756
757   if (new_pid != 0)
758     {
759       if (new_pid < 0)
760         return errno;
761
762       /* The call was successful.  Store the PID if necessary.  */
763       if (pid != NULL)
764         *pid = new_pid;
765
766       return 0;
767     }
768
769   /* Set signal mask.  */
770   if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
771       && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
772     _exit (SPAWN_ERROR);
773
774   /* Set signal default action.  */
775   if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
776     {
777       /* We have to iterate over all signals.  This could possibly be
778          done better but it requires system specific solutions since
779          the sigset_t data type can be very different on different
780          architectures.  */
781       int sig;
782       struct sigaction sa;
783
784       memset (&sa, '\0', sizeof (sa));
785       sa.sa_handler = SIG_DFL;
786
787       for (sig = 1; sig <= NSIG; ++sig)
788         if (sigismember (&attrp->_sd, sig) != 0
789             && sigaction (sig, &sa, NULL) != 0)
790           _exit (SPAWN_ERROR);
791
792     }
793
794 #if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
795   /* Set the scheduling algorithm and parameters.  */
796   if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
797       == POSIX_SPAWN_SETSCHEDPARAM)
798     {
799       if (sched_setparam (0, &attrp->_sp) == -1)
800         _exit (SPAWN_ERROR);
801     }
802   else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
803     {
804       if (sched_setscheduler (0, attrp->_policy,
805                               (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
806                               ? &attrp->_sp : NULL) == -1)
807         _exit (SPAWN_ERROR);
808     }
809 #endif
810
811   /* Set the process group ID.  */
812   if ((flags & POSIX_SPAWN_SETPGROUP) != 0
813       && setpgid (0, attrp->_pgrp) != 0)
814     _exit (SPAWN_ERROR);
815
816   /* Set the effective user and group IDs.  */
817   if ((flags & POSIX_SPAWN_RESETIDS) != 0
818       && (local_seteuid (getuid ()) != 0
819           || local_setegid (getgid ()) != 0))
820     _exit (SPAWN_ERROR);
821
822   /* Execute the file actions.  */
823   if (file_actions != NULL)
824     {
825       int cnt;
826
827       for (cnt = 0; cnt < file_actions->_used; ++cnt)
828         {
829           struct __spawn_action *action = &file_actions->_actions[cnt];
830
831           switch (action->tag)
832             {
833             case spawn_do_close:
834               if (close_not_cancel (action->action.close_action.fd) != 0)
835                 /* Signal the error.  */
836                 _exit (SPAWN_ERROR);
837               break;
838
839             case spawn_do_open:
840               {
841                 int new_fd = open_not_cancel (action->action.open_action.path,
842                                               action->action.open_action.oflag
843                                               | O_LARGEFILE,
844                                               action->action.open_action.mode);
845
846                 if (new_fd == -1)
847                   /* The 'open' call failed.  */
848                   _exit (SPAWN_ERROR);
849
850                 /* Make sure the desired file descriptor is used.  */
851                 if (new_fd != action->action.open_action.fd)
852                   {
853                     if (dup2 (new_fd, action->action.open_action.fd)
854                         != action->action.open_action.fd)
855                       /* The 'dup2' call failed.  */
856                       _exit (SPAWN_ERROR);
857
858                     if (close_not_cancel (new_fd) != 0)
859                       /* The 'close' call failed.  */
860                       _exit (SPAWN_ERROR);
861                   }
862               }
863               break;
864
865             case spawn_do_dup2:
866               if (dup2 (action->action.dup2_action.fd,
867                         action->action.dup2_action.newfd)
868                   != action->action.dup2_action.newfd)
869                 /* The 'dup2' call failed.  */
870                 _exit (SPAWN_ERROR);
871               break;
872
873             case spawn_do_chdir:
874               if (chdir (action->action.chdir_action.path) < 0)
875                 /* The 'chdir' call failed.  */
876                 _exit (SPAWN_ERROR);
877               break;
878
879             case spawn_do_fchdir:
880               if (fchdir (action->action.fchdir_action.fd) < 0)
881                 /* The 'fchdir' call failed.  */
882                 _exit (SPAWN_ERROR);
883               break;
884             }
885         }
886     }
887
888   if (! use_path || strchr (file, '/') != NULL)
889     {
890       /* The FILE parameter is actually a path.  */
891       execve (file, (char * const *) argv, (char * const *) envp);
892
893       /* Oh, oh.  'execve' returns.  This is bad.  */
894       _exit (SPAWN_ERROR);
895     }
896
897   /* We have to search for FILE on the path.  */
898   path = getenv ("PATH");
899   if (path == NULL)
900     {
901 #if HAVE_CONFSTR
902       /* There is no 'PATH' in the environment.
903          The default search path is the current directory
904          followed by the path 'confstr' returns for '_CS_PATH'.  */
905       len = confstr (_CS_PATH, (char *) NULL, 0);
906       path = (char *) alloca (1 + len);
907       path[0] = ':';
908       (void) confstr (_CS_PATH, path + 1, len);
909 #else
910       /* Pretend that the PATH contains only the current directory.  */
911       path = "";
912 #endif
913     }
914
915   len = strlen (file) + 1;
916   pathlen = strlen (path);
917   name = alloca (pathlen + len + 1);
918   /* Copy the file name at the top.  */
919   name = (char *) memcpy (name + pathlen + 1, file, len);
920   /* And add the slash.  */
921   *--name = '/';
922
923   p = path;
924   do
925     {
926       char *startp;
927
928       path = p;
929       p = strchrnul (path, ':');
930
931       if (p == path)
932         /* Two adjacent colons, or a colon at the beginning or the end
933            of 'PATH' means to search the current directory.  */
934         startp = name + 1;
935       else
936         startp = (char *) memcpy (name - (p - path), path, p - path);
937
938       /* Try to execute this name.  If it works, execv will not return.  */
939       execve (startp, (char * const *) argv, (char * const *) envp);
940
941       switch (errno)
942         {
943         case EACCES:
944         case ENOENT:
945         case ESTALE:
946         case ENOTDIR:
947           /* Those errors indicate the file is missing or not executable
948              by us, in which case we want to just try the next path
949              directory.  */
950           break;
951
952         default:
953           /* Some other error means we found an executable file, but
954              something went wrong executing it; return the error to our
955              caller.  */
956           _exit (SPAWN_ERROR);
957         }
958     }
959   while (*p++ != '\0');
960
961   /* Return with an error.  */
962   _exit (SPAWN_ERROR);
963 }
964
965 #endif