root/maint/gnulib/lib/spawni.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. grow_inheritable_handles
  2. shrink_inheritable_handles
  3. close_inheritable_handles
  4. memiszero
  5. sigisempty
  6. open_handle
  7. do_open
  8. do_dup2
  9. do_close
  10. __spawni
  11. __spawni

   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 file is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU Lesser General Public License as
   7    published by the Free Software Foundation; either version 2.1 of the
   8    License, or (at your option) any later version.
   9 
  10    This file 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 Lesser General Public License for more details.
  14 
  15    You should have received a copy of the GNU Lesser 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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

/* [previous][next][first][last][top][bottom][index][help] */