mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-04-20 03:25:03 +00:00
Add command execution with redirection
Expose command execution with pipes to stdin, stdout and stderr.
This commit is contained in:
parent
36d3799727
commit
d1c9ed4e2e
3 changed files with 200 additions and 39 deletions
|
@ -24,11 +24,13 @@
|
|||
# define PROCESS_NONE NULL
|
||||
typedef HANDLE process_t;
|
||||
typedef DWORD exit_code_t;
|
||||
typedef HANDLE pipe_t;
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# 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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "command.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
@ -9,65 +10,151 @@
|
|||
#include <unistd.h>
|
||||
#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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue