Loading adb/commandline.cpp +45 −26 Original line number Original line Diff line number Diff line Loading @@ -467,6 +467,7 @@ struct StdinReadArgs { int stdin_fd, write_fd; int stdin_fd, write_fd; bool raw_stdin; bool raw_stdin; std::unique_ptr<ShellProtocol> protocol; std::unique_ptr<ShellProtocol> protocol; char escape_char; }; }; // Loops to read from stdin and push the data to the given FD. // Loops to read from stdin and push the data to the given FD. Loading @@ -474,7 +475,6 @@ struct StdinReadArgs { // will take ownership of the object and delete it when finished. // will take ownership of the object and delete it when finished. static void* stdin_read_thread_loop(void* x) { static void* stdin_read_thread_loop(void* x) { std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x)); std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x)); int state = 0; #if !defined(_WIN32) #if !defined(_WIN32) // Mask SIGTTIN in case we're in a backgrounded process. // Mask SIGTTIN in case we're in a backgrounded process. Loading @@ -496,7 +496,7 @@ static void* stdin_read_thread_loop(void* x) { // Set up the initial window size. // Set up the initial window size. send_window_size_change(args->stdin_fd, args->protocol); send_window_size_change(args->stdin_fd, args->protocol); char raw_buffer[1024]; char raw_buffer[BUFSIZ]; char* buffer_ptr = raw_buffer; char* buffer_ptr = raw_buffer; size_t buffer_size = sizeof(raw_buffer); size_t buffer_size = sizeof(raw_buffer); if (args->protocol != nullptr) { if (args->protocol != nullptr) { Loading @@ -504,6 +504,14 @@ static void* stdin_read_thread_loop(void* x) { buffer_size = args->protocol->data_capacity(); 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) { while (true) { // Use unix_read() rather than adb_read() for stdin. // Use unix_read() rather than adb_read() for stdin. D("stdin_read_thread_loop(): pre unix_read(fdi=%d,...)", args->stdin_fd); D("stdin_read_thread_loop(): pre unix_read(fdi=%d,...)", args->stdin_fd); Loading @@ -529,36 +537,36 @@ static void* stdin_read_thread_loop(void* x) { } } break; 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 // this situation signals like Ctrl+C are sent remotely rather than // interpreted locally so this provides an emergency out if the remote // interpreted locally so this provides an emergency out if the remote // process starts ignoring the signal. SSH also does this, see the // process starts ignoring the signal. SSH also does this, see the // "escape characters" section on the ssh man page for more info. // "escape characters" section on the ssh man page for more info. if (args->raw_stdin) { if (args->raw_stdin && args->escape_char != '\0') { for (int n = 0; n < r; n++) { char ch = buffer_ptr[0]; switch (buffer_ptr[n]) { if (ch == args->escape_char) { case '\n': if (state == kStartOfLine) { state = 1; state = kInEscape; break; // Swallow the escape character. case '\r': continue; state = 1; break; case '~': if (state == 1) { state++; } else { } else { state = 0; state = kMidFlow; } } break; } else { case '.': if (state == kInEscape) { if (state == 2) { if (ch == '.') { fprintf(stderr,"\r\n* disconnect *\r\n"); fprintf(stderr,"\r\n[ disconnected ]\r\n"); stdin_raw_restore(); stdin_raw_restore(); exit(0); 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) { if (args->protocol) { Loading Loading @@ -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, // On success returns the remote exit code if |use_shell_protocol| is true, // 0 otherwise. On failure returns 1. // 0 otherwise. On failure returns 1. static int RemoteShell(bool use_shell_protocol, const std::string& type_arg, static int RemoteShell(bool use_shell_protocol, const std::string& type_arg, char escape_char, const std::string& command) { const std::string& command) { std::string service_string = ShellServiceString(use_shell_protocol, std::string service_string = ShellServiceString(use_shell_protocol, type_arg, command); type_arg, command); Loading @@ -628,6 +637,7 @@ static int RemoteShell(bool use_shell_protocol, const std::string& type_arg, args->stdin_fd = STDIN_FILENO; args->stdin_fd = STDIN_FILENO; args->write_fd = fd; args->write_fd = fd; args->raw_stdin = raw_stdin; args->raw_stdin = raw_stdin; args->escape_char = escape_char; if (use_shell_protocol) { if (use_shell_protocol) { args->protocol.reset(new ShellProtocol(args->write_fd)); args->protocol.reset(new ShellProtocol(args->write_fd)); } } Loading Loading @@ -689,8 +699,17 @@ static int adb_shell(int argc, const char** argv, --argc; --argc; ++argv; ++argv; int t_arg_count = 0; int t_arg_count = 0; char escape_char = '~'; while (argc) { 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)) { if (!CanUseFeature(features, kFeatureShell2)) { fprintf(stderr, "error: target doesn't support PTY args -Tt\n"); fprintf(stderr, "error: target doesn't support PTY args -Tt\n"); return 1; return 1; Loading Loading @@ -746,7 +765,7 @@ static int adb_shell(int argc, const char** argv, command = android::base::Join(std::vector<const char*>(argv, argv + argc), ' '); 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, static int adb_download_buffer(const char *service, const char *fn, const void* data, unsigned sz, Loading Loading
adb/commandline.cpp +45 −26 Original line number Original line Diff line number Diff line Loading @@ -467,6 +467,7 @@ struct StdinReadArgs { int stdin_fd, write_fd; int stdin_fd, write_fd; bool raw_stdin; bool raw_stdin; std::unique_ptr<ShellProtocol> protocol; std::unique_ptr<ShellProtocol> protocol; char escape_char; }; }; // Loops to read from stdin and push the data to the given FD. // Loops to read from stdin and push the data to the given FD. Loading @@ -474,7 +475,6 @@ struct StdinReadArgs { // will take ownership of the object and delete it when finished. // will take ownership of the object and delete it when finished. static void* stdin_read_thread_loop(void* x) { static void* stdin_read_thread_loop(void* x) { std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x)); std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x)); int state = 0; #if !defined(_WIN32) #if !defined(_WIN32) // Mask SIGTTIN in case we're in a backgrounded process. // Mask SIGTTIN in case we're in a backgrounded process. Loading @@ -496,7 +496,7 @@ static void* stdin_read_thread_loop(void* x) { // Set up the initial window size. // Set up the initial window size. send_window_size_change(args->stdin_fd, args->protocol); send_window_size_change(args->stdin_fd, args->protocol); char raw_buffer[1024]; char raw_buffer[BUFSIZ]; char* buffer_ptr = raw_buffer; char* buffer_ptr = raw_buffer; size_t buffer_size = sizeof(raw_buffer); size_t buffer_size = sizeof(raw_buffer); if (args->protocol != nullptr) { if (args->protocol != nullptr) { Loading @@ -504,6 +504,14 @@ static void* stdin_read_thread_loop(void* x) { buffer_size = args->protocol->data_capacity(); 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) { while (true) { // Use unix_read() rather than adb_read() for stdin. // Use unix_read() rather than adb_read() for stdin. D("stdin_read_thread_loop(): pre unix_read(fdi=%d,...)", args->stdin_fd); D("stdin_read_thread_loop(): pre unix_read(fdi=%d,...)", args->stdin_fd); Loading @@ -529,36 +537,36 @@ static void* stdin_read_thread_loop(void* x) { } } break; 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 // this situation signals like Ctrl+C are sent remotely rather than // interpreted locally so this provides an emergency out if the remote // interpreted locally so this provides an emergency out if the remote // process starts ignoring the signal. SSH also does this, see the // process starts ignoring the signal. SSH also does this, see the // "escape characters" section on the ssh man page for more info. // "escape characters" section on the ssh man page for more info. if (args->raw_stdin) { if (args->raw_stdin && args->escape_char != '\0') { for (int n = 0; n < r; n++) { char ch = buffer_ptr[0]; switch (buffer_ptr[n]) { if (ch == args->escape_char) { case '\n': if (state == kStartOfLine) { state = 1; state = kInEscape; break; // Swallow the escape character. case '\r': continue; state = 1; break; case '~': if (state == 1) { state++; } else { } else { state = 0; state = kMidFlow; } } break; } else { case '.': if (state == kInEscape) { if (state == 2) { if (ch == '.') { fprintf(stderr,"\r\n* disconnect *\r\n"); fprintf(stderr,"\r\n[ disconnected ]\r\n"); stdin_raw_restore(); stdin_raw_restore(); exit(0); 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) { if (args->protocol) { Loading Loading @@ -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, // On success returns the remote exit code if |use_shell_protocol| is true, // 0 otherwise. On failure returns 1. // 0 otherwise. On failure returns 1. static int RemoteShell(bool use_shell_protocol, const std::string& type_arg, static int RemoteShell(bool use_shell_protocol, const std::string& type_arg, char escape_char, const std::string& command) { const std::string& command) { std::string service_string = ShellServiceString(use_shell_protocol, std::string service_string = ShellServiceString(use_shell_protocol, type_arg, command); type_arg, command); Loading @@ -628,6 +637,7 @@ static int RemoteShell(bool use_shell_protocol, const std::string& type_arg, args->stdin_fd = STDIN_FILENO; args->stdin_fd = STDIN_FILENO; args->write_fd = fd; args->write_fd = fd; args->raw_stdin = raw_stdin; args->raw_stdin = raw_stdin; args->escape_char = escape_char; if (use_shell_protocol) { if (use_shell_protocol) { args->protocol.reset(new ShellProtocol(args->write_fd)); args->protocol.reset(new ShellProtocol(args->write_fd)); } } Loading Loading @@ -689,8 +699,17 @@ static int adb_shell(int argc, const char** argv, --argc; --argc; ++argv; ++argv; int t_arg_count = 0; int t_arg_count = 0; char escape_char = '~'; while (argc) { 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)) { if (!CanUseFeature(features, kFeatureShell2)) { fprintf(stderr, "error: target doesn't support PTY args -Tt\n"); fprintf(stderr, "error: target doesn't support PTY args -Tt\n"); return 1; return 1; Loading Loading @@ -746,7 +765,7 @@ static int adb_shell(int argc, const char** argv, command = android::base::Join(std::vector<const char*>(argv, argv + argc), ' '); 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, static int adb_download_buffer(const char *service, const char *fn, const void* data, unsigned sz, Loading