diff --git a/app/src/command.h b/app/src/command.h index 3e0fcca6..385d09d7 100644 --- a/app/src/command.h +++ b/app/src/command.h @@ -24,11 +24,13 @@ # define PROCESS_NONE NULL typedef HANDLE process_t; typedef DWORD exit_code_t; + typedef HANDLE pipe_t; #else # include # define PROCESS_NONE -1 typedef pid_t process_t; typedef int exit_code_t; + typedef int pipe_t; #endif # define NO_EXIT_CODE -1 @@ -39,6 +41,8 @@ enum process_result { }; enum process_result cmd_execute(const char *path, const char *const argv[], process_t *process); +enum process_result cmd_execute_redirect(const char *path, const char *const argv[], process_t *process, + pipe_t *pipe_stdin, pipe_t *pipe_stdout, pipe_t *pipe_stderr); SDL_bool cmd_terminate(process_t pid); SDL_bool cmd_simple_wait(process_t pid, exit_code_t *exit_code); @@ -55,4 +59,7 @@ process_t adb_remove_path(const char *serial, const char *path); // automatically log process errors with the provided process name SDL_bool process_check_success(process_t process, const char *name); +int read_pipe(pipe_t pipe, char *data, size_t len); +void close_pipe(pipe_t pipe); + #endif diff --git a/app/src/sys/unix/command.c b/app/src/sys/unix/command.c index ed9bbeac..c2a6e882 100644 --- a/app/src/sys/unix/command.c +++ b/app/src/sys/unix/command.c @@ -1,5 +1,6 @@ #include "command.h" +#include #include #include #include @@ -9,65 +10,151 @@ #include #include "log.h" -enum process_result cmd_execute(const char *path, const char *const argv[], pid_t *pid) { - int fd[2]; +enum process_result cmd_execute_redirect(const char *path, const char *const argv[], pid_t *pid, + int *pipe_stdin, int *pipe_stdout, int *pipe_stderr) { + int in[2]; + int out[2]; + int err[2]; + int internal[2]; // communication between parent and children - if (pipe(fd) == -1) { + if (pipe(internal) == -1) { perror("pipe"); return PROCESS_ERROR_GENERIC; } - - enum process_result ret = PROCESS_SUCCESS; + if (pipe_stdin) { + if (pipe(in) == -1) { + perror("pipe"); + close(internal[0]); + close(internal[1]); + return PROCESS_ERROR_GENERIC; + } + } + if (pipe_stdout) { + if (pipe(out) == -1) { + perror("pipe"); + // clean up + if (pipe_stdin) { + close(in[0]); + close(in[1]); + } + close(internal[0]); + close(internal[1]); + return PROCESS_ERROR_GENERIC; + } + } + if (pipe_stderr) { + if (pipe(err) == -1) { + perror("pipe"); + // clean up + if (pipe_stdout) { + close(out[0]); + close(out[1]); + } + if (pipe_stdin) { + close(in[0]); + close(in[1]); + } + close(internal[0]); + close(internal[1]); + return PROCESS_ERROR_GENERIC; + } + } *pid = fork(); if (*pid == -1) { perror("fork"); - ret = PROCESS_ERROR_GENERIC; - goto end; + // clean up + if (pipe_stderr) { + close(err[0]); + close(err[1]); + } + if (pipe_stdout) { + close(out[0]); + close(out[1]); + } + if (pipe_stdin) { + close(in[0]); + close(in[1]); + } + close(internal[0]); + close(internal[1]); + return PROCESS_ERROR_GENERIC; } - if (*pid > 0) { - // parent close write side - close(fd[1]); - fd[1] = -1; - // wait for EOF or receive errno from child - if (read(fd[0], &ret, sizeof(ret)) == -1) { - perror("read"); - ret = PROCESS_ERROR_GENERIC; - goto end; - } - } else if (*pid == 0) { - // child close read side - close(fd[0]); - if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) == 0) { - execvp(path, (char *const *)argv); - if (errno == ENOENT) { - ret = PROCESS_ERROR_MISSING_BINARY; - } else { - ret = PROCESS_ERROR_GENERIC; + if (*pid == 0) { + if (pipe_stdin) { + if (in[0] != STDIN_FILENO) { + dup2(in[0], STDIN_FILENO); + close(in[0]); } + close(in[1]); + } + if (pipe_stdout) { + if (out[1] != STDOUT_FILENO) { + dup2(out[1], STDOUT_FILENO); + close(out[1]); + } + close(out[0]); + } + if (pipe_stderr) { + if (err[1] != STDERR_FILENO) { + dup2(err[1], STDERR_FILENO); + close(err[1]); + } + close(err[0]); + } + close(internal[0]); + enum process_result err; + if (fcntl(internal[1], F_SETFD, FD_CLOEXEC) == 0) { + execvp(path, (char *const *)argv); perror("exec"); + err = errno == ENOENT ? PROCESS_ERROR_MISSING_BINARY + : PROCESS_ERROR_GENERIC; } else { perror("fcntl"); - ret = PROCESS_ERROR_GENERIC; + err = PROCESS_ERROR_GENERIC; } - // send ret to the parent - if (write(fd[1], &ret, sizeof(ret)) == -1) { + printf("==> %d\n",(int)err); + // send err to the parent + if (write(internal[1], &err, sizeof(err)) == -1) { perror("write"); } - // close write side before exiting - close(fd[1]); + close(internal[1]); _exit(1); } -end: - if (fd[0] != -1) { - close(fd[0]); + /* parent */ + assert(*pid > 0); + + close(internal[1]); + + enum process_result res = PROCESS_SUCCESS; + // wait for EOF or receive err from child + if (read(internal[0], &res, sizeof(res)) == -1) { + perror("read"); + res = PROCESS_ERROR_GENERIC; } - if (fd[1] != -1) { - close(fd[1]); + + close(internal[0]); + + if (pipe_stdin) { + close(in[0]); + *pipe_stdin = in[1]; } - return ret; + if (pipe_stdout) { + *pipe_stdout = out[0]; + close(out[1]); + } + if (pipe_stderr) { + *pipe_stderr = err[0]; + close(err[1]); + } + + return res; +} + +enum process_result cmd_execute(const char *path, const char *const argv[], pid_t *pid) { + return cmd_execute_redirect(path, argv, pid, NULL, NULL, NULL); } SDL_bool cmd_terminate(pid_t pid) { @@ -92,3 +179,13 @@ SDL_bool cmd_simple_wait(pid_t pid, int *exit_code) { } return !code; } + +int read_pipe(int pipe, char *data, size_t len) { + return read(pipe, data, len); +} + +void close_pipe(int pipe) { + if (close(pipe)) { + perror("close pipe"); + } +} diff --git a/app/src/sys/win/command.c b/app/src/sys/win/command.c index d0f189f7..4954c76b 100644 --- a/app/src/sys/win/command.c +++ b/app/src/sys/win/command.c @@ -17,15 +17,68 @@ static int build_cmd(char *cmd, size_t len, const char *const argv[]) { return 0; } -enum process_result cmd_execute(const char *path, const char *const argv[], HANDLE *handle) { +enum process_result cmd_execute_redirect(const char *path, const char *const argv[], HANDLE *handle, + HANDLE *pipe_stdin, HANDLE *pipe_stdout, HANDLE *pipe_stderr) { + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + HANDLE stdin_read_handle; + HANDLE stdout_write_handle; + HANDLE stderr_write_handle; + if (pipe_stdin) { + if (!CreatePipe(&stdin_read_handle, pipe_stdin, &sa, 0)) { + perror("pipe"); + return PROCESS_ERROR_GENERIC; + } + } + if (pipe_stdout) { + if (!CreatePipe(pipe_stdout, &stdout_write_handle, &sa, 0)) { + perror("pipe"); + // clean up + if (pipe_stdin) { + CloseHandle(&stdin_read_handle); + CloseHandle(pipe_stdin); + } + return PROCESS_ERROR_GENERIC; + } + } + if (pipe_stderr) { + if (!CreatePipe(pipe_stderr, &stderr_write_handle, &sa, 0)) { + perror("pipe"); + // clean up + if (pipe_stdin) { + CloseHandle(&stdin_read_handle); + CloseHandle(pipe_stdin); + } + if (pipe_stdout) { + CloseHandle(pipe_stdout); + CloseHandle(&stdout_write_handle); + } + return PROCESS_ERROR_GENERIC; + } + } + STARTUPINFO si; PROCESS_INFORMATION pi; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); + if (pipe_stdin || pipe_stdout || pipe_stderr) { + si.dwFlags = STARTF_USESTDHANDLES; + if (pipe_stdin) { + si.hStdInput = stdin_read_handle; + } + if (pipe_stdout) { + si.hStdOutput = stdout_write_handle; + } + if (pipe_stderr) { + si.hStdError = stderr_write_handle; + } + } char cmd[256]; if (build_cmd(cmd, sizeof(cmd), argv)) { - *handle = NULL; return PROCESS_ERROR_GENERIC; } @@ -46,6 +99,10 @@ enum process_result cmd_execute(const char *path, const char *const argv[], HAND return PROCESS_SUCCESS; } +enum process_result cmd_execute(const char *path, const char *const argv[], HANDLE *handle) { + return cmd_execute_redirect(path, argv, handle, NULL, NULL, NULL); +} + SDL_bool cmd_terminate(HANDLE handle) { return TerminateProcess(handle, 1) && CloseHandle(handle); }