From 143bfc03950f05fe27dd536eef3d3fd51a2ade57 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Fri, 19 Nov 2021 22:42:49 +0100 Subject: [PATCH] Expose inherit flag for process execution Let the caller decide if stdout and stderr must be inherited on process creation, i.e. if stdout and stderr of the child process should be printed in the scrcpy console. This allows to get output and errors for specific adb commands depending on the context. --- app/src/adb.c | 6 +++++- app/src/sys/unix/process.c | 21 ++++++++++++++++++++- app/src/sys/win/process.c | 31 ++++++++++++++++++++++--------- app/src/util/process.c | 4 ++-- app/src/util/process.h | 15 +++++++++++++-- 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/app/src/adb.c b/app/src/adb.c index 630a1952..9ffc752a 100644 --- a/app/src/adb.c +++ b/app/src/adb.c @@ -132,8 +132,12 @@ adb_execute_p(const char *serial, const char *const adb_cmd[], memcpy(&argv[i], adb_cmd, len * sizeof(const char *)); argv[len + i] = NULL; + unsigned inherit = SC_STDERR; + if (!pout) { + inherit |= SC_STDOUT; + } enum sc_process_result r = - sc_process_execute_p(argv, &pid, NULL, pout, NULL); + sc_process_execute_p(argv, &pid, inherit, NULL, pout, NULL); if (r != SC_PROCESS_SUCCESS) { show_adb_err_msg(r, argv); pid = SC_PROCESS_NONE; diff --git a/app/src/sys/unix/process.c b/app/src/sys/unix/process.c index 5f4a9890..d876cc76 100644 --- a/app/src/sys/unix/process.c +++ b/app/src/sys/unix/process.c @@ -11,8 +11,16 @@ #include "util/log.h" enum sc_process_result -sc_process_execute_p(const char *const argv[], sc_pid *pid, +sc_process_execute_p(const char *const argv[], sc_pid *pid, unsigned inherit, int *pin, int *pout, int *perr) { + bool inherit_stdout = inherit & SC_STDOUT; + bool inherit_stderr = inherit & SC_STDERR; + + // If pout is defined, then inherit MUST NOT contain SC_STDOUT. + assert(!pout || !inherit_stdout); + // If perr is defined, then inherit MUST NOT contain SC_STDERR. + assert(!perr || !inherit_stderr); + int in[2]; int out[2]; int err[2]; @@ -90,20 +98,31 @@ sc_process_execute_p(const char *const argv[], sc_pid *pid, } close(in[1]); } + // Do not close stdin in the child process, this makes adb fail on + // Linux + if (pout) { if (out[1] != STDOUT_FILENO) { dup2(out[1], STDOUT_FILENO); close(out[1]); } close(out[0]); + } else if (!inherit_stdout) { + // Close stdout in the child process + close(STDOUT_FILENO); } + if (perr) { if (err[1] != STDERR_FILENO) { dup2(err[1], STDERR_FILENO); close(err[1]); } close(err[0]); + } else if (!inherit_stderr) { + // Close stderr in the child process + close(STDERR_FILENO); } + close(internal[0]); enum sc_process_result err; if (fcntl(internal[1], F_SETFD, FD_CLOEXEC) == 0) { diff --git a/app/src/sys/win/process.c b/app/src/sys/win/process.c index 222a0240..51be5066 100644 --- a/app/src/sys/win/process.c +++ b/app/src/sys/win/process.c @@ -27,12 +27,22 @@ build_cmd(char *cmd, size_t len, const char *const argv[]) { } enum sc_process_result -sc_process_execute_p(const char *const argv[], HANDLE *handle, +sc_process_execute_p(const char *const argv[], HANDLE *handle, unsigned inherit, HANDLE *pin, HANDLE *pout, HANDLE *perr) { - enum sc_process_result ret = SC_PROCESS_ERROR_GENERIC; + bool inherit_stdout = inherit & SC_STDOUT; + bool inherit_stderr = inherit & SC_STDERR; + + // If pout is defined, then inherit MUST NOT contain SC_STDOUT. + assert(!pout || !inherit_stdout); + // If perr is defined, then inherit MUST NOT contain SC_STDERR. + assert(!perr || !inherit_stderr); // Add 1 per non-NULL pointer - unsigned handle_count = !!pin + !!pout + !!perr; + unsigned handle_count = !!pin + + (pout || inherit_stdout) + + (perr || inherit_stderr); + + enum sc_process_result ret = SC_PROCESS_ERROR_GENERIC; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); @@ -82,18 +92,19 @@ sc_process_execute_p(const char *const argv[], HANDLE *handle, LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL; if (handle_count) { si.StartupInfo.dwFlags = STARTF_USESTDHANDLES; - unsigned i = 0; if (pin) { si.StartupInfo.hStdInput = stdin_read_handle; handles[i++] = si.StartupInfo.hStdInput; } - if (pout) { - si.StartupInfo.hStdOutput = stdout_write_handle; + if (pout || inherit_stdout) { + si.StartupInfo.hStdOutput = pout ? stdout_write_handle + : GetStdHandle(STD_OUTPUT_HANDLE); handles[i++] = si.StartupInfo.hStdOutput; } - if (perr) { - si.StartupInfo.hStdError = stderr_write_handle; + if (perr || inherit_stderr) { + si.StartupInfo.hStdError = perr ? stderr_write_handle + : GetStdHandle(STD_ERROR_HANDLE); handles[i++] = si.StartupInfo.hStdError; } @@ -141,7 +152,9 @@ sc_process_execute_p(const char *const argv[], HANDLE *handle, } BOOL bInheritHandles = handle_count > 0; - DWORD dwCreationFlags = handle_count > 0 ? EXTENDED_STARTUPINFO_PRESENT : 0; + // DETACHED_PROCESS to disable stdin, stdout and stderr + DWORD dwCreationFlags = handle_count == 0 ? DETACHED_PROCESS + : EXTENDED_STARTUPINFO_PRESENT; BOOL ok = CreateProcessW(NULL, wide, NULL, NULL, bInheritHandles, dwCreationFlags, NULL, NULL, &si.StartupInfo, &pi); free(wide); diff --git a/app/src/util/process.c b/app/src/util/process.c index 28f51edd..8fcfdd7c 100644 --- a/app/src/util/process.c +++ b/app/src/util/process.c @@ -5,8 +5,8 @@ #include "log.h" enum sc_process_result -sc_process_execute(const char *const argv[], sc_pid *pid) { - return sc_process_execute_p(argv, pid, NULL, NULL, NULL); +sc_process_execute(const char *const argv[], sc_pid *pid, unsigned inherit) { + return sc_process_execute_p(argv, pid, inherit, NULL, NULL, NULL); } bool diff --git a/app/src/util/process.h b/app/src/util/process.h index 7964be5c..6c85a9ed 100644 --- a/app/src/util/process.h +++ b/app/src/util/process.h @@ -67,20 +67,31 @@ enum sc_process_result { SC_PROCESS_ERROR_MISSING_BINARY, }; +#define SC_STDOUT (1 << 0) +#define SC_STDERR (1 << 1) + /** * Execute the command and write the process id to `pid` + * + * The parameter `inherit` is a OR of any of SC_STDOUT and SC_STDERR. It + * indicates if stdout and stderr must be inherited from the scrcpy process (in + * other words, if the process must output to the scrcpy console). */ enum sc_process_result -sc_process_execute(const char *const argv[], sc_pid *pid); +sc_process_execute(const char *const argv[], sc_pid *pid, unsigned inherit); /** * Execute the command and write the process id to `pid` * * If not NULL, provide a pipe for stdin (`pin`), stdout (`pout`) and stderr * (`perr`). + * + * The parameter `inherit` has the same semantics as in `sc_process_execute()`. + * If `pout` is not NULL, then `inherit` MUST NOT contain SC_STDOUT. + * If `perr` is not NULL, then `inherit` MUST NOT contain SC_STDERR. */ enum sc_process_result -sc_process_execute_p(const char *const argv[], sc_pid *pid, +sc_process_execute_p(const char *const argv[], sc_pid *pid, unsigned inherit, sc_pipe *pin, sc_pipe *pout, sc_pipe *perr); /**