OSDN Git Service

4e352ac5bf099be726f1cd211e3438182c0dc1b0
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / spawn.cc
1 /* spawn.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4    2005, 2006, 2007 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <unistd.h>
16 #include <process.h>
17 #include <sys/wait.h>
18 #include <limits.h>
19 #include <wingdi.h>
20 #include <winuser.h>
21 #include <ctype.h>
22 #include "cygerrno.h"
23 #include <sys/cygwin.h>
24 #include "security.h"
25 #include "path.h"
26 #include "fhandler.h"
27 #include "dtable.h"
28 #include "sigproc.h"
29 #include "cygheap.h"
30 #include "child_info.h"
31 #include "shared_info.h"
32 #include "pinfo.h"
33 #include "registry.h"
34 #include "environ.h"
35 #include "cygtls.h"
36 #include "winf.h"
37
38 static suffix_info exe_suffixes[] =
39 {
40   suffix_info ("", 1),
41   suffix_info (".exe", 1),
42   suffix_info (".com"),
43   suffix_info (NULL)
44 };
45
46 static suffix_info dll_suffixes[] =
47 {
48   suffix_info (".dll"),
49   suffix_info ("", 1),
50   suffix_info (".exe", 1),
51   suffix_info (NULL)
52 };
53
54 HANDLE hExeced;
55 child_info_spawn *chExeced;
56
57 /* Add .exe to PROG if not already present and see if that exists.
58    If not, return PROG (converted from posix to win32 rules if necessary).
59    The result is always BUF.
60
61    Returns (possibly NULL) suffix */
62
63 static const char *
64 perhaps_suffix (const char *prog, path_conv& buf, int& err, unsigned opt)
65 {
66   char *ext;
67
68   err = 0;
69   debug_printf ("prog '%s'", prog);
70   buf.check (prog, PC_SYM_FOLLOW | PC_NULLEMPTY,
71              (opt & FE_DLL) ? dll_suffixes : exe_suffixes);
72
73   if (buf.isdir ())
74     {
75       err = EACCES;
76       ext = NULL;
77     }
78   else if (!buf.exists ())
79     {
80       err = ENOENT;
81       ext = NULL;
82     }
83   else if (buf.known_suffix)
84     ext = (char *) buf + (buf.known_suffix - buf.get_win32 ());
85   else
86     ext = strchr (buf, '\0');
87
88   debug_printf ("buf %s, suffix found '%s'", (char *) buf, ext);
89   return ext;
90 }
91
92 /* Find an executable name, possibly by appending known executable
93    suffixes to it.  The win32-translated name is placed in 'buf'.
94    Any found suffix is returned in known_suffix.
95
96    If the file is not found and !null_if_not_found then the win32 version
97    of name is placed in buf and returned.  Otherwise the contents of buf
98    is undefined and NULL is returned.  */
99
100 const char * __stdcall
101 find_exec (const char *name, path_conv& buf, const char *mywinenv,
102            unsigned opt, const char **known_suffix)
103 {
104   const char *suffix = "";
105   debug_printf ("find_exec (%s)", name);
106   const char *retval = buf;
107   char tmp[CYG_MAX_PATH];
108   const char *posix = (opt & FE_NATIVE) ? NULL : name;
109   bool has_slash = strchr (name, '/');
110   int err;
111
112   /* Check to see if file can be opened as is first.
113      Win32 systems always check . first, but PATH may not be set up to
114      do this. */
115   if ((has_slash || opt & FE_CWD)
116       && (suffix = perhaps_suffix (name, buf, err, opt)) != NULL)
117     {
118       if (posix && !has_slash)
119         {
120           tmp[0] = '.';
121           tmp[1] = '/';
122           strcpy (tmp + 2, name);
123           posix = tmp;
124         }
125       goto out;
126     }
127
128   win_env *winpath;
129   const char *path;
130   const char *posix_path;
131
132   posix = (opt & FE_NATIVE) ? NULL : tmp;
133
134   if (strchr (mywinenv, '/'))
135     {
136       /* it's not really an environment variable at all */
137       int n = cygwin_posix_to_win32_path_list_buf_size (mywinenv);
138       char *s = (char *) alloca (n + 1);
139       if (cygwin_posix_to_win32_path_list (mywinenv, s))
140         goto errout;
141       path = s;
142       posix_path = mywinenv - 1;
143     }
144   else if (has_slash || strchr (name, '\\') || isdrive (name)
145       || !(winpath = getwinenv (mywinenv))
146       || !(path = winpath->get_native ()) || *path == '\0')
147     /* Return the error condition if this is an absolute path or if there
148        is no PATH to search. */
149     goto errout;
150   else
151     posix_path = winpath->get_posix () - 1;
152
153   debug_printf ("%s%s", mywinenv, path);
154   /* Iterate over the specified path, looking for the file with and without
155      executable extensions. */
156   do
157     {
158       posix_path++;
159       char *eotmp = strccpy (tmp, &path, ';');
160       /* An empty path or '.' means the current directory, but we've
161          already tried that.  */
162       if (opt & FE_CWD && (tmp[0] == '\0' || (tmp[0] == '.' && tmp[1] == '\0')))
163         continue;
164
165       *eotmp++ = '\\';
166       strcpy (eotmp, name);
167
168       debug_printf ("trying %s", tmp);
169
170       if ((suffix = perhaps_suffix (tmp, buf, err, opt)) != NULL)
171         {
172           if (buf.has_acls () && allow_ntsec && check_file_access (buf, X_OK))
173             continue;
174
175           if (posix == tmp)
176             {
177               eotmp = strccpy (tmp, &posix_path, ':');
178               if (eotmp == tmp)
179                 *eotmp++ = '.';
180               *eotmp++ = '/';
181               strcpy (eotmp, name);
182             }
183           goto out;
184         }
185     }
186   while (*path && *++path && (posix_path = strchr (posix_path, ':')));
187
188  errout:
189   posix = NULL;
190   /* Couldn't find anything in the given path.
191      Take the appropriate action based on null_if_not_found. */
192   if (opt & FE_NNF)
193     retval = NULL;
194   else if (opt & FE_NATIVE)
195     buf.check (name);
196   else
197     retval = name;
198
199  out:
200   if (posix)
201     buf.set_path (posix);
202   debug_printf ("%s = find_exec (%s)", (char *) buf, name);
203   if (known_suffix)
204     *known_suffix = suffix ?: strchr (buf, '\0');
205   if (!retval && err)
206     set_errno (err);
207   return retval;
208 }
209
210 /* Utility for spawn_guts.  */
211
212 static HANDLE
213 handle (int fd, bool writing)
214 {
215   HANDLE h;
216   cygheap_fdget cfd (fd);
217
218   if (cfd < 0)
219     h = INVALID_HANDLE_VALUE;
220   else if (cfd->close_on_exec ())
221     h = INVALID_HANDLE_VALUE;
222   else if (!writing)
223     h = cfd->get_handle ();
224   else
225     h = cfd->get_output_handle ();
226
227   return h;
228 }
229
230 int
231 iscmd (const char *argv0, const char *what)
232 {
233   int n;
234   n = strlen (argv0) - strlen (what);
235   if (n >= 2 && argv0[1] != ':')
236     return 0;
237   return n >= 0 && strcasematch (argv0 + n, what) &&
238          (n == 0 || isdirsep (argv0[n - 1]));
239 }
240
241 struct pthread_cleanup
242 {
243   _sig_func_ptr oldint;
244   _sig_func_ptr oldquit;
245   sigset_t oldmask;
246   pthread_cleanup (): oldint (NULL), oldquit (NULL), oldmask ((sigset_t) -1) {}
247 };
248
249 static void
250 do_cleanup (void *args)
251 {
252 # define cleanup ((pthread_cleanup *) args)
253   if (cleanup->oldmask != (sigset_t) -1)
254     {
255       signal (SIGINT, cleanup->oldint);
256       signal (SIGQUIT, cleanup->oldquit);
257       sigprocmask (SIG_SETMASK, &(cleanup->oldmask), NULL);
258     }
259 # undef cleanup
260 }
261
262
263 int __stdcall
264 spawn_guts (const char * prog_arg, const char *const *argv,
265             const char *const envp[], int mode, int __stdin, int __stdout)
266 {
267   bool rc;
268   pid_t cygpid;
269   int res = -1;
270
271   if (prog_arg == NULL)
272     {
273       syscall_printf ("prog_arg is NULL");
274       set_errno (EINVAL);
275       return -1;
276     }
277
278   syscall_printf ("spawn_guts (%d, %.9500s)", mode, prog_arg);
279
280   if (argv == NULL)
281     {
282       syscall_printf ("argv is NULL");
283       set_errno (EINVAL);
284       return -1;
285     }
286
287   /* FIXME: There is a small race here and FIXME: not thread safe! */
288
289   pthread_cleanup cleanup;
290   if (mode == _P_SYSTEM)
291     {
292       sigset_t child_block;
293       cleanup.oldint = signal (SIGINT, SIG_IGN);
294       cleanup.oldquit = signal (SIGQUIT, SIG_IGN);
295       sigemptyset (&child_block);
296       sigaddset (&child_block, SIGCHLD);
297       sigprocmask (SIG_BLOCK, &child_block, &cleanup.oldmask);
298     }
299   pthread_cleanup_push (do_cleanup, (void *) &cleanup);
300   av newargv;
301   linebuf one_line;
302   child_info_spawn ch;
303   char *envblock = NULL;
304   path_conv real_path;
305   bool reset_sendsig = false;
306
307   const char *runpath;
308   int c_flags;
309   bool wascygexec;
310   cygheap_exec_info *moreinfo;
311
312   bool null_app_name = false;
313   STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
314                     NULL, NULL, NULL};
315   int looped = 0;
316   HANDLE orig_wr_proc_pipe = NULL;
317
318   myfault efault;
319   if (efault.faulted ())
320     {
321       if (get_errno () == ENOMEM)
322         set_errno (E2BIG);
323       else
324         set_errno (EFAULT);
325       res = -1;
326       goto out;
327     }
328
329   child_info_types chtype;
330   if (mode != _P_OVERLAY)
331     chtype = PROC_SPAWN;
332   else
333     chtype = PROC_EXEC;
334
335   moreinfo = (cygheap_exec_info *) ccalloc (HEAP_1_EXEC, 1, sizeof (cygheap_exec_info));
336   moreinfo->old_title = NULL;
337
338   /* CreateProcess takes one long string that is the command line (sigh).
339      We need to quote any argument that has whitespace or embedded "'s.  */
340
341   int ac;
342   for (ac = 0; argv[ac]; ac++)
343     /* nothing */;
344
345   newargv.set (ac, argv);
346
347   int err;
348   const char *ext;
349   if ((ext = perhaps_suffix (prog_arg, real_path, err, FE_NADA)) == NULL)
350     {
351       set_errno (err);
352       res = -1;
353       goto out;
354     }
355
356
357   wascygexec = real_path.iscygexec ();
358   res = newargv.fixup (prog_arg, real_path, ext);
359
360   if (res)
361     goto out;
362
363   if (ac == 3 && argv[1][0] == '/' && argv[1][1] == 'c' &&
364       (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe")))
365     {
366       real_path.check (prog_arg);
367       one_line.add ("\"");
368       if (!real_path.error)
369         one_line.add (real_path);
370       else
371         one_line.add (argv[0]);
372       one_line.add ("\"");
373       one_line.add (" ");
374       one_line.add (argv[1]);
375       one_line.add (" ");
376       one_line.add (argv[2]);
377       strcpy (real_path, argv[0]);
378       null_app_name = true;
379     }
380   else
381     {
382       if (wascygexec)
383         newargv.dup_all ();
384       else if (!one_line.fromargv (newargv, real_path, real_path.iscygexec ()))
385         {
386           res = -1;
387           goto out;
388         }
389
390
391       newargv.all_calloced ();
392       moreinfo->argc = newargv.argc;
393       moreinfo->argv = newargv;
394
395       if (mode != _P_OVERLAY ||
396           !DuplicateHandle (hMainProc, myself.shared_handle (), hMainProc,
397                             &moreinfo->myself_pinfo, 0,
398                             TRUE, DUPLICATE_SAME_ACCESS))
399         moreinfo->myself_pinfo = NULL;
400       else
401         VerifyHandle (moreinfo->myself_pinfo);
402     }
403
404   PROCESS_INFORMATION pi;
405   pi.hProcess = pi.hThread = NULL;
406   pi.dwProcessId = pi.dwThreadId = 0;
407   si.lpReserved = NULL;
408   si.lpDesktop = NULL;
409
410   /* Set up needed handles for stdio */
411   si.dwFlags = STARTF_USESTDHANDLES;
412   si.hStdInput = handle ((__stdin < 0 ? 0 : __stdin), false);
413   si.hStdOutput = handle ((__stdout < 0 ? 1 : __stdout), true);
414   si.hStdError = handle (2, true);
415
416   si.cb = sizeof (si);
417   if (!wincap.pty_needs_alloc_console () && newargv.iscui && myself->ctty == -1)
418     {
419       si.dwFlags |= STARTF_USESHOWWINDOW;
420       si.wShowWindow = SW_HIDE;
421     }
422
423   c_flags = GetPriorityClass (hMainProc);
424   sigproc_printf ("priority class %d", c_flags);
425   c_flags |= CREATE_SEPARATE_WOW_VDM;
426
427   if (mode == _P_DETACH)
428     c_flags |= DETACHED_PROCESS;
429   else
430     set_console_state_for_spawn (real_path.iscygexec ());
431
432   if (mode != _P_OVERLAY)
433     myself->exec_sendsig = NULL;
434   else
435     {
436       /* Reset sendsig so that any process which wants to send a signal
437          to this pid will wait for the new process to become active.
438          Save the old value in case the exec fails.  */
439       if (!myself->exec_sendsig)
440         {
441           myself->exec_sendsig = myself->sendsig;
442           myself->exec_dwProcessId = myself->dwProcessId;
443           myself->sendsig = NULL;
444           reset_sendsig = true;
445         }
446       /* Save a copy of a handle to the current process around the first time we
447          exec so that the pid will not be reused.  Why did I stop cygwin from
448          generating its own pids again? */
449       if (cygheap->pid_handle)
450         /* already done previously */;
451       else if (DuplicateHandle (hMainProc, hMainProc, hMainProc, &cygheap->pid_handle,
452                                 PROCESS_QUERY_INFORMATION, TRUE, 0))
453         ProtectHandleINH (cygheap->pid_handle);
454       else
455         system_printf ("duplicate to pid_handle failed, %E");
456     }
457
458   /* Some file types (currently only sockets) need extra effort in the parent
459      after CreateProcess and before copying the datastructures to the child.
460      So we have to start the child in suspend state, unfortunately, to avoid
461      a race condition. */
462   if (!newargv.win16_exe
463       && (wincap.start_proc_suspended () || mode != _P_OVERLAY
464           || cygheap->fdtab.need_fixup_before ()))
465     c_flags |= CREATE_SUSPENDED;
466
467   runpath = null_app_name ? NULL : (const char *) real_path;
468
469   syscall_printf ("null_app_name %d (%s, %.9500s)", null_app_name, runpath, one_line.buf);
470
471   cygbench ("spawn-guts");
472
473   cygheap->fdtab.set_file_pointers_for_exec ();
474
475   moreinfo->envp = build_env (envp, envblock, moreinfo->envc, real_path.iscygexec ());
476   if (!moreinfo->envp || !envblock)
477     {
478       set_errno (E2BIG);
479       res = -1;
480       goto out;
481     }
482   ch.set (chtype, real_path.iscygexec ());
483   ch.moreinfo = moreinfo;
484   ch.__stdin = __stdin;
485   ch.__stdout = __stdout;
486
487   si.lpReserved2 = (LPBYTE) &ch;
488   si.cbReserved2 = sizeof (ch);
489
490   /* When ruid != euid we create the new process under the current original
491      account and impersonate in child, this way maintaining the different
492      effective vs. real ids.
493      FIXME: If ruid != euid and ruid != saved_uid we currently give
494      up on ruid. The new process will have ruid == euid. */
495 loop:
496   cygheap->user.deimpersonate ();
497
498   if (!cygheap->user.issetuid ()
499       || (cygheap->user.saved_uid == cygheap->user.real_uid
500           && cygheap->user.saved_gid == cygheap->user.real_gid
501           && !cygheap->user.groups.issetgroups ()))
502     {
503       rc = CreateProcess (runpath,      /* image name - with full path */
504                           one_line.buf, /* what was passed to exec */
505                           &sec_none_nih,/* process security attrs */
506                           &sec_none_nih,/* thread security attrs */
507                           TRUE,         /* inherit handles from parent */
508                           c_flags,
509                           envblock,     /* environment */
510                           wincap.is_winnt () || real_path.iscygexec () ?
511                           NULL : cygheap->cwd.win32,
512                           &si,
513                           &pi);
514     }
515   else
516     {
517       /* Give access to myself */
518       if (mode == _P_OVERLAY)
519         myself.set_acl();
520
521       /* allow the child to interact with our window station/desktop */
522       HANDLE hwst, hdsk;
523       SECURITY_INFORMATION dsi = DACL_SECURITY_INFORMATION;
524       DWORD n;
525       char wstname[1024];
526       char dskname[1024];
527
528       hwst = GetProcessWindowStation ();
529       SetUserObjectSecurity (hwst, &dsi, get_null_sd ());
530       GetUserObjectInformation (hwst, UOI_NAME, wstname, 1024, &n);
531       hdsk = GetThreadDesktop (GetCurrentThreadId ());
532       SetUserObjectSecurity (hdsk, &dsi, get_null_sd ());
533       GetUserObjectInformation (hdsk, UOI_NAME, dskname, 1024, &n);
534       strcat (wstname, "\\");
535       strcat (wstname, dskname);
536       si.lpDesktop = wstname;
537
538       rc = CreateProcessAsUser (cygheap->user.primary_token (),
539                        runpath,         /* image name - with full path */
540                        one_line.buf,    /* what was passed to exec */
541                        &sec_none_nih,   /* process security attrs */
542                        &sec_none_nih,   /* thread security attrs */
543                        TRUE,            /* inherit handles from parent */
544                        c_flags,
545                        envblock,        /* environment */
546                        wincap.is_winnt () || real_path.iscygexec () ?
547                        NULL : cygheap->cwd.win32,
548                        &si,
549                        &pi);
550     }
551
552   /* Restore impersonation. In case of _P_OVERLAY this isn't
553      allowed since it would overwrite child data. */
554   if (mode != _P_OVERLAY || !rc)
555     cygheap->user.reimpersonate ();
556
557   /* Set errno now so that debugging messages from it appear before our
558      final debugging message [this is a general rule for debugging
559      messages].  */
560   if (!rc)
561     {
562       __seterrno ();
563       syscall_printf ("CreateProcess failed, %E");
564       /* If this was a failed exec, restore the saved sendsig. */
565       if (reset_sendsig)
566         {
567           myself->sendsig = myself->exec_sendsig;
568           myself->exec_sendsig = NULL;
569         }
570       res = -1;
571       if (moreinfo->myself_pinfo)
572         CloseHandle (moreinfo->myself_pinfo);
573       goto out;
574     }
575
576   if (!(c_flags & CREATE_SUSPENDED))
577     strace.write_childpid (ch, pi.dwProcessId);
578
579   /* Fixup the parent data structures if needed and resume the child's
580      main thread. */
581   if (cygheap->fdtab.need_fixup_before ())
582     cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
583
584   if (mode != _P_OVERLAY)
585     cygpid = cygwin_pid (pi.dwProcessId);
586   else
587     cygpid = myself->pid;
588
589   /* We print the original program name here so the user can see that too.  */
590   syscall_printf ("%d = spawn_guts (%s, %.9500s)",
591                   rc ? cygpid : (unsigned int) -1, prog_arg, one_line.buf);
592
593   /* Name the handle similarly to proc_subproc. */
594   ProtectHandle1 (pi.hProcess, childhProc);
595
596   bool synced;
597   pid_t pid;
598   if (mode == _P_OVERLAY)
599     {
600       chExeced = &ch;   /* FIXME: there's a race here if a user sneaks in CTRL-C */
601       myself->dwProcessId = pi.dwProcessId;
602       strace.execing = 1;
603       myself.hProcess = hExeced = pi.hProcess;
604       strcpy (myself->progname, real_path); // FIXME: race?
605       sigproc_printf ("new process name %s", myself->progname);
606       /* If wr_proc_pipe doesn't exist then this process was not started by a cygwin
607          process.  So, we need to wait around until the process we've just "execed"
608          dies.  Use our own wait facility to wait for our own pid to exit (there
609          is some minor special case code in proc_waiter and friends to accommodate
610          this).
611
612          If wr_proc_pipe exists, then it should be duplicated to the child.
613          If the child has exited already, that's ok.  The parent will pick up
614          on this fact when we exit.  dup_proc_pipe will close our end of the pipe.
615          Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE.  That will make
616          dup_proc_pipe essentially a no-op.  */
617       if (!newargv.win16_exe && myself->wr_proc_pipe)
618         {
619           if (!looped)
620             {
621               myself->sync_proc_pipe ();        /* Make sure that we own wr_proc_pipe
622                                                    just in case we've been previously
623                                                    execed. */
624             }
625           orig_wr_proc_pipe = myself->dup_proc_pipe (pi.hProcess);
626         }
627       pid = myself->pid;
628       if (!ch.iscygwin ())
629         close_all_files ();
630     }
631   else
632     {
633       myself->set_has_pgid_children ();
634       ProtectHandle (pi.hThread);
635       pinfo child (cygpid, PID_IN_USE);
636       if (!child)
637         {
638           syscall_printf ("pinfo failed");
639           if (get_errno () != ENOMEM)
640             set_errno (EAGAIN);
641           res = -1;
642           goto out;
643         }
644       child->dwProcessId = pi.dwProcessId;
645       child.hProcess = pi.hProcess;
646
647       strcpy (child->progname, real_path);
648       /* FIXME: This introduces an unreferenced, open handle into the child.
649          The purpose is to keep the pid shared memory open so that all of
650          the fields filled out by child.remember do not disappear and so there
651          is not a brief period during which the pid is not available.
652          However, we should try to find another way to do this eventually. */
653       DuplicateHandle (hMainProc, child.shared_handle (), pi.hProcess,
654                               NULL, 0, 0, DUPLICATE_SAME_ACCESS);
655       child->start_time = time (NULL); /* Register child's starting time. */
656       child->nice = myself->nice;
657       if (!child.remember (mode == _P_DETACH))
658         {
659           /* FIXME: Child in strange state now */
660           CloseHandle (pi.hProcess);
661           ForceCloseHandle (pi.hThread);
662           res = -1;
663           goto out;
664         }
665       pid = child->pid;
666     }
667
668   /* Start the child running */
669   if (c_flags & CREATE_SUSPENDED)
670     {
671       ResumeThread (pi.hThread);
672       strace.write_childpid (ch, pi.dwProcessId);
673     }
674   ForceCloseHandle (pi.hThread);
675
676   sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
677
678   if ((mode == _P_DETACH || mode == _P_NOWAIT) && !ch.iscygwin ())
679     synced = false;
680   else
681     synced = ch.sync (pi.dwProcessId, pi.hProcess, INFINITE);
682
683   switch (mode)
684     {
685     case _P_OVERLAY:
686       myself.hProcess = pi.hProcess;
687       if (!synced)
688         {
689           if (orig_wr_proc_pipe)
690             {
691               myself->wr_proc_pipe_owner = GetCurrentProcessId ();
692               myself->wr_proc_pipe = orig_wr_proc_pipe;
693             }
694           DWORD res = ch.proc_retry (pi.hProcess);
695           if (!res)
696             {
697               looped++;
698               goto loop;
699             }
700           close_all_files (true);
701         }
702       else
703         {
704           close_all_files (true);
705           if (!myself->wr_proc_pipe
706               && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
707             {
708               extern bool is_toplevel_proc;
709               is_toplevel_proc = true;
710               myself.remember (false);
711               waitpid (myself->pid, &res, 0);
712             }
713         }
714       myself.exit (EXITCODE_NOSET);
715       break;
716     case _P_WAIT:
717     case _P_SYSTEM:
718       if (waitpid (cygpid, &res, 0) != cygpid)
719         res = -1;
720       break;
721     case _P_DETACH:
722       res = 0;  /* Lost all memory of this child. */
723       break;
724     case _P_NOWAIT:
725     case _P_NOWAITO:
726     case _P_VFORK:
727       res = cygpid;
728       break;
729     default:
730       break;
731     }
732
733 out:
734   if (envblock)
735     free (envblock);
736   pthread_cleanup_pop (1);
737   return (int) res;
738 #undef ch
739 }
740
741 extern "C" int
742 cwait (int *result, int pid, int)
743 {
744   return waitpid (pid, result, 0);
745 }
746
747 /*
748 * Helper function for spawn runtime calls.
749 * Doesn't search the path.
750 */
751
752 extern "C" int
753 spawnve (int mode, const char *path, const char *const *argv,
754        const char *const *envp)
755 {
756   int ret;
757 #ifdef NEWVFORK
758   vfork_save *vf = vfork_storage.val ();
759
760   if (vf != NULL && (vf->pid < 0) && mode == _P_OVERLAY)
761     mode = _P_NOWAIT;
762   else
763     vf = NULL;
764 #endif
765
766   syscall_printf ("spawnve (%s, %s, %x)", path, argv[0], envp);
767
768   switch (mode)
769     {
770     case _P_OVERLAY:
771       /* We do not pass _P_SEARCH_PATH here. execve doesn't search PATH.*/
772       /* Just act as an exec if _P_OVERLAY set. */
773       spawn_guts (path, argv, envp, mode);
774       /* Errno should be set by spawn_guts.  */
775       ret = -1;
776       break;
777     case _P_VFORK:
778     case _P_NOWAIT:
779     case _P_NOWAITO:
780     case _P_WAIT:
781     case _P_DETACH:
782     case _P_SYSTEM:
783       ret = spawn_guts (path, argv, envp, mode);
784 #ifdef NEWVFORK
785       if (vf)
786         {
787           if (ret > 0)
788             {
789               debug_printf ("longjmping due to vfork");
790               vf->restore_pid (ret);
791             }
792         }
793 #endif
794       break;
795     default:
796       set_errno (EINVAL);
797       ret = -1;
798       break;
799     }
800   return ret;
801 }
802
803 /*
804 * spawn functions as implemented in the MS runtime library.
805 * Most of these based on (and copied from) newlib/libc/posix/execXX.c
806 */
807
808 extern "C" int
809 spawnl (int mode, const char *path, const char *arg0, ...)
810 {
811   int i;
812   va_list args;
813   const char *argv[256];
814
815   va_start (args, arg0);
816   argv[0] = arg0;
817   i = 1;
818
819   do
820       argv[i] = va_arg (args, const char *);
821   while (argv[i++] != NULL);
822
823   va_end (args);
824
825   return spawnve (mode, path, (char * const  *) argv, cur_environ ());
826 }
827
828 extern "C" int
829 spawnle (int mode, const char *path, const char *arg0, ...)
830 {
831   int i;
832   va_list args;
833   const char * const *envp;
834   const char *argv[256];
835
836   va_start (args, arg0);
837   argv[0] = arg0;
838   i = 1;
839
840   do
841     argv[i] = va_arg (args, const char *);
842   while (argv[i++] != NULL);
843
844   envp = va_arg (args, const char * const *);
845   va_end (args);
846
847   return spawnve (mode, path, (char * const *) argv, (char * const *) envp);
848 }
849
850 extern "C" int
851 spawnlp (int mode, const char *path, const char *arg0, ...)
852 {
853   int i;
854   va_list args;
855   const char *argv[256];
856
857   va_start (args, arg0);
858   argv[0] = arg0;
859   i = 1;
860
861   do
862       argv[i] = va_arg (args, const char *);
863   while (argv[i++] != NULL);
864
865   va_end (args);
866
867   return spawnvpe (mode, path, (char * const *) argv, cur_environ ());
868 }
869
870 extern "C" int
871 spawnlpe (int mode, const char *path, const char *arg0, ...)
872 {
873   int i;
874   va_list args;
875   const char * const *envp;
876   const char *argv[256];
877
878   va_start (args, arg0);
879   argv[0] = arg0;
880   i = 1;
881
882   do
883     argv[i] = va_arg (args, const char *);
884   while (argv[i++] != NULL);
885
886   envp = va_arg (args, const char * const *);
887   va_end (args);
888
889   return spawnvpe (mode, path, (char * const *) argv, envp);
890 }
891
892 extern "C" int
893 spawnv (int mode, const char *path, const char * const *argv)
894 {
895   return spawnve (mode, path, argv, cur_environ ());
896 }
897
898 extern "C" int
899 spawnvp (int mode, const char *path, const char * const *argv)
900 {
901   return spawnvpe (mode, path, argv, cur_environ ());
902 }
903
904 extern "C" int
905 spawnvpe (int mode, const char *file, const char * const *argv,
906                                            const char * const *envp)
907 {
908   path_conv buf;
909   return spawnve (mode, find_exec (file, buf), argv, envp);
910 }
911
912 int
913 av::fixup (const char *prog_arg, path_conv& real_path, const char *ext)
914 {
915   const char *p;
916   bool exeext = strcasematch (ext, ".exe");
917   if (exeext && real_path.iscygexec () || strcasematch (ext, ".bat"))
918     return 0;
919   if (!*ext && ((p = ext - 4) > (char *) real_path)
920       && (strcasematch (p, ".bat") || strcasematch (p, ".cmd")
921           || strcasematch (p, ".btm")))
922     return 0;
923   while (1)
924     {
925       char *pgm = NULL;
926       char *arg1 = NULL;
927       char *ptr, *buf;
928
929       HANDLE h = CreateFile (real_path, GENERIC_READ,
930                                FILE_SHARE_READ | FILE_SHARE_WRITE,
931                                &sec_none_nih, OPEN_EXISTING,
932                                FILE_ATTRIBUTE_NORMAL, 0);
933       if (h == INVALID_HANDLE_VALUE)
934         goto err;
935
936       HANDLE hm = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL);
937       CloseHandle (h);
938       if (!hm)
939         {
940           /* ERROR_FILE_INVALID indicates very likely an empty file. */
941           if (GetLastError () == ERROR_FILE_INVALID)
942             {
943               debug_printf ("zero length file, treat as script.");
944               goto just_shell;
945             }
946           goto err;
947         }
948       buf = (char *) MapViewOfFile(hm, FILE_MAP_READ, 0, 0, 0);
949       CloseHandle (hm);
950       if (!buf)
951         goto err;
952
953       {
954         myfault efault;
955         if (efault.faulted ())
956           {
957             UnmapViewOfFile (buf);
958             real_path.set_cygexec (false);
959             break;
960           }
961         if (buf[0] == 'M' && buf[1] == 'Z')
962           {
963             WORD subsys;
964             unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8);
965             win16_exe = off < sizeof (IMAGE_DOS_HEADER);
966             if (!win16_exe)
967               real_path.set_cygexec (!!hook_or_detect_cygwin (buf, NULL, subsys));
968             else
969               real_path.set_cygexec (false);
970             UnmapViewOfFile (buf);
971             iscui = subsys == IMAGE_SUBSYSTEM_WINDOWS_CUI;
972             break;
973           }
974       }
975
976       debug_printf ("%s is possibly a script", (char *) real_path);
977
978       ptr = buf;
979       if (*ptr++ == '#' && *ptr++ == '!')
980         {
981           ptr += strspn (ptr, " \t");
982           size_t len = strcspn (ptr, "\r\n");
983           if (len)
984             {
985               char *namebuf = (char *) alloca (len + 1);
986               memcpy (namebuf, ptr, len);
987               namebuf[len] = '\0';
988               for (ptr = pgm = namebuf; *ptr; ptr++)
989                 if (!arg1 && (*ptr == ' ' || *ptr == '\t'))
990                   {
991                     /* Null terminate the initial command and step over any additional white
992                        space.  If we've hit the end of the line, exit the loop.  Otherwise,
993                        we've found the first argument. Position the current pointer on the
994                        last known white space. */
995                     *ptr = '\0';
996                     char *newptr = ptr + 1;
997                     newptr += strspn (newptr, " \t");
998                     if (!*newptr)
999                       break;
1000                     arg1 = newptr;
1001                     ptr = newptr - 1;
1002                   }
1003             }
1004         }
1005       UnmapViewOfFile (buf);
1006 just_shell:
1007       if (!pgm)
1008         {
1009           if (strcasematch (ext, ".com"))
1010             break;
1011           pgm = (char *) "/bin/sh";
1012           arg1 = NULL;
1013         }
1014
1015       /* Replace argv[0] with the full path to the script if this is the
1016          first time through the loop. */
1017       replace0_maybe (prog_arg);
1018
1019       /* pointers:
1020        * pgm    interpreter name
1021        * arg1   optional string
1022        */
1023       if (arg1)
1024         unshift (arg1);
1025
1026       /* FIXME: This should not be using FE_NATIVE.  It should be putting
1027          the posix path on the argv list. */
1028       find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext);
1029       unshift (real_path, 1);
1030     }
1031   return 0;
1032
1033 err:
1034   __seterrno ();
1035   return -1;
1036 }