pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int cloexec_mutex_is_locked) { #if defined(__linux__) /* posix_spawnp of Linux does not return error if the executable does not exist, see * https://gist.github.com/kazuho/0c233e6f86d27d6e4f09 */ extern char **environ; int pipefds[2] = {-1, -1}, errnum; pid_t pid; /* create pipe, used for sending error codes */ if (pipe2(pipefds, O_CLOEXEC) != 0) goto Error; /* fork */ if (!cloexec_mutex_is_locked) pthread_mutex_lock(&cloexec_mutex); if ((pid = fork()) == 0) { /* in child process, map the file descriptors and execute; return the errnum through pipe if exec failed */ if (mapped_fds != NULL) { for (; *mapped_fds != -1; mapped_fds += 2) { if (mapped_fds[1] != -1) dup2(mapped_fds[0], mapped_fds[1]); close(mapped_fds[0]); } } char **env = build_spawn_env(); if (env != NULL) environ = env; execvp(cmd, argv); errnum = errno; write(pipefds[1], &errnum, sizeof(errnum)); _exit(EX_SOFTWARE); } if (!cloexec_mutex_is_locked) pthread_mutex_unlock(&cloexec_mutex); if (pid == -1) goto Error; /* parent process */ close(pipefds[1]); pipefds[1] = -1; ssize_t rret; errnum = 0; while ((rret = read(pipefds[0], &errnum, sizeof(errnum))) == -1 && errno == EINTR) ; if (rret != 0) { /* spawn failed */ while (waitpid(pid, NULL, 0) != pid) ; pid = -1; errno = errnum; goto Error; } /* spawn succeeded */ close(pipefds[0]); return pid; Error: errnum = errno; if (pipefds[0] != -1) close(pipefds[0]); if (pipefds[1] != -1) close(pipefds[1]); errno = errnum; return -1; #elif defined _MSC_VER //-- : process : https://msdn.microsoft.com/en-us/library/20y988d2.aspx pid_t pid; extern char** environ; uv_loop_t *loop; uv_process_t child_req; uv_process_options_t options = { 0 }; //-- Default initialization must be 0 loop = uv_default_loop(); //-- Container for file descruptor uv_stdio_container_t child_stdio[3]; child_stdio[0].flags = UV_IGNORE; child_stdio[1].flags = UV_INHERIT_FD; //STD_OUT should be redirected to calling function child_stdio[2].flags = UV_IGNORE; if (mapped_fds != NULL) { for (; *mapped_fds != -1; mapped_fds += 2) { if (mapped_fds[1] != -1) //dup2(mapped_fds[0], mapped_fds[1]); //Equivalent to dup2() in *inx systems. child_stdio[1].data.fd = mapped_fds[0]; //2 or 1? //close(mapped_fds[0]); //add or delete a close or open action to a spawn file actions object } } if (!cloexec_mutex_is_locked) uv_mutex_lock(&cloexec_mutex); options.stdio = child_stdio; options.exit_cb = waitpid; //This function will be executed when child exists. options.file = cmd; options.args = argv; options.env = environ; //If the process is successfully spawned, this function will return 0. errno = uv_spawn(loop, &child_req, &options); pid = child_req.pid; if (!cloexec_mutex_is_locked) uv_mutex_unlock(&cloexec_mutex); if (errno != 0) return -1; return pid; #else posix_spawn_file_actions_t file_actions; pid_t pid; extern char **environ; char **env = build_spawn_env(); posix_spawn_file_actions_init(&file_actions); if (mapped_fds != NULL) { for (; *mapped_fds != -1; mapped_fds += 2) { if (mapped_fds[1] != -1) posix_spawn_file_actions_adddup2(&file_actions, mapped_fds[0], mapped_fds[1]); posix_spawn_file_actions_addclose(&file_actions, mapped_fds[0]); } } if (!cloexec_mutex_is_locked) pthread_mutex_lock(&cloexec_mutex); errno = posix_spawnp(&pid, cmd, &file_actions, NULL, argv, env != NULL ? env : environ); if (!cloexec_mutex_is_locked) pthread_mutex_unlock(&cloexec_mutex); free(env); if (errno != 0) return -1; return pid; #endif }
pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int cloexec_mutex_is_locked) { #if defined(__linux__) /* posix_spawnp of Linux does not return error if the executable does not exist, see * https://gist.github.com/kazuho/0c233e6f86d27d6e4f09 */ extern char **environ; int pipefds[2] = {-1, -1}, errnum; pid_t pid; /* create pipe, used for sending error codes */ if (pipe2(pipefds, O_CLOEXEC) != 0) goto Error; /* fork */ if (!cloexec_mutex_is_locked) pthread_mutex_lock(&cloexec_mutex); if ((pid = fork()) == 0) { /* in child process, map the file descriptors and execute; return the errnum through pipe if exec failed */ if (mapped_fds != NULL) { for (; *mapped_fds != -1; mapped_fds += 2) { if (mapped_fds[1] != -1) dup2(mapped_fds[0], mapped_fds[1]); close(mapped_fds[0]); } } char **env = build_spawn_env(); if (env != NULL) environ = env; execvp(cmd, argv); errnum = errno; write(pipefds[1], &errnum, sizeof(errnum)); _exit(EX_SOFTWARE); } if (!cloexec_mutex_is_locked) pthread_mutex_unlock(&cloexec_mutex); if (pid == -1) goto Error; /* parent process */ close(pipefds[1]); pipefds[1] = -1; ssize_t rret; errnum = 0; while ((rret = read(pipefds[0], &errnum, sizeof(errnum))) == -1 && errno == EINTR) ; if (rret != 0) { /* spawn failed */ while (waitpid(pid, NULL, 0) != pid) ; pid = -1; errno = errnum; goto Error; } /* spawn succeeded */ close(pipefds[0]); return pid; Error: errnum = errno; if (pipefds[0] != -1) close(pipefds[0]); if (pipefds[1] != -1) close(pipefds[1]); errno = errnum; return -1; #else posix_spawn_file_actions_t file_actions; pid_t pid; extern char **environ; char **env = build_spawn_env(); posix_spawn_file_actions_init(&file_actions); if (mapped_fds != NULL) { for (; *mapped_fds != -1; mapped_fds += 2) { if (mapped_fds[1] != -1) posix_spawn_file_actions_adddup2(&file_actions, mapped_fds[0], mapped_fds[1]); posix_spawn_file_actions_addclose(&file_actions, mapped_fds[0]); } } if (!cloexec_mutex_is_locked) pthread_mutex_lock(&cloexec_mutex); errno = posix_spawnp(&pid, cmd, &file_actions, NULL, argv, env != NULL ? env : environ); if (!cloexec_mutex_is_locked) pthread_mutex_unlock(&cloexec_mutex); free(env); if (errno != 0) return -1; return pid; #endif }