Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a55d6810 authored by Elliott Hughes's avatar Elliott Hughes Committed by android-build-merger
Browse files

Merge "Fix adb shell escape handling."

am: 79964cdf

* commit '79964cdf':
  Fix adb shell escape handling.
parents b1b09650 79964cdf
Loading
Loading
Loading
Loading
+45 −26
Original line number Diff line number Diff line
@@ -467,6 +467,7 @@ struct StdinReadArgs {
    int stdin_fd, write_fd;
    bool raw_stdin;
    std::unique_ptr<ShellProtocol> protocol;
    char escape_char;
};

// Loops to read from stdin and push the data to the given FD.
@@ -474,7 +475,6 @@ struct StdinReadArgs {
// will take ownership of the object and delete it when finished.
static void* stdin_read_thread_loop(void* x) {
    std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x));
    int state = 0;

#if !defined(_WIN32)
    // Mask SIGTTIN in case we're in a backgrounded process.
@@ -496,7 +496,7 @@ static void* stdin_read_thread_loop(void* x) {
    // Set up the initial window size.
    send_window_size_change(args->stdin_fd, args->protocol);

    char raw_buffer[1024];
    char raw_buffer[BUFSIZ];
    char* buffer_ptr = raw_buffer;
    size_t buffer_size = sizeof(raw_buffer);
    if (args->protocol != nullptr) {
@@ -504,6 +504,14 @@ static void* stdin_read_thread_loop(void* x) {
        buffer_size = args->protocol->data_capacity();
    }

    // If we need to parse escape sequences, make life easy.
    if (args->raw_stdin && args->escape_char != '\0') {
        buffer_size = 1;
    }

    enum EscapeState { kMidFlow, kStartOfLine, kInEscape };
    EscapeState state = kStartOfLine;

    while (true) {
        // Use unix_read() rather than adb_read() for stdin.
        D("stdin_read_thread_loop(): pre unix_read(fdi=%d,...)", args->stdin_fd);
@@ -529,36 +537,36 @@ static void* stdin_read_thread_loop(void* x) {
            }
            break;
        }
        // If we made stdin raw, check input for the "~." escape sequence. In
        // If we made stdin raw, check input for escape sequences. In
        // this situation signals like Ctrl+C are sent remotely rather than
        // interpreted locally so this provides an emergency out if the remote
        // process starts ignoring the signal. SSH also does this, see the
        // "escape characters" section on the ssh man page for more info.
        if (args->raw_stdin) {
            for (int n = 0; n < r; n++) {
                switch (buffer_ptr[n]) {
                case '\n':
                    state = 1;
                    break;
                case '\r':
                    state = 1;
                    break;
                case '~':
                    if (state == 1) {
                        state++;
        if (args->raw_stdin && args->escape_char != '\0') {
            char ch = buffer_ptr[0];
            if (ch == args->escape_char) {
                if (state == kStartOfLine) {
                    state = kInEscape;
                    // Swallow the escape character.
                    continue;
                } else {
                        state = 0;
                    state = kMidFlow;
                }
                    break;
                case '.':
                    if (state == 2) {
                        fprintf(stderr,"\r\n* disconnect *\r\n");
            } else {
                if (state == kInEscape) {
                    if (ch == '.') {
                        fprintf(stderr,"\r\n[ disconnected ]\r\n");
                        stdin_raw_restore();
                        exit(0);
                    } else {
                        // We swallowed an escape character that wasn't part of
                        // a valid escape sequence; time to cough it up.
                        buffer_ptr[0] = args->escape_char;
                        buffer_ptr[1] = ch;
                        ++r;
                    }
                default:
                    state = 0;
                }
                state = (ch == '\n' || ch == '\r') ? kStartOfLine : kMidFlow;
            }
        }
        if (args->protocol) {
@@ -603,6 +611,7 @@ static std::string ShellServiceString(bool use_shell_protocol,
// On success returns the remote exit code if |use_shell_protocol| is true,
// 0 otherwise. On failure returns 1.
static int RemoteShell(bool use_shell_protocol, const std::string& type_arg,
                       char escape_char,
                       const std::string& command) {
    std::string service_string = ShellServiceString(use_shell_protocol,
                                                    type_arg, command);
@@ -628,6 +637,7 @@ static int RemoteShell(bool use_shell_protocol, const std::string& type_arg,
    args->stdin_fd = STDIN_FILENO;
    args->write_fd = fd;
    args->raw_stdin = raw_stdin;
    args->escape_char = escape_char;
    if (use_shell_protocol) {
        args->protocol.reset(new ShellProtocol(args->write_fd));
    }
@@ -689,8 +699,17 @@ static int adb_shell(int argc, const char** argv,
    --argc;
    ++argv;
    int t_arg_count = 0;
    char escape_char = '~';
    while (argc) {
        if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
        if (!strcmp(argv[0], "-e")) {
            if (argc < 2 || !(strlen(argv[1]) == 1 || strcmp(argv[1], "none") == 0)) {
                fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
                return 1;
            }
            escape_char = (strcmp(argv[1], "none") == 0) ? 0 : argv[1][0];
            argc -= 2;
            argv += 2;
        } else if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
            if (!CanUseFeature(features, kFeatureShell2)) {
                fprintf(stderr, "error: target doesn't support PTY args -Tt\n");
                return 1;
@@ -746,7 +765,7 @@ static int adb_shell(int argc, const char** argv,
        command = android::base::Join(std::vector<const char*>(argv, argv + argc), ' ');
    }

    return RemoteShell(use_shell_protocol, shell_type_arg, command);
    return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command);
}

static int adb_download_buffer(const char *service, const char *fn, const void* data, unsigned sz,