3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
22 #include <sys/cygwin.h>
29 #include "child_info.h"
37 static suffix_info exe_suffixes[] =
40 suffix_info (".exe", 1),
46 /* CV, 2009-11-05: Used to be used when searching for DLLs in calls to
47 dlopen(). However, dlopen() on other platforms never adds a suffix by
48 its own. Therefore we use stat_suffixes now, which only adds a .exe
49 suffix for symmetry. */
50 static suffix_info dll_suffixes[] =
54 suffix_info (".exe", 1),
59 child_info_spawn *chExeced;
61 /* Add .exe to PROG if not already present and see if that exists.
62 If not, return PROG (converted from posix to win32 rules if necessary).
63 The result is always BUF.
65 Returns (possibly NULL) suffix */
68 perhaps_suffix (const char *prog, path_conv& buf, int& err, unsigned opt)
73 debug_printf ("prog '%s'", prog);
74 buf.check (prog, PC_SYM_FOLLOW | PC_NULLEMPTY,
75 (opt & FE_DLL) ? stat_suffixes : exe_suffixes);
82 else if (!buf.exists ())
87 else if (buf.known_suffix)
88 ext = buf.get_win32 () + (buf.known_suffix - buf.get_win32 ());
90 ext = strchr (buf.get_win32 (), '\0');
92 debug_printf ("buf %s, suffix found '%s'", (char *) buf.get_win32 (), ext);
96 /* Find an executable name, possibly by appending known executable
97 suffixes to it. The win32-translated name is placed in 'buf'.
98 Any found suffix is returned in known_suffix.
100 If the file is not found and !null_if_not_found then the win32 version
101 of name is placed in buf and returned. Otherwise the contents of buf
102 is undefined and NULL is returned. */
104 const char * __stdcall
105 find_exec (const char *name, path_conv& buf, const char *mywinenv,
106 unsigned opt, const char **known_suffix)
108 const char *suffix = "";
109 debug_printf ("find_exec (%s)", name);
112 char *tmp = tp.c_get ();
113 const char *posix = (opt & FE_NATIVE) ? NULL : name;
114 bool has_slash = !!strpbrk (name, "/\\");
117 /* Check to see if file can be opened as is first.
118 Win32 systems always check . first, but PATH may not be set up to
120 if ((has_slash || opt & FE_CWD)
121 && (suffix = perhaps_suffix (name, buf, err, opt)) != NULL)
123 if (posix && !has_slash)
127 strcpy (tmp + 2, name);
130 retval = buf.get_win32 ();
136 const char *posix_path;
138 posix = (opt & FE_NATIVE) ? NULL : tmp;
140 if (strchr (mywinenv, '/'))
142 /* it's not really an environment variable at all */
143 int n = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, mywinenv, NULL, 0);
144 char *s = (char *) alloca (n);
145 if (cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, mywinenv, s, n))
148 posix_path = mywinenv - 1;
150 else if (has_slash || strchr (name, '\\') || isdrive (name)
151 || !(winpath = getwinenv (mywinenv))
152 || !(path = winpath->get_native ()) || *path == '\0')
153 /* Return the error condition if this is an absolute path or if there
154 is no PATH to search. */
157 posix_path = winpath->get_posix () - 1;
159 debug_printf ("%s%s", mywinenv, path);
160 /* Iterate over the specified path, looking for the file with and without
161 executable extensions. */
165 char *eotmp = strccpy (tmp, &path, ';');
166 /* An empty path or '.' means the current directory, but we've
167 already tried that. */
168 if (opt & FE_CWD && (tmp[0] == '\0' || (tmp[0] == '.' && tmp[1] == '\0')))
172 strcpy (eotmp, name);
174 debug_printf ("trying %s", tmp);
178 if ((suffix = perhaps_suffix (tmp, buf, err1, opt)) != NULL)
180 if (buf.has_acls () && check_file_access (buf, X_OK, true))
185 eotmp = strccpy (tmp, &posix_path, ':');
189 strcpy (eotmp, name);
191 retval = buf.get_win32 ();
195 while (*path && *++path && (posix_path = strchr (posix_path, ':')));
199 /* Couldn't find anything in the given path.
200 Take the appropriate action based on null_if_not_found. */
203 else if (!(opt & FE_NATIVE))
208 retval = buf.get_win32 ();
213 retval = buf.set_path (posix);
214 debug_printf ("%s = find_exec (%s)", (char *) buf.get_win32 (), name);
216 *known_suffix = suffix ?: strchr (buf.get_win32 (), '\0');
222 /* Utility for spawn_guts. */
225 handle (int fd, bool writing)
228 cygheap_fdget cfd (fd);
231 h = INVALID_HANDLE_VALUE;
232 else if (cfd->close_on_exec ())
233 h = INVALID_HANDLE_VALUE;
235 h = cfd->get_handle ();
237 h = cfd->get_output_handle ();
243 iscmd (const char *argv0, const char *what)
246 n = strlen (argv0) - strlen (what);
247 if (n >= 2 && argv0[1] != ':')
249 return n >= 0 && strcasematch (argv0 + n, what) &&
250 (n == 0 || isdirsep (argv0[n - 1]));
253 struct pthread_cleanup
255 _sig_func_ptr oldint;
256 _sig_func_ptr oldquit;
258 pthread_cleanup (): oldint (NULL), oldquit (NULL), oldmask ((sigset_t) -1) {}
262 do_cleanup (void *args)
264 # define cleanup ((pthread_cleanup *) args)
265 if (cleanup->oldmask != (sigset_t) -1)
267 signal (SIGINT, cleanup->oldint);
268 signal (SIGQUIT, cleanup->oldquit);
269 sigprocmask (SIG_SETMASK, &(cleanup->oldmask), NULL);
276 spawn_guts (const char *prog_arg, const char *const *argv,
277 const char *const envp[], int mode, int __stdin, int __stdout)
283 /* Check if we have been called from exec{lv}p or spawn{lv}p and mask
284 mode to keep only the spawn mode. */
285 bool p_type_exec = !!(mode & _P_PATH_TYPE_EXEC);
286 mode = _P_MODE (mode);
288 if (prog_arg == NULL)
290 syscall_printf ("prog_arg is NULL");
291 set_errno (EFAULT); /* As on Linux. */
296 syscall_printf ("prog_arg is empty");
297 set_errno (ENOENT); /* Per POSIX */
301 syscall_printf ("spawn_guts (%d, %.9500s)", mode, prog_arg);
303 /* FIXME: This is no error condition on Linux. */
306 syscall_printf ("argv is NULL");
311 /* FIXME: There is a small race here and FIXME: not thread safe! */
313 pthread_cleanup cleanup;
314 if (mode == _P_SYSTEM)
316 sigset_t child_block;
317 cleanup.oldint = signal (SIGINT, SIG_IGN);
318 cleanup.oldquit = signal (SIGQUIT, SIG_IGN);
319 sigemptyset (&child_block);
320 sigaddset (&child_block, SIGCHLD);
321 sigprocmask (SIG_BLOCK, &child_block, &cleanup.oldmask);
323 pthread_cleanup_push (do_cleanup, (void *) &cleanup);
327 PWCHAR envblock = NULL;
329 bool reset_sendsig = false;
332 PWCHAR runpath = tp.w_get ();
335 cygheap_exec_info *moreinfo;
337 bool null_app_name = false;
338 STARTUPINFOW si = {};
340 HANDLE orig_wr_proc_pipe = NULL;
343 if (efault.faulted ())
345 if (get_errno () == ENOMEM)
353 child_info_types chtype;
354 if (mode != _P_OVERLAY)
359 moreinfo = (cygheap_exec_info *) ccalloc_abort (HEAP_1_EXEC, 1,
360 sizeof (cygheap_exec_info));
361 moreinfo->old_title = NULL;
363 /* CreateProcess takes one long string that is the command line (sigh).
364 We need to quote any argument that has whitespace or embedded "'s. */
367 for (ac = 0; argv[ac]; ac++)
370 newargv.set (ac, argv);
374 if ((ext = perhaps_suffix (prog_arg, real_path, err, FE_NADA)) == NULL)
382 wascygexec = real_path.iscygexec ();
383 res = newargv.fixup (prog_arg, real_path, ext, p_type_exec);
388 if (!real_path.iscygexec () && cygheap->cwd.get_error ())
390 small_printf ("Error: Current working directory %s.\n"
391 "Can't start native Windows application from here.\n\n",
392 cygheap->cwd.get_error_desc ());
393 set_errno (cygheap->cwd.get_error ());
398 if (ac == 3 && argv[1][0] == '/' && argv[1][1] == 'c' &&
399 (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe")))
401 real_path.check (prog_arg);
403 if (!real_path.error)
404 one_line.add (real_path.get_win32 ());
406 one_line.add (argv[0]);
409 one_line.add (argv[1]);
411 one_line.add (argv[2]);
412 real_path.set_path (argv[0]);
413 null_app_name = true;
419 else if (!one_line.fromargv (newargv, real_path.get_win32 (),
420 real_path.iscygexec ()))
427 newargv.all_calloced ();
428 moreinfo->argc = newargv.argc;
429 moreinfo->argv = newargv;
431 if (mode != _P_OVERLAY ||
432 !DuplicateHandle (GetCurrentProcess (), myself.shared_handle (),
433 GetCurrentProcess (), &moreinfo->myself_pinfo,
434 0, TRUE, DUPLICATE_SAME_ACCESS))
435 moreinfo->myself_pinfo = NULL;
437 VerifyHandle (moreinfo->myself_pinfo);
439 WCHAR wone_line[one_line.ix + 1];
441 sys_mbstowcs (wone_line, one_line.ix + 1, one_line.buf);
443 wone_line[0] = L'\0';
445 PROCESS_INFORMATION pi;
446 pi.hProcess = pi.hThread = NULL;
447 pi.dwProcessId = pi.dwThreadId = 0;
449 /* Set up needed handles for stdio */
450 si.dwFlags = STARTF_USESTDHANDLES;
451 si.hStdInput = handle ((__stdin < 0 ? 0 : __stdin), false);
452 si.hStdOutput = handle ((__stdout < 0 ? 1 : __stdout), true);
453 si.hStdError = handle (2, true);
457 c_flags = GetPriorityClass (GetCurrentProcess ());
458 sigproc_printf ("priority class %d", c_flags);
459 c_flags |= CREATE_SEPARATE_WOW_VDM | CREATE_UNICODE_ENVIRONMENT;
461 if (mode == _P_DETACH)
462 c_flags |= DETACHED_PROCESS;
464 fhandler_console::need_invisible ();
466 if (mode != _P_OVERLAY)
467 myself->exec_sendsig = NULL;
470 /* Reset sendsig so that any process which wants to send a signal
471 to this pid will wait for the new process to become active.
472 Save the old value in case the exec fails. */
473 if (!myself->exec_sendsig)
475 myself->exec_sendsig = myself->sendsig;
476 myself->exec_dwProcessId = myself->dwProcessId;
477 myself->sendsig = NULL;
478 reset_sendsig = true;
480 /* Save a copy of a handle to the current process around the first time we
481 exec so that the pid will not be reused. Why did I stop cygwin from
482 generating its own pids again? */
483 if (cygheap->pid_handle)
484 /* already done previously */;
485 else if (DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
486 GetCurrentProcess (), &cygheap->pid_handle,
487 PROCESS_QUERY_INFORMATION, TRUE, 0))
488 ProtectHandleINH (cygheap->pid_handle);
490 system_printf ("duplicate to pid_handle failed, %E");
493 runpath = null_app_name ? NULL : real_path.get_wide_win32_path (runpath);
495 { /* If the executable path length is < MAX_PATH, make sure the long path
496 win32 prefix is removed from the path to make subsequent native Win32
497 child processes happy which are not long path aware. */
498 USHORT len = real_path.get_nt_native_path ()->Length;
499 if (len < (MAX_PATH + 4) * sizeof (WCHAR)
500 || (runpath[5] != L':' /* UNC path */
501 && len < (MAX_PATH + 6) * sizeof (WCHAR)))
503 PWCHAR r = runpath + 4;
504 if (r[1] != L':') /* UNC path */
506 if (!RtlIsDosDeviceName_U (r))
508 else if (*r == L'\\')
513 syscall_printf ("null_app_name %d (%W, %.9500W)", null_app_name,
516 cygbench ("spawn-guts");
518 if (!real_path.iscygexec())
519 cygheap->fdtab.set_file_pointers_for_exec ();
521 moreinfo->envp = build_env (envp, envblock, moreinfo->envc,
522 real_path.iscygexec ());
523 if (!moreinfo->envp || !envblock)
529 ch.set (chtype, real_path.iscygexec ());
530 ch.moreinfo = moreinfo;
531 ch.__stdin = __stdin;
532 ch.__stdout = __stdout;
534 si.lpReserved2 = (LPBYTE) &ch;
535 si.cbReserved2 = sizeof (ch);
537 /* Depends on ch.set call above.
538 Some file types might need extra effort in the parent after CreateProcess
539 and before copying the datastructures to the child. So we have to start
540 the child in suspend state, unfortunately, to avoid a race condition. */
541 if (!newargv.win16_exe
542 && (!ch.iscygwin () || mode != _P_OVERLAY
543 || cygheap->fdtab.need_fixup_before ()))
544 c_flags |= CREATE_SUSPENDED;
546 /* When ruid != euid we create the new process under the current original
547 account and impersonate in child, this way maintaining the different
548 effective vs. real ids.
549 FIXME: If ruid != euid and ruid != saved_uid we currently give
550 up on ruid. The new process will have ruid == euid. */
552 cygheap->user.deimpersonate ();
556 if (!real_path.iscygexec ())
558 myself->process_state |= PID_NOTCYGWIN;
559 cygheap->cwd.cwd_lock.acquire ();
560 cwd = cygheap->cwd.win32.Buffer;
563 if (!cygheap->user.issetuid ()
564 || (cygheap->user.saved_uid == cygheap->user.real_uid
565 && cygheap->user.saved_gid == cygheap->user.real_gid
566 && !cygheap->user.groups.issetgroups ()
567 && !cygheap->user.setuid_to_restricted))
569 rc = CreateProcessW (runpath, /* image name - with full path */
570 wone_line, /* what was passed to exec */
571 &sec_none_nih, /* process security attrs */
572 &sec_none_nih, /* thread security attrs */
573 TRUE, /* inherit handles from parent */
575 envblock, /* environment */
582 /* Give access to myself */
583 if (mode == _P_OVERLAY)
586 WCHAR wstname[1024] = { L'\0' };
587 HWINSTA hwst_orig = NULL, hwst = NULL;
588 HDESK hdsk_orig = NULL, hdsk = NULL;
589 PSECURITY_ATTRIBUTES sa;
592 hwst_orig = GetProcessWindowStation ();
593 hdsk_orig = GetThreadDesktop (GetCurrentThreadId ());
594 GetUserObjectInformationW (hwst_orig, UOI_NAME, wstname, 1024, &n);
595 /* Prior to Vista it was possible to start a service with the
596 "Interact with desktop" flag. This started the service in the
597 interactive window station of the console. A big security
598 risk, but we don't want to disable this behaviour for older
599 OSes because it's still heavily used by some users. They have
601 if (!cygheap->user.setuid_to_restricted
602 && wcscasecmp (wstname, L"WinSta0") != 0)
606 sa = sec_user ((PSECURITY_ATTRIBUTES) alloca (1024),
607 cygheap->user.sid ());
608 /* We're creating a window station per user, not per logon session.
609 First of all we might not have a valid logon session for
610 the user (logon by create_token), and second, it doesn't
611 make sense in terms of security to create a new window
612 station for every logon of the same user. It just fills up
613 the system with window stations for no good reason. */
614 hwst = CreateWindowStationW (cygheap->user.get_windows_id (sid), 0,
615 GENERIC_READ | GENERIC_WRITE, sa);
617 system_printf ("CreateWindowStation failed, %E");
618 else if (!SetProcessWindowStation (hwst))
619 system_printf ("SetProcessWindowStation failed, %E");
620 else if (!(hdsk = CreateDesktopW (L"Default", NULL, NULL, 0,
622 system_printf ("CreateDesktop failed, %E");
625 wcpcpy (wcpcpy (wstname, sid), L"\\Default");
626 si.lpDesktop = wstname;
627 debug_printf ("Desktop: %W", si.lpDesktop);
631 rc = CreateProcessAsUserW (cygheap->user.primary_token (),
632 runpath, /* image name - with full path */
633 wone_line, /* what was passed to exec */
634 &sec_none_nih, /* process security attrs */
635 &sec_none_nih, /* thread security attrs */
636 TRUE, /* inherit handles from parent */
638 envblock, /* environment */
644 SetProcessWindowStation (hwst_orig);
645 CloseWindowStation (hwst);
649 SetThreadDesktop (hdsk_orig);
654 if (!real_path.iscygexec())
655 cygheap->cwd.cwd_lock.release ();
657 /* Restore impersonation. In case of _P_OVERLAY this isn't
658 allowed since it would overwrite child data. */
659 if (mode != _P_OVERLAY || !rc)
660 cygheap->user.reimpersonate ();
662 /* Set errno now so that debugging messages from it appear before our
663 final debugging message [this is a general rule for debugging
668 syscall_printf ("CreateProcess failed, %E");
669 /* If this was a failed exec, restore the saved sendsig. */
672 myself->sendsig = myself->exec_sendsig;
673 myself->exec_sendsig = NULL;
679 if (!(c_flags & CREATE_SUSPENDED))
680 strace.write_childpid (ch, pi.dwProcessId);
682 /* Fixup the parent data structures if needed and resume the child's
684 if (cygheap->fdtab.need_fixup_before ())
685 cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
687 if (mode != _P_OVERLAY)
688 cygpid = cygwin_pid (pi.dwProcessId);
690 cygpid = myself->pid;
692 /* We print the original program name here so the user can see that too. */
693 syscall_printf ("%d = spawn_guts (%s, %.9500s)",
694 rc ? cygpid : (unsigned int) -1, prog_arg, one_line.buf);
696 /* Name the handle similarly to proc_subproc. */
697 ProtectHandle1 (pi.hProcess, childhProc);
701 if (mode == _P_OVERLAY)
703 chExeced = &ch; /* FIXME: there's a race here if a user sneaks in CTRL-C */
704 myself->dwProcessId = pi.dwProcessId;
706 myself.hProcess = hExeced = pi.hProcess;
707 real_path.get_wide_win32_path (myself->progname); // FIXME: race?
708 sigproc_printf ("new process name %W", myself->progname);
709 /* If wr_proc_pipe doesn't exist then this process was not started by a cygwin
710 process. So, we need to wait around until the process we've just "execed"
711 dies. Use our own wait facility to wait for our own pid to exit (there
712 is some minor special case code in proc_waiter and friends to accommodate
715 If wr_proc_pipe exists, then it should be duplicated to the child.
716 If the child has exited already, that's ok. The parent will pick up
717 on this fact when we exit. dup_proc_pipe will close our end of the pipe.
718 Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE. That will make
719 dup_proc_pipe essentially a no-op. */
720 if (!newargv.win16_exe && myself->wr_proc_pipe)
723 myself->sync_proc_pipe (); /* Make sure that we own wr_proc_pipe
724 just in case we've been previously
726 orig_wr_proc_pipe = myself->dup_proc_pipe (pi.hProcess);
734 myself->set_has_pgid_children ();
735 ProtectHandle (pi.hThread);
737 PID_IN_USE | (real_path.iscygexec () ? 0 : PID_NOTCYGWIN));
740 syscall_printf ("pinfo failed");
741 if (get_errno () != ENOMEM)
746 child->dwProcessId = pi.dwProcessId;
747 child.hProcess = pi.hProcess;
749 real_path.get_wide_win32_path (child->progname);
750 /* FIXME: This introduces an unreferenced, open handle into the child.
751 The purpose is to keep the pid shared memory open so that all of
752 the fields filled out by child.remember do not disappear and so there
753 is not a brief period during which the pid is not available.
754 However, we should try to find another way to do this eventually. */
755 DuplicateHandle (GetCurrentProcess (), child.shared_handle (),
756 pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS);
757 child->start_time = time (NULL); /* Register child's starting time. */
758 child->nice = myself->nice;
759 if (!child.remember (mode == _P_DETACH))
761 /* FIXME: Child in strange state now */
762 CloseHandle (pi.hProcess);
763 ForceCloseHandle (pi.hThread);
770 /* Start the child running */
771 if (c_flags & CREATE_SUSPENDED)
773 ResumeThread (pi.hThread);
774 strace.write_childpid (ch, pi.dwProcessId);
776 ForceCloseHandle (pi.hThread);
778 sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
780 if ((mode == _P_DETACH || mode == _P_NOWAIT) && !ch.iscygwin ())
783 synced = ch.sync (pi.dwProcessId, pi.hProcess, INFINITE);
788 myself.hProcess = pi.hProcess;
791 if (orig_wr_proc_pipe)
793 myself->wr_proc_pipe_owner = GetCurrentProcessId ();
794 myself->wr_proc_pipe = orig_wr_proc_pipe;
796 if (!ch.proc_retry (pi.hProcess))
801 close_all_files (true);
805 close_all_files (true);
806 if (!myself->wr_proc_pipe
807 && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
809 extern bool is_toplevel_proc;
810 is_toplevel_proc = true;
811 myself.remember (false);
812 waitpid (myself->pid, &res, 0);
815 myself.exit (EXITCODE_NOSET);
819 if (waitpid (cygpid, &res, 0) != cygpid)
823 res = 0; /* Lost all memory of this child. */
837 pthread_cleanup_pop (1);
843 cwait (int *result, int pid, int)
845 return waitpid (pid, result, 0);
849 * Helper function for spawn runtime calls.
850 * Doesn't search the path.
854 spawnve (int mode, const char *path, const char *const *argv,
855 const char *const *envp)
857 static char *const empty_env[] = { NULL };
861 vfork_save *vf = vfork_storage.val ();
863 if (vf != NULL && (vf->pid < 0) && mode == _P_OVERLAY)
869 syscall_printf ("spawnve (%s, %s, %x)", path, argv[0], envp);
874 switch (_P_MODE (mode))
877 spawn_guts (path, argv, envp, mode);
878 /* Errno should be set by spawn_guts. */
887 ret = spawn_guts (path, argv, envp, mode);
893 debug_printf ("longjmping due to vfork");
894 vf->restore_pid (ret);
908 * spawn functions as implemented in the MS runtime library.
909 * Most of these based on (and copied from) newlib/libc/posix/execXX.c
913 spawnl (int mode, const char *path, const char *arg0, ...)
917 const char *argv[256];
919 va_start (args, arg0);
924 argv[i] = va_arg (args, const char *);
925 while (argv[i++] != NULL);
929 return spawnve (mode, path, (char * const *) argv, cur_environ ());
933 spawnle (int mode, const char *path, const char *arg0, ...)
937 const char * const *envp;
938 const char *argv[256];
940 va_start (args, arg0);
945 argv[i] = va_arg (args, const char *);
946 while (argv[i++] != NULL);
948 envp = va_arg (args, const char * const *);
951 return spawnve (mode, path, (char * const *) argv, (char * const *) envp);
955 spawnlp (int mode, const char *file, const char *arg0, ...)
959 const char *argv[256];
962 va_start (args, arg0);
967 argv[i] = va_arg (args, const char *);
968 while (argv[i++] != NULL);
972 return spawnve (mode | _P_PATH_TYPE_EXEC, find_exec (file, buf),
973 (char * const *) argv, cur_environ ());
977 spawnlpe (int mode, const char *file, const char *arg0, ...)
981 const char * const *envp;
982 const char *argv[256];
985 va_start (args, arg0);
990 argv[i] = va_arg (args, const char *);
991 while (argv[i++] != NULL);
993 envp = va_arg (args, const char * const *);
996 return spawnve (mode | _P_PATH_TYPE_EXEC, find_exec (file, buf),
997 (char * const *) argv, envp);
1001 spawnv (int mode, const char *path, const char * const *argv)
1003 return spawnve (mode, path, argv, cur_environ ());
1007 spawnvp (int mode, const char *file, const char * const *argv)
1010 return spawnve (mode | _P_PATH_TYPE_EXEC, find_exec (file, buf), argv,
1015 spawnvpe (int mode, const char *file, const char * const *argv,
1016 const char * const *envp)
1019 return spawnve (mode | _P_PATH_TYPE_EXEC, find_exec (file, buf), argv, envp);
1023 av::fixup (const char *prog_arg, path_conv& real_path, const char *ext,
1027 bool exeext = ascii_strcasematch (ext, ".exe");
1028 if ((exeext && real_path.iscygexec ()) || ascii_strcasematch (ext, ".bat"))
1030 if (!*ext && ((p = ext - 4) > real_path.get_win32 ())
1031 && (ascii_strcasematch (p, ".bat") || ascii_strcasematch (p, ".cmd")
1032 || ascii_strcasematch (p, ".btm")))
1039 OBJECT_ATTRIBUTES attr;
1044 status = NtOpenFile (&h, SYNCHRONIZE | GENERIC_READ,
1045 real_path.get_object_attr (attr, sec_none_nih),
1046 &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
1047 FILE_SYNCHRONOUS_IO_NONALERT
1048 | FILE_OPEN_FOR_BACKUP_INTENT
1049 | FILE_NON_DIRECTORY_FILE);
1050 if (!NT_SUCCESS (status))
1052 /* File is not readable? Doesn't mean it's not executable.
1053 Test for executablility and if so, just assume the file is
1054 a cygwin executable and go ahead. */
1055 if (status == STATUS_ACCESS_DENIED && real_path.has_acls ()
1056 && check_file_access (real_path, X_OK, true) == 0)
1058 real_path.set_cygexec (true);
1064 HANDLE hm = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL);
1068 /* ERROR_FILE_INVALID indicates very likely an empty file. */
1069 if (GetLastError () == ERROR_FILE_INVALID)
1071 debug_printf ("zero length file, treat as script.");
1076 buf = (char *) MapViewOfFile(hm, FILE_MAP_READ, 0, 0, 0);
1083 if (efault.faulted ())
1085 UnmapViewOfFile (buf);
1086 real_path.set_cygexec (false);
1089 if (buf[0] == 'M' && buf[1] == 'Z')
1092 unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8);
1093 win16_exe = off < sizeof (IMAGE_DOS_HEADER);
1095 real_path.set_cygexec (!!hook_or_detect_cygwin (buf, NULL, subsys));
1097 real_path.set_cygexec (false);
1098 UnmapViewOfFile (buf);
1103 debug_printf ("%s is possibly a script", real_path.get_win32 ());
1106 if (*ptr++ == '#' && *ptr++ == '!')
1108 ptr += strspn (ptr, " \t");
1109 size_t len = strcspn (ptr, "\r\n");
1112 char *namebuf = (char *) alloca (len + 1);
1113 memcpy (namebuf, ptr, len);
1114 namebuf[len] = '\0';
1115 for (ptr = pgm = namebuf; *ptr; ptr++)
1116 if (!arg1 && (*ptr == ' ' || *ptr == '\t'))
1118 /* Null terminate the initial command and step over any
1119 additional white space. If we've hit the end of the
1120 line, exit the loop. Otherwise, we've found the first
1121 argument. Position the current pointer on the last known
1124 char *newptr = ptr + 1;
1125 newptr += strspn (newptr, " \t");
1133 UnmapViewOfFile (buf);
1139 /* Not called from exec[lv]p. Don't try to treat as script. */
1140 debug_printf ("%s is not a valid executable",
1141 real_path.get_win32 ());
1142 set_errno (ENOEXEC);
1145 if (ascii_strcasematch (ext, ".com"))
1147 pgm = (char *) "/bin/sh";
1151 /* Check if script is executable. Otherwise we start non-executable
1152 scripts successfully, which is incorrect behaviour. */
1153 if (real_path.has_acls ()
1154 && check_file_access (real_path, X_OK, true) < 0)
1155 return -1; /* errno is already set. */
1157 /* Replace argv[0] with the full path to the script if this is the
1158 first time through the loop. */
1159 replace0_maybe (prog_arg);
1162 * pgm interpreter name
1163 * arg1 optional string
1168 /* FIXME: This should not be using FE_NATIVE. It should be putting
1169 the posix path on the argv list. */
1170 find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext);
1171 unshift (real_path.get_win32 (), 1);