📄 spawn.cc
字号:
one_line.add ("\"", 1); /* Handle embedded special characters " and \. A " is always preceded by a \. A \ is not special unless it precedes a ". If it does, then all preceding \'s must be doubled to avoid having the Windows command line parser interpret the \ as quoting the ". This rule applies to a string of \'s before the end of the string, since cygwin/windows uses a " to delimit the argument. */ for (; (p = strpbrk (a, "\"\\")); a = ++p) { one_line.add (a, p - a); /* Find length of string of backslashes */ int n = strspn (p, "\\"); if (!n) one_line.add ("\\\"", 2); /* No backslashes, so it must be a ". The " has to be protected with a backslash. */ else { one_line.add (p, n); /* Add the run of backslashes */ /* Need to double up all of the preceding backslashes if they precede a quote or EOS. */ if (!p[n] || p[n] == '"') one_line.add (p, n); p += n - 1; /* Point to last backslash */ } } if (*a) one_line.add (a); one_line.add ("\"", 1); } MALLOC_CHECK; one_line.add (" ", 1); MALLOC_CHECK; } MALLOC_CHECK; if (one_line.ix) one_line.buf[one_line.ix - 1] = '\0'; else one_line.add ("", 1); MALLOC_CHECK; } char *envblock; newargv.all_calloced (); if (newargv.error) { set_errno (newargv.error); return -1; } ciresrv.moreinfo->argc = newargv.argc; ciresrv.moreinfo->argv = newargv; ciresrv.hexec_proc = hexec_proc; if (mode != _P_OVERLAY || !DuplicateHandle (hMainProc, myself.shared_handle (), hMainProc, &ciresrv.moreinfo->myself_pinfo, 0, TRUE, DUPLICATE_SAME_ACCESS)) ciresrv.moreinfo->myself_pinfo = NULL; skip_arg_parsing: PROCESS_INFORMATION pi = {NULL, 0, 0, 0}; si.lpReserved = NULL; si.lpDesktop = NULL; si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = handle (0, 0); /* Get input handle */ si.hStdOutput = handle (1, 1); /* Get output handle */ si.hStdError = handle (2, 1); /* Get output handle */ si.cb = sizeof (si); int flags = CREATE_DEFAULT_ERROR_MODE | GetPriorityClass (hMainProc); if (mode == _P_DETACH || !set_console_state_for_spawn ()) flags |= DETACHED_PROCESS; if (mode != _P_OVERLAY) flags |= CREATE_SUSPENDED; /* Some file types (currently only sockets) need extra effort in the parent after CreateProcess and before copying the datastructures to the child. So we have to start the child in suspend state, unfortunately, to avoid a race condition. */ if (cygheap->fdtab.need_fixup_before ()) flags |= CREATE_SUSPENDED; const char *runpath = null_app_name ? NULL : (const char *) real_path; syscall_printf ("null_app_name %d (%s, %.132s)", null_app_name, runpath, one_line.buf); void *newheap; /* Preallocated buffer for `sec_user' call */ char sa_buf[1024]; cygbench ("spawn-guts"); cygheap->fdtab.set_file_pointers_for_exec (); if (!cygheap->user.issetuid ()) { PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf); ciresrv.moreinfo->envp = build_env (envp, envblock, ciresrv.moreinfo->envc, real_path.iscygexec ()); newheap = cygheap_setup_for_child (&ciresrv, cygheap->fdtab.need_fixup_before ()); rc = CreateProcess (runpath, /* image name - with full path */ one_line.buf, /* what was passed to exec */ sec_attribs, /* process security attrs */ sec_attribs, /* thread security attrs */ TRUE, /* inherit handles from parent */ flags, envblock, /* environment */ 0, /* use current drive/directory */ &si, &pi); } else { PSID sid = cygheap->user.sid (); /* Set security attributes with sid */ PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf, sid); RevertToSelf (); /* Load users registry hive. */ load_registry_hive (sid); /* allow the child to interact with our window station/desktop */ HANDLE hwst, hdsk; SECURITY_INFORMATION dsi = DACL_SECURITY_INFORMATION; DWORD n; char wstname[1024]; char dskname[1024]; ciresrv.moreinfo->uid = ILLEGAL_UID; hwst = GetProcessWindowStation (); SetUserObjectSecurity (hwst, &dsi, get_null_sd ()); GetUserObjectInformation (hwst, UOI_NAME, wstname, 1024, &n); hdsk = GetThreadDesktop (GetCurrentThreadId ()); SetUserObjectSecurity (hdsk, &dsi, get_null_sd ()); GetUserObjectInformation (hdsk, UOI_NAME, dskname, 1024, &n); strcat (wstname, "\\"); strcat (wstname, dskname); si.lpDesktop = wstname; ciresrv.moreinfo->envp = build_env (envp, envblock, ciresrv.moreinfo->envc, real_path.iscygexec ()); newheap = cygheap_setup_for_child (&ciresrv, cygheap->fdtab.need_fixup_before ()); rc = CreateProcessAsUser (cygheap->user.token, runpath, /* image name - with full path */ one_line.buf, /* what was passed to exec */ sec_attribs, /* process security attrs */ sec_attribs, /* thread security attrs */ TRUE, /* inherit handles from parent */ flags, envblock, /* environment */ 0, /* use current drive/directory */ &si, &pi); /* Restore impersonation. In case of _P_OVERLAY this isn't allowed since it would overwrite child data. */ if (mode != _P_OVERLAY) ImpersonateLoggedOnUser (cygheap->user.token); } MALLOC_CHECK; if (envblock) free (envblock); MALLOC_CHECK; /* Set errno now so that debugging messages from it appear before our final debugging message [this is a general rule for debugging messages]. */ if (!rc) { __seterrno (); syscall_printf ("CreateProcess failed, %E"); if (subproc_ready) ForceCloseHandle (subproc_ready); cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0); return -1; } /* Fixup the parent datastructure if needed and resume the child's main thread. */ if (!cygheap->fdtab.need_fixup_before ()) cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0); else { cygheap->fdtab.fixup_before_exec (pi.dwProcessId); cygheap_setup_for_child_cleanup (newheap, &ciresrv, 1); if (mode == _P_OVERLAY) { ResumeThread (pi.hThread); cygthread::terminate (); } } if (mode != _P_OVERLAY) cygpid = cygwin_pid (pi.dwProcessId); else cygpid = myself->pid; /* We print the original program name here so the user can see that too. */ syscall_printf ("%d = spawn_guts (%s, %.132s)", rc ? cygpid : (unsigned int) -1, prog_arg, one_line.buf); /* Name the handle similarly to proc_subproc. */ ProtectHandle1 (pi.hProcess, childhProc); if (mode == _P_OVERLAY) { /* These are both duplicated in the child code. We do this here, primarily for strace. */ strace.execing = 1; hExeced = pi.hProcess; dwExeced = pi.dwProcessId; strcpy (myself->progname, real_path); close_all_files (); } else { myself->set_has_pgid_children (); ProtectHandle (pi.hThread); pinfo child (cygpid, 1); if (!child) { set_errno (EAGAIN); syscall_printf ("-1 = spawnve (), process table full"); return -1; } child->dwProcessId = pi.dwProcessId; child->hProcess = pi.hProcess; child.remember (); strcpy (child->progname, real_path); /* FIXME: This introduces an unreferenced, open handle into the child. The purpose is to keep the pid shared memory open so that all of the fields filled out by child.remember do not disappear and so there is not a brief period during which the pid is not available. However, we should try to find another way to do this eventually. */ (void) DuplicateHandle (hMainProc, child.shared_handle (), pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS); /* Start the child running */ ResumeThread (pi.hThread); } ForceCloseHandle (pi.hThread); sigproc_printf ("spawned windows pid %d", pi.dwProcessId); DWORD res; BOOL exited; res = 0; exited = FALSE; MALLOC_CHECK; if (mode == _P_OVERLAY) { int nwait = 3; HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, subproc_ready}; for (int i = 0; i < 100; i++) { switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, INFINITE)) { case WAIT_OBJECT_0: sigproc_printf ("subprocess exited"); DWORD exitcode; if (!GetExitCodeProcess (pi.hProcess, &exitcode)) exitcode = 1; res |= exitcode; exited = TRUE; break; case WAIT_OBJECT_0 + 1: sigproc_printf ("signal arrived"); reset_signal_arrived (); continue; case WAIT_OBJECT_0 + 2: if (myself->ppid_handle) res |= EXIT_REPARENTING; if (!my_parent_is_alive ()) { nwait = 2; sigproc_terminate (); continue; } break; case WAIT_FAILED: system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E", nwait, myself->pid, myself->dwProcessId); system_printf ("waitbuf[0] %p %d", waitbuf[0], WaitForSingleObject (waitbuf[0], 0)); system_printf ("waitbuf[1] %p = %d", waitbuf[1], WaitForSingleObject (waitbuf[1], 0)); system_printf ("waitbuf[w] %p = %d", waitbuf[2], WaitForSingleObject (waitbuf[2], 0)); set_errno (ECHILD); try_to_debug (); return -1; } break; } ForceCloseHandle (subproc_ready); sigproc_printf ("res = %x", res); if (res & EXIT_REPARENTING) { /* Try to reparent child process. * Make handles to child available to parent process and exit with * EXIT_REPARENTING status. Wait() syscall in parent will then wait * for newly created child. */ HANDLE oldh = myself->hProcess; HANDLE h = myself->ppid_handle; sigproc_printf ("parent handle %p", h); int rc = DuplicateHandle (hMainProc, pi.hProcess, h, &myself->hProcess, 0, FALSE, DUPLICATE_SAME_ACCESS); sigproc_printf ("%d = DuplicateHandle, oldh %p, newh %p", rc, oldh, myself->hProcess); if (!rc && my_parent_is_alive ()) { system_printf ("Reparent failed, parent handle %p, %E", h); system_printf ("my dwProcessId %d, myself->dwProcessId %d", GetCurrentProcessId (), myself->dwProcessId); system_printf ("old hProcess %p, hProcess %p", oldh, myself->hProcess); } } } MALLOC_CHECK; switch (mode) { case _P_OVERLAY: ForceCloseHandle1 (pi.hProcess, childhProc); proc_terminate (); myself->exit (res, 1); break; case _P_WAIT: waitpid (cygpid, (int *) &res, 0); break; case _P_DETACH: res = 0; /* Lose all memory of this child. */ break; case _P_NOWAIT: case _P_NOWAITO: case _P_VFORK: res = cygpid; break; default: break; } return (int) res;}extern "C" intcwait (int *result, int pid, int){ return waitpid (pid, result, 0);}/* * Helper function for spawn runtime calls. * Doesn't search the path. */extern "C" intspawnve (int mode, const char *path, const char *const *argv, const char *const *envp){ int ret; vfork_save *vf = vfork_storage.val (); if (vf != NULL && (vf->pid < 0) && mode == _P_OVERLAY) mode = _P_NOWAIT; else vf = NULL; syscall_printf ("spawnve (%s, %s, %x)", path, argv[0], envp); switch (mode) { case _P_OVERLAY: /* We do not pass _P_SEARCH_PATH here. execve doesn't search PATH.*/ /* Just act as an exec if _P_OVERLAY set. */ spawn_guts (path, argv, envp, mode); /* Errno should be set by spawn_guts. */ ret = -1; break; case _P_VFORK: case _P_NOWAIT: case _P_NOWAITO: case _P_WAIT: case _P_DETACH: subproc_init (); ret = spawn_guts (path, argv, envp, mode); if (vf) { debug_printf ("longjmping due to vfork"); if (ret < 0) vf->restore_exit (ret); else vf->restore_pid (ret); } break; default: set_errno (EINVAL); ret = -1; break; } return ret;}/* * spawn functions as implemented in the MS runtime library. * Most of these based on (and copied from) newlib/libc/posix/execXX.c */extern "C" intspawnl (int mode, const char *path, const char *arg0, ...){ int i; va_list args; const char *argv[256]; va_start (args, arg0); argv[0] = arg0; i = 1; do argv[i] = va_arg (args, const char *); while (argv[i++] != NULL); va_end (args); return spawnve (mode, path, (char * const *) argv, cur_environ ());}extern "C" intspawnle (int mode, const char *path, const char *arg0, ...){ int i; va_list args; const char * const *envp; const char *argv[256]; va_start (args, arg0); argv[0] = arg0; i = 1; do argv[i] = va_arg (args, const char *); while (argv[i++] != NULL); envp = va_arg (args, const char * const *); va_end (args); return spawnve (mode, path, (char * const *) argv, (char * const *) envp);}extern "C" intspawnlp (int mode, const char *path, const char *arg0, ...){ int i; va_list args; const char *argv[256]; va_start (args, arg0); argv[0] = arg0; i = 1; do argv[i] = va_arg (args, const char *); while (argv[i++] != NULL); va_end (args); return spawnvpe (mode, path, (char * const *) argv, cur_environ ());}extern "C" intspawnlpe (int mode, const char *path, const char *arg0, ...){ int i; va_list args; const char * const *envp; const char *argv[256]; va_start (args, arg0); argv[0] = arg0; i = 1; do argv[i] = va_arg (args, const char *); while (argv[i++] != NULL); envp = va_arg (args, const char * const *); va_end (args); return spawnvpe (mode, path, (char * const *) argv, envp);}extern "C" intspawnv (int mode, const char *path, const char * const *argv){ return spawnve (mode, path, argv, cur_environ ());}extern "C" intspawnvp (int mode, const char *path, const char * const *argv){ return spawnvpe (mode, path, argv, cur_environ ());}extern "C" intspawnvpe (int mode, const char *file, const char * const *argv, const char * const *envp){ path_conv buf; return spawnve (mode, find_exec (file, buf), argv, envp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -