diff --git a/app/src/adb.c b/app/src/adb.c index 630a1952..ee0ef184 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_INHERIT_STDERR; + if (!pout) { + inherit |= SC_INHERIT_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..fead51b0 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_INHERIT_STDOUT; + bool inherit_stderr = inherit & SC_INHERIT_STDERR; + + // If pout is defined, then inherit MUST NOT contain SC_INHERIT_STDOUT. + assert(!pout || !inherit_stdout); + // If perr is defined, then inherit MUST NOT contain SC_INHERIT_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..8da65817 100644 --- a/app/src/sys/win/process.c +++ b/app/src/sys/win/process.c @@ -27,12 +27,17 @@ 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_INHERIT_STDOUT; + bool inherit_stderr = inherit & SC_INHERIT_STDERR; - // Add 1 per non-NULL pointer - unsigned handle_count = !!pin + !!pout + !!perr; + // If pout is defined, then inherit MUST NOT contain SC_INHERIT_STDOUT. + assert(!pout || !inherit_stdout); + // If perr is defined, then inherit MUST NOT contain SC_INHERIT_STDERR. + assert(!perr || !inherit_stderr); + + enum sc_process_result ret = SC_PROCESS_ERROR_GENERIC; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); @@ -80,53 +85,52 @@ sc_process_execute_p(const char *const argv[], HANDLE *handle, HANDLE handles[3]; LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL; - if (handle_count) { - si.StartupInfo.dwFlags = STARTF_USESTDHANDLES; + 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; - handles[i++] = si.StartupInfo.hStdOutput; - } - if (perr) { - si.StartupInfo.hStdError = stderr_write_handle; - handles[i++] = si.StartupInfo.hStdError; - } - - SIZE_T size; - // Call it once to know the required buffer size - BOOL ok = - InitializeProcThreadAttributeList(NULL, 1, 0, &size) - || GetLastError() == ERROR_INSUFFICIENT_BUFFER; - if (!ok) { - goto error_close_stderr; - } - - lpAttributeList = malloc(size); - if (!lpAttributeList) { - goto error_close_stderr; - } - - ok = InitializeProcThreadAttributeList(lpAttributeList, 1, 0, &size); - if (!ok) { - free(lpAttributeList); - goto error_close_stderr; - } - - ok = UpdateProcThreadAttribute(lpAttributeList, 0, - PROC_THREAD_ATTRIBUTE_HANDLE_LIST, - handles, handle_count * sizeof(HANDLE), - NULL, NULL); - if (!ok) { - goto error_free_attribute_list; - } - - si.lpAttributeList = lpAttributeList; + unsigned handle_count = 0; + if (pin) { + si.StartupInfo.hStdInput = stdin_read_handle; + handles[handle_count++] = si.StartupInfo.hStdInput; } + if (pout || inherit_stdout) { + si.StartupInfo.hStdOutput = pout ? stdout_write_handle + : GetStdHandle(STD_OUTPUT_HANDLE); + handles[handle_count++] = si.StartupInfo.hStdOutput; + } + if (perr || inherit_stderr) { + si.StartupInfo.hStdError = perr ? stderr_write_handle + : GetStdHandle(STD_ERROR_HANDLE); + handles[handle_count++] = si.StartupInfo.hStdError; + } + + SIZE_T size; + // Call it once to know the required buffer size + BOOL ok = + InitializeProcThreadAttributeList(NULL, 1, 0, &size) + || GetLastError() == ERROR_INSUFFICIENT_BUFFER; + if (!ok) { + goto error_close_stderr; + } + + lpAttributeList = malloc(size); + if (!lpAttributeList) { + goto error_close_stderr; + } + + ok = InitializeProcThreadAttributeList(lpAttributeList, 1, 0, &size); + if (!ok) { + free(lpAttributeList); + goto error_close_stderr; + } + + ok = UpdateProcThreadAttribute(lpAttributeList, 0, + PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, + handle_count * sizeof(HANDLE), NULL, NULL); + if (!ok) { + goto error_free_attribute_list; + } + + si.lpAttributeList = lpAttributeList; char *cmd = malloc(CMD_MAX_LEN); if (!cmd || !build_cmd(cmd, CMD_MAX_LEN, argv)) { @@ -140,10 +144,9 @@ sc_process_execute_p(const char *const argv[], HANDLE *handle, goto error_free_attribute_list; } - BOOL bInheritHandles = handle_count > 0; - DWORD dwCreationFlags = handle_count > 0 ? EXTENDED_STARTUPINFO_PRESENT : 0; - BOOL ok = CreateProcessW(NULL, wide, NULL, NULL, bInheritHandles, - dwCreationFlags, NULL, NULL, &si.StartupInfo, &pi); + ok = CreateProcessW(NULL, wide, NULL, NULL, TRUE, + EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, + &si.StartupInfo, &pi); free(wide); if (!ok) { if (GetLastError() == ERROR_FILE_NOT_FOUND) { 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..0aa09b29 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_INHERIT_STDOUT (1 << 0) +#define SC_INHERIT_STDERR (1 << 1) + /** * Execute the command and write the process id to `pid` + * + * The parameter `inherit` is a ORed value of SC_INHERIT_* flags. 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_INHERIT_STDOUT. + * If `perr` is not NULL, then `inherit` MUST NOT contain SC_INHERIT_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); /**