This source file includes following definitions.
- grow_inheritable_handles
- shrink_inheritable_handles
- close_inheritable_handles
- memiszero
- sigisempty
- open_handle
- do_open
- do_dup2
- do_close
- __spawni
- __spawni
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 #include <config.h>
  19 
  20 
  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 
  82 
  83 
  84 
  85 
  86 #define SPAWN_ERROR     127
  87 
  88 
  89 #if defined _WIN32 && ! defined __CYGWIN__
  90 
  91 
  92 
  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 
 106 # undef CreateFile
 107 # define CreateFile CreateFileA
 108 # undef STARTUPINFO
 109 # define STARTUPINFO STARTUPINFOA
 110 # undef CreateProcess
 111 # define CreateProcess CreateProcessA
 112 
 113 
 114 
 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 
 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 
 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 
 183 
 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 
 195 static bool
 196 sigisempty (const sigset_t *s)
     
 197 {
 198   return memiszero (s, sizeof (sigset_t));
 199 }
 200 
 201 
 202 
 203 static HANDLE
 204 open_handle (const char *name, int flags, mode_t mode)
     
 205 {
 206   
 207   if (strcmp (name, "/dev/null") == 0)
 208     name = "NUL";
 209 
 210   
 211 
 212 
 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   
 224 
 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   
 238   if (!check_dir && rlen == drive_prefix_len)
 239     {
 240       errno = ENOENT;
 241       return INVALID_HANDLE_VALUE;
 242     }
 243 
 244   
 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   
 272 
 273   
 274 
 275 
 276 
 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                 
 292 
 293                 
 294 
 295 
 296                 
 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       
 306 
 307       case ERROR_FILE_NOT_FOUND: 
 308       case ERROR_PATH_NOT_FOUND: 
 309       case ERROR_BAD_PATHNAME:   
 310       case ERROR_BAD_NETPATH:    
 311       case ERROR_BAD_NET_NAME:   
 312       case ERROR_INVALID_NAME:   
 313       case ERROR_DIRECTORY:
 314         errno = ENOENT;
 315         break;
 316 
 317       case ERROR_ACCESS_DENIED:  
 318       case ERROR_SHARING_VIOLATION: 
 319                                     
 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: 
 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 
 361 
 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   
 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; 
 412       return -1;
 413     }
 414   inh_handles->flags[newfd] = ((flags & O_APPEND) != 0 ? 32 : 0);
 415   return 0;
 416 }
 417 
 418 
 419 
 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       
 447 
 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; 
 453           return -1;
 454         }
 455       inh_handles->flags[newfd] = 0;
 456     }
 457   return 0;
 458 }
 459 
 460 
 461 
 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   
 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   
 499 
 500 
 501 
 502 
 503 
 504 
 505 
 506 
 507 
 508 
 509 
 510 
 511 
 512 
 513 
 514 
 515   
 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; 
 523   argv++;
 524 
 525   
 526   char *command = compose_command (argv);
 527   if (command == NULL)
 528     {
 529       free (argv_mem_to_free);
 530       return ENOMEM;
 531     }
 532 
 533   
 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   
 549 
 550 
 551 
 552 
 553   struct inheritable_handles inh_handles;
 554   if (init_inheritable_handles (&inh_handles, true) < 0)
 555     goto failed_1;
 556 
 557   
 558   const char *directory = NULL;
 559 
 560   
 561 
 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               
 621               errno = EINVAL;
 622               goto failed_2;
 623             }
 624         }
 625     }
 626 
 627   
 628   shrink_inheritable_handles (&inh_handles);
 629 
 630   
 631 
 632   
 633 
 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   
 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 
 722 
 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   
 735   short int flags = attrp == NULL ? 0 : attrp->_flags;
 736 
 737   
 738 
 739   (void) &flags;
 740 
 741   
 742 #if HAVE_VFORK
 743   if ((flags & POSIX_SPAWN_USEVFORK) != 0
 744       
 745 
 746 
 747 
 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       
 763       if (pid != NULL)
 764         *pid = new_pid;
 765 
 766       return 0;
 767     }
 768 
 769   
 770   if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
 771       && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
 772     _exit (SPAWN_ERROR);
 773 
 774   
 775   if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
 776     {
 777       
 778 
 779 
 780 
 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   
 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   
 812   if ((flags & POSIX_SPAWN_SETPGROUP) != 0
 813       && setpgid (0, attrp->_pgrp) != 0)
 814     _exit (SPAWN_ERROR);
 815 
 816   
 817   if ((flags & POSIX_SPAWN_RESETIDS) != 0
 818       && (local_seteuid (getuid ()) != 0
 819           || local_setegid (getgid ()) != 0))
 820     _exit (SPAWN_ERROR);
 821 
 822   
 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                 
 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                   
 848                   _exit (SPAWN_ERROR);
 849 
 850                 
 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                       
 856                       _exit (SPAWN_ERROR);
 857 
 858                     if (close_not_cancel (new_fd) != 0)
 859                       
 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                 
 870                 _exit (SPAWN_ERROR);
 871               break;
 872 
 873             case spawn_do_chdir:
 874               if (chdir (action->action.chdir_action.path) < 0)
 875                 
 876                 _exit (SPAWN_ERROR);
 877               break;
 878 
 879             case spawn_do_fchdir:
 880               if (fchdir (action->action.fchdir_action.fd) < 0)
 881                 
 882                 _exit (SPAWN_ERROR);
 883               break;
 884             }
 885         }
 886     }
 887 
 888   if (! use_path || strchr (file, '/') != NULL)
 889     {
 890       
 891       execve (file, (char * const *) argv, (char * const *) envp);
 892 
 893       
 894       _exit (SPAWN_ERROR);
 895     }
 896 
 897   
 898   path = getenv ("PATH");
 899   if (path == NULL)
 900     {
 901 #if HAVE_CONFSTR
 902       
 903 
 904 
 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       
 911       path = "";
 912 #endif
 913     }
 914 
 915   len = strlen (file) + 1;
 916   pathlen = strlen (path);
 917   name = alloca (pathlen + len + 1);
 918   
 919   name = (char *) memcpy (name + pathlen + 1, file, len);
 920   
 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         
 933 
 934         startp = name + 1;
 935       else
 936         startp = (char *) memcpy (name - (p - path), path, p - path);
 937 
 938       
 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           
 948 
 949 
 950           break;
 951 
 952         default:
 953           
 954 
 955 
 956           _exit (SPAWN_ERROR);
 957         }
 958     }
 959   while (*p++ != '\0');
 960 
 961   
 962   _exit (SPAWN_ERROR);
 963 }
 964 
 965 #endif