diff options
author | Christopher Faylor <me@cgf.cx> | 2005-07-17 00:51:03 +0000 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2005-07-17 00:51:03 +0000 |
commit | e8454a340033a287a9245e049a6f23eb68ec7f95 (patch) | |
tree | e235728e012c817a8bc813232961e972d49f4ac1 /winsup/cygwin/spawn.cc | |
parent | cd929277d69996a60f29d17bb4d612063926a5f7 (diff) | |
download | cygnal-e8454a340033a287a9245e049a6f23eb68ec7f95.tar.gz cygnal-e8454a340033a287a9245e049a6f23eb68ec7f95.tar.bz2 cygnal-e8454a340033a287a9245e049a6f23eb68ec7f95.zip |
* child_info.h (child_info::sync): Pass pid and HANDLE rather than using pinfo.
(child_info::child_info): Accept an argument controlling whether to create
proc_subproc.
(child_info_spawn::child_info_spawn): Ditto.
* sigproc.cc (child_info::child_info): Ditto.
(child_info_spawn::child_info_spawn): Ditto.
(child_info::sync): Use passed in pid and HANDLE.
* fork.cc (fork_parent): Reflect additional arguments required for
child_info::sync.
* hookapi.cc (hook_or_detect_cygwin): Rename. Change so that NULL 'fn'
argument just returns "true", indicating that program uses cygwin1.dll.
* spawn.cc (av::win16_exe): New element.
* spawn.cc (av::iscygwin): New element.
(av::fixup): New function.
(spawn_guts): Protect against SEGV. Use fixup function to detect when it is
safe to wait for a spawned (as opposed to an execed) program. Reflect changes
in child_info::sync arguments.
* external.cc (cygwin_internal): Reflect function renaming to
hook_or_detect_cygwin.
* cygheap.cc (cygheap_fixup_in_child): Close handle after debug fixup has been
done to prevent false positives in handle collision.
* exceptions.cc (try_to_debug): Notify debugger if already being debugged.
Diffstat (limited to 'winsup/cygwin/spawn.cc')
-rw-r--r-- | winsup/cygwin/spawn.cc | 223 |
1 files changed, 120 insertions, 103 deletions
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index cf6d3e4fe..8261a45da 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -32,7 +32,7 @@ details. */ #include "pinfo.h" #include "registry.h" #include "environ.h" -#include "cygthread.h" +#include "cygtls.h" #define LINE_BUF_CHUNK (CYG_MAX_PATH * 2) @@ -264,7 +264,9 @@ class av public: int error; int argc; - av (int ac, const char * const *av) : calloced (0), error (false), argc (ac) + bool win16_exe; + bool iscygwin; + av (int ac, const char * const *av) : calloced (0), error (false), argc (ac), win16_exe (false), iscygwin (true) { argv = (char **) cmalloc (HEAP_1_ARGV, (argc + 5) * sizeof (char *)); memcpy (argv, av, (argc + 1) * sizeof (char *)); @@ -303,6 +305,7 @@ class av if (!(argv[i] = cstrdup1 (argv[i]))) error = errno; } + int fixup (child_info_types, const char *, path_conv&, const char *); }; int @@ -360,8 +363,6 @@ spawn_guts (const char * prog_arg, const char *const *argv, bool rc; pid_t cygpid; - MALLOC_CHECK; - if (prog_arg == NULL) { syscall_printf ("prog_arg is NULL"); @@ -400,9 +401,12 @@ spawn_guts (const char * prog_arg, const char *const *argv, for (ac = 0; argv[ac]; ac++) /* nothing */; + myfault efault; + if (efault.faulted (EFAULT)) + return -1; // FIXME: Could be very leaky + av newargv (ac, argv); - bool win16_exe = false; int null_app_name = 0; if (ac == 3 && argv[1][0] == '/' && argv[1][1] == 'c' && (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe"))) @@ -431,100 +435,10 @@ spawn_guts (const char * prog_arg, const char *const *argv, } MALLOC_CHECK; - - /* If the file name ends in either .exe, .com, .bat, or .cmd we assume - that it is NOT a script file */ - while (*ext == '\0' || (wincap.detect_win16_exe () && strcasematch (ext, ".exe"))) - { - HANDLE hnd = CreateFile (real_path, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_none_nih, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, 0); - if (hnd == INVALID_HANDLE_VALUE) - { - __seterrno (); - return -1; - } - - DWORD done; - - char buf[2 * CYG_MAX_PATH]; - buf[0] = buf[1] = buf[2] = buf[sizeof (buf) - 1] = '\0'; - if (!ReadFile (hnd, buf, sizeof (buf) - 1, &done, 0)) - { - CloseHandle (hnd); - __seterrno (); - return -1; - } - - CloseHandle (hnd); - - if (buf[0] == 'M' && buf[1] == 'Z') - { - unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8); - win16_exe = off < sizeof (IMAGE_DOS_HEADER); - break; - } - - debug_printf ("%s is a script", (char *) real_path); - - if (real_path.has_acls () && allow_ntsec - && check_file_access (real_path, X_OK)) - { - debug_printf ("... but not executable"); - break; - } - - char *pgm, *arg1; - - if (buf[0] != '#' || buf[1] != '!') - { - pgm = (char *) "/bin/sh"; - arg1 = NULL; - } - else - { - char *ptr; - pgm = buf + 2; - pgm += strspn (pgm, " \t"); - for (ptr = pgm, arg1 = NULL; - *ptr && *ptr != '\r' && *ptr != '\n'; - ptr++) - if (!arg1 && (*ptr == ' ' || *ptr == '\t')) - { - /* Null terminate the initial command and step over - any additional white space. If we've hit the - end of the line, exit the loop. Otherwise, we've - found the first argument. Position the current - pointer on the last known white space. */ - *ptr = '\0'; - char *newptr = ptr + 1; - newptr += strspn (newptr, " \t"); - if (!*newptr || *newptr == '\r' || *newptr == '\n') - break; - arg1 = newptr; - ptr = newptr - 1; - } - - *ptr = '\0'; - } - - /* Replace argv[0] with the full path to the script if this is the - first time through the loop. */ - newargv.replace0_maybe (prog_arg); - - /* pointers: - * pgm interpreter name - * arg1 optional string - */ - if (arg1) - newargv.unshift (arg1); - - /* FIXME: This should not be using FE_NATIVE. It should be putting - the posix path on the argv list. */ - find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext); - newargv.unshift (real_path, 1); - } + int res; + res = newargv.fixup (chtype, prog_arg, real_path, ext); + if (res) + return res; if (real_path.iscygexec ()) newargv.dup_all (); @@ -672,7 +586,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, cygheap->user.deimpersonate (); moreinfo->envp = build_env (envp, envblock, moreinfo->envc, real_path.iscygexec ()); - child_info_spawn ciresrv (chtype); + child_info_spawn ciresrv (chtype, newargv.iscygwin); ciresrv.moreinfo = moreinfo; si.lpReserved2 = (LPBYTE) &ciresrv; @@ -763,7 +677,6 @@ spawn_guts (const char * prog_arg, const char *const *argv, /* FIXME: There is a small race here */ - int res; pthread_cleanup cleanup; if (mode == _P_SYSTEM) { @@ -794,6 +707,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, ProtectHandle1 (pi.hProcess, childhProc); bool synced; + pid_t pid; if (mode == _P_OVERLAY) { myself->dwProcessId = dwExeced = pi.dwProcessId; @@ -813,7 +727,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, on this fact when we exit. dup_proc_pipe will close our end of the pipe. Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE. That will make dup_proc_pipe essentially a no-op. */ - if (!win16_exe && myself->wr_proc_pipe) + if (!newargv.win16_exe && myself->wr_proc_pipe) { myself->sync_proc_pipe (); /* Make sure that we own wr_proc_pipe just in case we've been previously @@ -821,6 +735,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, myself.zap_cwd (); myself->dup_proc_pipe (pi.hProcess); } + pid = myself->pid; } else { @@ -856,6 +771,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, res = -1; goto out; } + pid = child->pid; } /* Start the child running */ @@ -865,7 +781,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, sigproc_printf ("spawned windows pid %d", pi.dwProcessId); - synced = ciresrv.sync (myself, INFINITE); + synced = ciresrv.sync (pid, pi.hProcess, INFINITE); switch (mode) { @@ -1075,3 +991,104 @@ spawnvpe (int mode, const char *file, const char * const *argv, path_conv buf; return spawnve (mode, find_exec (file, buf), argv, envp); } + +int +av::fixup (child_info_types chtype, const char *prog_arg, path_conv& real_path, const char *ext) +{ + /* If the file name ends in either .exe, .com, .bat, or .cmd we assume + that it is NOT a script file */ + while (*ext == '\0' || chtype == PROC_SPAWN || (wincap.detect_win16_exe () && strcasematch (ext, ".exe"))) + { + HANDLE h = CreateFile (real_path, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0); + if (h == INVALID_HANDLE_VALUE) + goto err; + + HANDLE hm = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL); + CloseHandle (h); + if (!hm) + goto err; + char *buf = (char *) MapViewOfFile(hm, FILE_MAP_READ, 0, 0, 0); + CloseHandle (hm); + if (!buf) + goto err; + + if (buf[0] == 'M' && buf[1] == 'Z') + { + unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8); + win16_exe = off < sizeof (IMAGE_DOS_HEADER); + if (!win16_exe) + iscygwin = hook_or_detect_cygwin (buf, NULL); + UnmapViewOfFile (buf); + break; + } + + debug_printf ("%s is a script", (char *) real_path); + + if (real_path.has_acls () && allow_ntsec + && check_file_access (real_path, X_OK)) + { + debug_printf ("... but not executable"); + break; + } + + char *pgm = NULL; + char *arg1 = NULL; + char *ptr = buf; + if (*ptr++ == '#' && *ptr++ == '!') + { + ptr += strspn (ptr, " \t"); + size_t len = strcspn (ptr, "\r\n"); + if (len) + { + char *namebuf = (char *) alloca (len + 1); + memcpy (namebuf, ptr, len); + namebuf[len] = '\0'; + for (ptr = pgm = namebuf; *ptr; ptr++) + if (!arg1 && (*ptr == ' ' || *ptr == '\t')) + { + /* Null terminate the initial command and step over any additional white + space. If we've hit the end of the line, exit the loop. Otherwise, + we've found the first argument. Position the current pointer on the + last known white space. */ + *ptr = '\0'; + char *newptr = ptr + 1; + newptr += strspn (newptr, " \t"); + if (!*newptr) + break; + arg1 = newptr; + ptr = newptr - 1; + } + } + } + UnmapViewOfFile (buf); + if (!pgm) + { + pgm = (char *) "/bin/sh"; + arg1 = NULL; + } + + /* Replace argv[0] with the full path to the script if this is the + first time through the loop. */ + replace0_maybe (prog_arg); + + /* pointers: + * pgm interpreter name + * arg1 optional string + */ + if (arg1) + unshift (arg1); + + /* FIXME: This should not be using FE_NATIVE. It should be putting + the posix path on the argv list. */ + find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext); + unshift (real_path, 1); + } + return 0; + +err: + __seterrno (); + return -1; +} |