int win32_spawn(int job_id, const char *cmd_line, const char **env, int env_count, const char *annotation, const char* echo_cmdline) { int result_code = 1; char buffer[8192]; char env_block[128*1024]; HANDLE output_handle; STARTUPINFO sinfo; PROCESS_INFORMATION pinfo; if (0 != make_env_block(env_block, sizeof(env_block) - 2, env, env_count)) { fprintf(stderr, "%d: env block error; too big?\n", job_id); return 1; } _snprintf(buffer, sizeof(buffer), "cmd.exe /c \"%s\"", cmd_line); output_handle = alloc_fd(job_id); memset(&pinfo, 0, sizeof(pinfo)); memset(&sinfo, 0, sizeof(sinfo)); sinfo.cb = sizeof(sinfo); sinfo.hStdInput = NULL; sinfo.hStdOutput = sinfo.hStdError = output_handle; sinfo.dwFlags = STARTF_USESTDHANDLES; if (annotation) println_to_handle(output_handle, annotation); if (echo_cmdline) println_to_handle(output_handle, echo_cmdline); if (CreateProcess(NULL, buffer, NULL, NULL, TRUE, 0, env_block, NULL, &sinfo, &pinfo)) { DWORD result; CloseHandle(pinfo.hThread); while (WAIT_OBJECT_0 != WaitForSingleObject(pinfo.hProcess, INFINITE)) /* nop */; GetExitCodeProcess(pinfo.hProcess, &result); CloseHandle(pinfo.hProcess); result_code = (int) result; } else { fprintf(stderr, "%d: Couldn't launch process; Win32 error = %d\n", job_id, (int) GetLastError()); } free_fd(job_id, output_handle); return result_code; }
static int posix_spawn_common( bool search_path, pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]) { STARTUPINFO sinfo; SECURITY_ATTRIBUTES sec; PROCESS_INFORMATION pinfo; char *cmdbuf; char *env_block; DWORD create_flags = CREATE_NO_WINDOW; int ret; int i; unused_parameter(envp); // FIXME cmdbuf = build_command_line(argv); if (!cmdbuf) { return ENOMEM; } env_block = make_env_block(envp); if (!env_block) { free(cmdbuf); return ENOMEM; } memset(&sinfo, 0, sizeof(sinfo)); sinfo.cb = sizeof(sinfo); sinfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; sinfo.wShowWindow = SW_HIDE; memset(&sec, 0, sizeof(sec)); sec.nLength = sizeof(sec); sec.bInheritHandle = TRUE; memset(&pinfo, 0, sizeof(pinfo)); if (attrp->flags & POSIX_SPAWN_SETPGROUP) { create_flags |= CREATE_NEW_PROCESS_GROUP; } // Process any dup(2) actions for (i = 0; i < file_actions->ndups; i++) { struct _posix_spawn_file_dup *dup = &file_actions->dups[i]; HANDLE *target = NULL; DWORD err; switch (dup->target_fd) { case 0: target = &sinfo.hStdInput; break; case 1: target = &sinfo.hStdOutput; break; case 2: target = &sinfo.hStdError; break; } if (!target) { w_log(W_LOG_ERR, "posix_spawn: can't target fd outside range [0-2]\n"); ret = ENOSYS; goto done; } if (*target) { CloseHandle(*target); *target = INVALID_HANDLE_VALUE; } if (!DuplicateHandle(GetCurrentProcess(), dup->local_handle, GetCurrentProcess(), target, 0, TRUE, DUPLICATE_SAME_ACCESS)) { err = GetLastError(); w_log(W_LOG_ERR, "posix_spawn: failed to duplicate handle: %s\n", win32_strerror(err)); ret = map_win32_err(err); goto done; } } // Process any file opening actions for (i = 0; i < file_actions->nopens; i++) { struct _posix_spawn_file_open *op = &file_actions->opens[i]; HANDLE h; HANDLE *target = NULL; switch (op->target_fd) { case 0: target = &sinfo.hStdInput; break; case 1: target = &sinfo.hStdOutput; break; case 2: target = &sinfo.hStdError; break; } if (!target) { w_log(W_LOG_ERR, "posix_spawn: can't target fd outside range [0-2]\n"); ret = ENOSYS; goto done; } h = w_handle_open(op->name, op->flags & ~O_CLOEXEC); if (h == INVALID_HANDLE_VALUE) { ret = errno; w_log(W_LOG_ERR, "posix_spawn: failed to open %s:\n", op->name); goto done; } if (*target) { CloseHandle(*target); } *target = h; } if (!sinfo.hStdInput) { sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); } if (!sinfo.hStdOutput) { sinfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); } if (!sinfo.hStdError) { sinfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); } if (!CreateProcess(search_path ? NULL : path, cmdbuf, &sec, &sec, TRUE, create_flags, env_block, attrp->working_dir, &sinfo, &pinfo)) { w_log(W_LOG_ERR, "CreateProcess: `%s`: (cwd=%s) %s\n", cmdbuf, attrp->working_dir ? attrp->working_dir : "<process cwd>", win32_strerror(GetLastError())); ret = EACCES; } else { *pid = (pid_t)pinfo.dwProcessId; // Record the pid -> handle mapping for later wait/reap pthread_mutex_lock(&child_proc_lock); if (!child_procs) { child_procs = w_ht_new(2, NULL); } w_ht_set(child_procs, pinfo.dwProcessId, w_ht_ptr_val(pinfo.hProcess)); pthread_mutex_unlock(&child_proc_lock); CloseHandle(pinfo.hThread); ret = 0; } done: free(cmdbuf); free(env_block); // If we manufactured any handles, close them out now if (sinfo.hStdInput != GetStdHandle(STD_INPUT_HANDLE)) { CloseHandle(sinfo.hStdInput); } if (sinfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE)) { CloseHandle(sinfo.hStdOutput); } if (sinfo.hStdError != GetStdHandle(STD_ERROR_HANDLE)) { CloseHandle(sinfo.hStdError); } return ret; }