diff --git a/app/src/command.c b/app/src/command.c index b7ea67d2..011a2b85 100644 --- a/app/src/command.c +++ b/app/src/command.c @@ -1,5 +1,8 @@ #include "command.h" +#ifndef __WINDOWS__ +# include +#endif #include #include #include @@ -18,9 +21,30 @@ static inline const char *get_adb_command() { return adb_command; } +static void show_err_msg(int err) { +#ifdef __WINDOWS__ + (void) err; // unused + LOGE("Failed to execute adb"); +#else + switch (err) { + case -1: + LOGE("Failed to execute adb"); + break; + case ENOENT: + LOGE("'adb' command not found (make it accessible from your PATH " + "or define its full path in the ADB environment variable)"); + break; + default: + LOGE("Failed to execute adb: %s", strerror(err)); + break; + } +#endif +} + process_t adb_execute(const char *serial, const char *const adb_cmd[], int len) { const char *cmd[len + 4]; int i; + process_t process; cmd[0] = get_adb_command(); if (serial) { cmd[1] = "-s"; @@ -32,7 +56,12 @@ process_t adb_execute(const char *serial, const char *const adb_cmd[], int len) memcpy(&cmd[i], adb_cmd, len * sizeof(const char *)); cmd[len + i] = NULL; - return cmd_execute(cmd[0], cmd); + int r = cmd_execute(cmd[0], cmd, &process); + if (r != 0) { + show_err_msg(r); + return PROCESS_NONE; + } + return process; } process_t adb_forward(const char *serial, uint16_t local_port, const char *device_socket_name) { diff --git a/app/src/command.h b/app/src/command.h index 4113f251..dfc0d58a 100644 --- a/app/src/command.h +++ b/app/src/command.h @@ -32,7 +32,7 @@ #endif # define NO_EXIT_CODE -1 -process_t cmd_execute(const char *path, const char *const argv[]); +int cmd_execute(const char *path, const char *const argv[], process_t *process); SDL_bool cmd_terminate(process_t pid); SDL_bool cmd_simple_wait(process_t pid, exit_code_t *exit_code); diff --git a/app/src/sys/unix/command.c b/app/src/sys/unix/command.c index 0083a93b..20218cb9 100644 --- a/app/src/sys/unix/command.c +++ b/app/src/sys/unix/command.c @@ -1,5 +1,7 @@ #include "command.h" +#include +#include #include #include #include @@ -7,18 +9,58 @@ #include #include "log.h" -pid_t cmd_execute(const char *path, const char *const argv[]) { - pid_t pid = fork(); - if (pid == -1) { - perror("fork"); +int cmd_execute(const char *path, const char *const argv[], pid_t *pid) { + int fd[2]; + int ret = 0; + + if (pipe(fd) == -1) { + perror("pipe"); return -1; } - if (pid == 0) { - execvp(path, (char *const *)argv); - perror("exec"); + + *pid = fork(); + if (*pid == -1) { + perror("fork"); + ret = -1; + goto end; + } + + 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(int)) == -1) { + perror("read"); + ret = -1; + 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); + } else { + perror("fcntl"); + } + // send errno to the parent + ret = errno; + if (write(fd[1], &ret, sizeof(int)) == -1) { + perror("write"); + } + // close write side before exiting + close(fd[1]); _exit(1); } - return pid; + +end: + if (fd[0] != -1) { + close(fd[0]); + } + if (fd[1] != -1) { + close(fd[1]); + } + return ret; } SDL_bool cmd_terminate(pid_t pid) { diff --git a/app/src/sys/win/command.c b/app/src/sys/win/command.c index 2552eeca..cea928b4 100644 --- a/app/src/sys/win/command.c +++ b/app/src/sys/win/command.c @@ -4,7 +4,7 @@ #include "log.h" #include "str_util.h" -HANDLE cmd_execute(const char *path, const char *const argv[]) { +int cmd_execute(const char *path, const char *const argv[], HANDLE *handle) { STARTUPINFO si; PROCESS_INFORMATION pi; memset(&si, 0, sizeof(si)); @@ -18,7 +18,8 @@ HANDLE cmd_execute(const char *path, const char *const argv[]) { size_t ret = xstrjoin(cmd, argv, ' ', sizeof(cmd)); if (ret >= sizeof(cmd)) { LOGE("Command too long (%" PRIsizet " chars)", sizeof(cmd) - 1); - return NULL; + *handle = NULL; + return -1; } #ifdef WINDOWS_NOCONSOLE @@ -27,10 +28,12 @@ HANDLE cmd_execute(const char *path, const char *const argv[]) { int flags = 0; #endif if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, flags, NULL, NULL, &si, &pi)) { - return NULL; + *handle = NULL; + return -1; } - return pi.hProcess; + *handle = pi.hProcess; + return 0; } SDL_bool cmd_terminate(HANDLE handle) {