diff options
Diffstat (limited to 'tools/gator/daemon/Setup.cpp')
-rw-r--r-- | tools/gator/daemon/Setup.cpp | 202 |
1 files changed, 147 insertions, 55 deletions
diff --git a/tools/gator/daemon/Setup.cpp b/tools/gator/daemon/Setup.cpp index d4ce0328c633..7dd83ceafcce 100644 --- a/tools/gator/daemon/Setup.cpp +++ b/tools/gator/daemon/Setup.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -15,7 +15,9 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/mount.h> #include <sys/stat.h> +#include <sys/syscall.h> #include <sys/types.h> #include <sys/utsname.h> #include <sys/wait.h> @@ -24,12 +26,17 @@ #include "Config.h" #include "DynBuf.h" #include "Logging.h" +#include "SessionData.h" + +#define GATOR_MSG "gator: " +#define GATOR_ERROR "gator: error: " +#define GATOR_CONFIRM "gator: confirm: " bool getLinuxVersion(int version[3]) { // Check the kernel version struct utsname utsname; if (uname(&utsname) != 0) { - logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("uname failed"); return false; } @@ -57,7 +64,7 @@ static int pgrep_gator(DynBuf *const printb) { DIR *proc = opendir("/proc"); if (proc == NULL) { - logg->logError(__FILE__, __LINE__, "gator: error: opendir failed"); + logg->logError(GATOR_ERROR "opendir failed"); handleException(); } @@ -73,7 +80,7 @@ static int pgrep_gator(DynBuf *const printb) { } if (!printb->printf("/proc/%i/stat", pid)) { - logg->logError(__FILE__, __LINE__, "gator: error: DynBuf::printf failed"); + logg->logError(GATOR_ERROR "DynBuf::printf failed"); handleException(); } @@ -84,21 +91,35 @@ static int pgrep_gator(DynBuf *const printb) { char *comm = strchr(b.getBuf(), '('); if (comm == NULL) { - logg->logError(__FILE__, __LINE__, "gator: error: parsing stat begin failed"); + logg->logError(GATOR_ERROR "parsing stat comm begin failed"); handleException(); } ++comm; char *const str = strrchr(comm, ')'); if (str == NULL) { - logg->logError(__FILE__, __LINE__, "gator: error: parsing stat end failed"); + logg->logError(GATOR_ERROR "parsing stat comm end failed"); handleException(); } *str = '\0'; - if (strncmp(comm, "gator", 5) == 0) { - // Assume there is only one gator process - return pid; + if (strncmp(comm, "gator", 5) != 0) { + continue; + } + + char state; + const int count = sscanf(str + 2, " %c ", &state); + if (count != 1) { + logg->logError(GATOR_ERROR "parsing stat state failed"); + handleException(); + } + + if (state == 'Z') { + // This gator is a zombie, ignore + continue; } + + // Assume there is only one gator process + return pid; } closedir(proc); @@ -106,73 +127,106 @@ static int pgrep_gator(DynBuf *const printb) { return -1; } -int update(const char *const gatorPath) { - printf("gator: starting\n"); +static bool confirm(const char *const message) { + char buf[1<<10]; + + printf(GATOR_CONFIRM "%s\n", message); + while (fgets(buf, sizeof(buf), stdin) != NULL) { + if (strcmp(buf, "y\n") == 0) { + return true; + } + if (strcmp(buf, "n\n") == 0) { + return false; + } + // Ignore unrecognized input + } + + return false; +} + +void update(const char *const gatorPath) { + printf(GATOR_MSG "starting\n"); int version[3]; if (!getLinuxVersion(version)) { - logg->logError(__FILE__, __LINE__, "gator: error: getLinuxVersion failed"); + logg->logError(GATOR_ERROR "getLinuxVersion failed"); handleException(); } if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(2, 6, 32)) { - logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device."); + logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device."); handleException(); } if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(3, 4, 0)) { - logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device."); - handleException(); - } - - if (access("/sys/module/gator", F_OK) == 0) { - logg->logError(__FILE__, __LINE__, "gator: error: Streamline has detected that the gator kernel module is loaded on your device. Please build an updated version of gator.ko and gatord and install them on your device."); + logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device."); handleException(); } if (geteuid() != 0) { - printf("gator: trying sudo\n"); + printf(GATOR_MSG "trying sudo\n"); execlp("sudo", "sudo", gatorPath, "-u", NULL); // Streamline will provide the password if needed - printf("gator: trying su\n"); + printf(GATOR_MSG "trying su\n"); char buf[1<<10]; - snprintf(buf, sizeof(buf), "%s -u", gatorPath); - execlp("su", "su", "-", "-c", buf, NULL); + /* + * Different versions of su handle additional -c command line options differently and expect the + * arguments in different ways. Try both ways wrapped in a shell. + * + * Then invoke another shell after su as it avoids odd failures on some Android systems + */ + snprintf(buf, sizeof(buf), "su -c \"sh -c '%s -u'\" || su -c sh -c '%s -u'", gatorPath, gatorPath); + execlp("sh", "sh", "-c", buf, NULL); // Streamline will provide the password if needed - logg->logError(__FILE__, __LINE__, "gator: error: Streamline was unable to sudo to root on your device. Please double check passwords, ensure sudo or su work with this user or try a different username."); + logg->logError(GATOR_ERROR "Streamline was unable to sudo to root on your device. Please double check passwords, ensure sudo or su work with this user or try a different username."); handleException(); } - printf("gator: now root\n"); + printf(GATOR_MSG "now root\n"); + + if (access("/sys/module/gator", F_OK) == 0) { + if (!confirm("Streamline has detected that the gator kernel module is loaded on your device. Click yes to switch to user space gator, click no to abort the install.")) { + printf("gator: cancel\n"); + exit(-1); + } + } // setenforce 0 not needed for userspace gator // Kill existing gator - DynBuf gatorStatPath; - int gator_main = pgrep_gator(&gatorStatPath); + DynBuf printb; + int gator_main = pgrep_gator(&printb); if (gator_main > 0) { if (kill(gator_main, SIGTERM) != 0) { - logg->logError(__FILE__, __LINE__, "gator: error: kill SIGTERM failed"); + logg->logError(GATOR_ERROR "kill SIGTERM failed"); + handleException(); + } + if (!printb.printf("/proc/%i/exe", gator_main)) { + logg->logError(GATOR_ERROR "DynBuf::printf failed"); handleException(); } for (int i = 0; ; ++i) { - if (access(gatorStatPath.getBuf(), F_OK) != 0) { + // /proc/<pid>/exe exists but will not be accessible for zombies + if (access(printb.getBuf(), F_OK) != 0) { break; } if (i == 5) { if (kill(gator_main, SIGKILL) != 0) { - logg->logError(__FILE__, __LINE__, "gator: error: kill SIGKILL failed"); + logg->logError(GATOR_ERROR "kill SIGKILL failed"); handleException(); } } else if (i >= 10) { - logg->logError(__FILE__, __LINE__, "gator: error: unable to kill running gator"); + logg->logError(GATOR_ERROR "unable to kill running gator"); handleException(); } sleep(1); } } - printf("gator: no gatord running\n"); + printf(GATOR_MSG "no gatord running\n"); + + umount("/dev/gator"); + syscall(__NR_delete_module, "gator", O_NONBLOCK); rename("gatord", "gatord.old"); rename("gator.ko", "gator.ko.old"); @@ -183,50 +237,88 @@ int update(const char *const gatorPath) { if (dot != NULL) { *dot = '\0'; if (rename(gatorPath, newGatorPath) != 0) { - logg->logError(__FILE__, __LINE__, "gator: error: rename failed"); + logg->logError(GATOR_ERROR "rename failed"); handleException(); } } - // Fork and start gatord (redirect stdout and stderr) + char buf[128]; + int pipefd[2]; + if (pipe_cloexec(pipefd) != 0) { + logg->logError(GATOR_ERROR "pipe failed"); + handleException(); + } + + // Fork and start gatord (redirect stdin, stdout and stderr so shell can close) int child = fork(); if (child < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: fork failed"); + logg->logError(GATOR_ERROR "fork failed"); handleException(); } else if (child == 0) { - int inFd = open("/dev/null", O_RDONLY | O_CLOEXEC); + int inFd; + int outFd; + int errFd; + int result = -1; + + buf[0] = '\0'; + close(pipefd[0]); + + inFd = open("/dev/null", O_RDONLY | O_CLOEXEC); if (inFd < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: open of /dev/null failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "open of /dev/null failed"); + goto fail_exit; } - int outFd = open("gatord.out", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600); + outFd = open("gatord.out", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); if (outFd < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.out failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "open of gatord.out failed"); + goto fail_exit; } - int errFd = open("gatord.err", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600); + errFd = open("gatord.err", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); if (errFd < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.err failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "open of gatord.err failed"); + goto fail_exit; } if (dup2(inFd, STDIN_FILENO) < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdin failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stdin failed"); + goto fail_exit; } + fflush(stdout); if (dup2(outFd, STDOUT_FILENO) < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdout failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stdout failed"); + goto fail_exit; } + fflush(stderr); if (dup2(errFd, STDERR_FILENO) < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stderr failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stderr failed"); + goto fail_exit; } - execlp(newGatorPath, newGatorPath, "-a", NULL); - logg->logError(__FILE__, __LINE__, "gator: error: execlp failed"); - handleException(); + + snprintf(buf, sizeof(buf), GATOR_MSG "done"); + result = 0; + + fail_exit: + if (buf[0] != '\0') { + const ssize_t bytes = write(pipefd[1], buf, sizeof(buf)); + // Can't do anything if this fails + (void)bytes; + } + close(pipefd[1]); + + if (result == 0) { + // Continue to execute gator normally + return; + } + exit(-1); } - printf("gator: done\n"); + close(pipefd[1]); + const ssize_t bytes = read(pipefd[0], buf, sizeof(buf)); + if (bytes > 0) { + logg->logError("%s", buf); + handleException(); + } + close(pipefd[0]); - return 0; + // Exit so parent shell can move on + exit(0); } |