fix: exec() error not returned to parent (#1363)

* fix: exec() error not returned to parent

* chore: remove accidental lua.h inclusion
This commit is contained in:
Takase 2023-02-01 06:26:15 +08:00 committed by takase1121
parent 218ba3ebac
commit b95fdfcf5f
No known key found for this signature in database
GPG Key ID: 60EEFFC68EB3031B
1 changed files with 44 additions and 3 deletions

View File

@ -293,6 +293,7 @@ static int process_start(lua_State* L) {
CloseHandle(self->process_information.hProcess); CloseHandle(self->process_information.hProcess);
CloseHandle(self->process_information.hThread); CloseHandle(self->process_information.hThread);
#else #else
int control_pipe[2] = { 0 };
for (int i = 0; i < 3; ++i) { // Make only the parents fd's non-blocking. Children should block. for (int i = 0; i < 3; ++i) { // Make only the parents fd's non-blocking. Children should block.
if (pipe(self->child_pipes[i]) || fcntl(self->child_pipes[i][i == STDIN_FD ? 1 : 0], F_SETFL, O_NONBLOCK) == -1) { if (pipe(self->child_pipes[i]) || fcntl(self->child_pipes[i][i == STDIN_FD ? 1 : 0], F_SETFL, O_NONBLOCK) == -1) {
lua_pushfstring(L, "Error creating pipes: %s", strerror(errno)); lua_pushfstring(L, "Error creating pipes: %s", strerror(errno));
@ -300,12 +301,25 @@ static int process_start(lua_State* L) {
goto cleanup; goto cleanup;
} }
} }
// create a pipe to get the exit code of exec()
if (pipe(control_pipe) == -1) {
lua_pushfstring(L, "Error creating control pipe: %s", strerror(errno));
retval = -1;
goto cleanup;
}
if (fcntl(control_pipe[1], F_SETFD, FD_CLOEXEC) == -1) {
lua_pushfstring(L, "Error setting FD_CLOEXEC: %s", strerror(errno));
retval = -1;
goto cleanup;
}
self->pid = (long)fork(); self->pid = (long)fork();
if (self->pid < 0) { if (self->pid < 0) {
lua_pushfstring(L, "Error running fork: %s.", strerror(errno)); lua_pushfstring(L, "Error running fork: %s.", strerror(errno));
retval = -1; retval = -1;
goto cleanup; goto cleanup;
} else if (!self->pid) { } else if (!self->pid) {
// child process
if (!detach) if (!detach)
setpgid(0,0); setpgid(0,0);
for (int stream = 0; stream < 3; ++stream) { for (int stream = 0; stream < 3; ++stream) {
@ -320,12 +334,39 @@ static int process_start(lua_State* L) {
for (set = 0; set < env_len && setenv(env_names[set], env_values[set], 1) == 0; ++set); for (set = 0; set < env_len && setenv(env_names[set], env_values[set], 1) == 0; ++set);
if (set == env_len && (!detach || setsid() != -1) && (!cwd || chdir(cwd) != -1)) if (set == env_len && (!detach || setsid() != -1) && (!cwd || chdir(cwd) != -1))
execvp(cmd[0], (char** const)cmd); execvp(cmd[0], (char** const)cmd);
const char* msg = strerror(errno); write(control_pipe[1], &errno, sizeof(errno));
size_t result = write(STDERR_FD, msg, strlen(msg)+1); _exit(-1);
_exit(result == strlen(msg)+1 ? -1 : -2);
} }
// close our write side so we can read from child
close(control_pipe[1]);
control_pipe[1] = 0;
// wait for child process to respond
int sz, process_rc;
while ((sz = read(control_pipe[0], &process_rc, sizeof(int))) == -1) {
if (errno == EPIPE) break;
if (errno != EINTR) {
lua_pushfstring(L, "Error getting child process status: %s", strerror(errno));
retval = -1;
goto cleanup;
}
}
if (sz) {
// read something from pipe; exec failed
int status;
waitpid(self->pid, &status, 0);
lua_pushfstring(L, "Error creating child process: %s", strerror(process_rc));
retval = -1;
goto cleanup;
}
#endif #endif
cleanup: cleanup:
#ifndef _WIN32
if (control_pipe[0]) close(control_pipe[0]);
if (control_pipe[1]) close(control_pipe[1]);
#endif
for (size_t i = 0; i < env_len; ++i) { for (size_t i = 0; i < env_len; ++i) {
free((char*)env_names[i]); free((char*)env_names[i]);
free((char*)env_values[i]); free((char*)env_values[i]);