diff --git a/app/src/command.c b/app/src/command.c index b7ea67d2..cc11a0de 100644 --- a/app/src/command.c +++ b/app/src/command.c @@ -18,9 +18,25 @@ static inline const char *get_adb_command() { return adb_command; } +static void show_adb_err_msg(enum process_result err) { + switch (err) { + case PROCESS_ERROR_GENERIC: + LOGE("Failed to execute adb"); + break; + case PROCESS_ERROR_MISSING_BINARY: + LOGE("'adb' command not found (make it accessible from your PATH " + "or define its full path in the ADB environment variable)"); + break; + case PROCESS_SUCCESS: + /* do nothing */ + break; + } +} + 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 +48,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); + enum process_result r = cmd_execute(cmd[0], cmd, &process); + if (r != PROCESS_SUCCESS) { + show_adb_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..3e0fcca6 100644 --- a/app/src/command.h +++ b/app/src/command.h @@ -32,7 +32,13 @@ #endif # define NO_EXIT_CODE -1 -process_t cmd_execute(const char *path, const char *const argv[]); +enum process_result { + PROCESS_SUCCESS, + PROCESS_ERROR_GENERIC, + PROCESS_ERROR_MISSING_BINARY, +}; + +enum process_result 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..ed9bbeac 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,65 @@ #include #include "log.h" -pid_t cmd_execute(const char *path, const char *const argv[]) { - pid_t pid = fork(); - if (pid == -1) { - perror("fork"); - return -1; +enum process_result cmd_execute(const char *path, const char *const argv[], pid_t *pid) { + int fd[2]; + + if (pipe(fd) == -1) { + perror("pipe"); + return PROCESS_ERROR_GENERIC; } - if (pid == 0) { - execvp(path, (char *const *)argv); - perror("exec"); + + enum process_result ret = PROCESS_SUCCESS; + + *pid = fork(); + if (*pid == -1) { + perror("fork"); + ret = PROCESS_ERROR_GENERIC; + 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(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; + } + perror("exec"); + } else { + perror("fcntl"); + ret = PROCESS_ERROR_GENERIC; + } + // send ret to the parent + if (write(fd[1], &ret, sizeof(ret)) == -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..7a29442d 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[]) { +enum process_result 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 PROCESS_ERROR_GENERIC; } #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 PROCESS_ERROR_GENERIC; } - return pi.hProcess; + *handle = pi.hProcess; + return PROCESS_SUCCESS; } SDL_bool cmd_terminate(HANDLE handle) {