From 18ddf5c6a233bd56d20548fd834c0ecbf8216410 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 16 Nov 2015 10:55:34 -0800 Subject: [PATCH] Pass $TERM to the device. Unfortunately, this isn't backwards-compatible with the current shell protocol because we made unknown shell: arguments errors. We could try to commit the change to make them just warnings first, but how would we know when everyone was running adbd with that change? Bumping the protocol version doesn't help because that only affects the code running on the host. And although we could add another feature to the reported features, since shell_v2 is still in development, that doesn't seem worthwhile. Bug: http://b/25601436 Change-Id: I12b81aa656cd25b91d14ef691dcbd2b7dab49535 --- adb/commandline.cpp | 7 +++++-- adb/services.cpp | 20 +++++++++++--------- adb/shell_service.cpp | 28 ++++++++++++++++++---------- adb/shell_service.h | 4 ++-- adb/shell_service_test.cpp | 2 +- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/adb/commandline.cpp b/adb/commandline.cpp index 5113eb8a7..c13872a3b 100644 --- a/adb/commandline.cpp +++ b/adb/commandline.cpp @@ -595,6 +595,10 @@ static std::string ShellServiceString(bool use_shell_protocol, if (!type_arg.empty()) { args.push_back(type_arg); } + const char* terminal_type = getenv("TERM"); + if (terminal_type != nullptr) { + args.push_back(std::string("TERM=") + terminal_type); + } // Shell service string can look like: shell[,arg1,arg2,...]:[command]. return android::base::StringPrintf("shell%s%s:%s", @@ -1029,8 +1033,7 @@ static int send_shell_command(TransportType transport_type, const char* serial, use_shell_protocol = CanUseFeature(features, kFeatureShell2); } - std::string service_string = ShellServiceString(use_shell_protocol, "", - command); + std::string service_string = ShellServiceString(use_shell_protocol, "", command); int fd; while (true) { diff --git a/adb/services.cpp b/adb/services.cpp index 19a6726f8..41da4b801 100644 --- a/adb/services.cpp +++ b/adb/services.cpp @@ -213,9 +213,11 @@ static int ShellService(const std::string& args, const atransport* transport) { // Defaults: // PTY for interactive, raw for non-interactive. // No protocol. + // $TERM set to "dumb". SubprocessType type(command.empty() ? SubprocessType::kPty : SubprocessType::kRaw); SubprocessProtocol protocol = SubprocessProtocol::kNone; + std::string terminal_type = "dumb"; for (const std::string& arg : android::base::Split(service_args, ",")) { if (arg == kShellServiceArgRaw) { @@ -224,14 +226,15 @@ static int ShellService(const std::string& args, const atransport* transport) { type = SubprocessType::kPty; } else if (arg == kShellServiceArgShellProtocol) { protocol = SubprocessProtocol::kShell; - } - else if (!arg.empty()) { - LOG(ERROR) << "Unsupported shell service arguments: " << args; - return -1; + } else if (android::base::StartsWith(arg, "TERM=")) { + terminal_type = arg.substr(5); + } else if (!arg.empty()) { + // This is not an error to allow for future expansion. + LOG(WARNING) << "Ignoring unknown shell service argument: " << arg; } } - return StartSubprocess(command.c_str(), type, protocol); + return StartSubprocess(command.c_str(), terminal_type.c_str(), type, protocol); } #endif // !ADB_HOST @@ -308,8 +311,7 @@ int service_to_fd(const char* name, const atransport* transport) { } else if(!strncmp(name, "shell", 5)) { ret = ShellService(name + 5, transport); } else if(!strncmp(name, "exec:", 5)) { - ret = StartSubprocess(name + 5, SubprocessType::kRaw, - SubprocessProtocol::kNone); + ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); } else if(!strncmp(name, "sync:", 5)) { ret = create_service_thread(file_sync_service, NULL); } else if(!strncmp(name, "remount:", 8)) { @@ -325,9 +327,9 @@ int service_to_fd(const char* name, const atransport* transport) { } else if(!strncmp(name, "backup:", 7)) { ret = StartSubprocess(android::base::StringPrintf("/system/bin/bu backup %s", (name + 7)).c_str(), - SubprocessType::kRaw, SubprocessProtocol::kNone); + nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); } else if(!strncmp(name, "restore:", 8)) { - ret = StartSubprocess("/system/bin/bu restore", SubprocessType::kRaw, + ret = StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone); } else if(!strncmp(name, "tcpip:", 6)) { int port; diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp index e3fde2691..2e41fe649 100644 --- a/adb/shell_service.cpp +++ b/adb/shell_service.cpp @@ -175,8 +175,8 @@ bool CreateSocketpair(ScopedFd* fd1, ScopedFd* fd2) { class Subprocess { public: - Subprocess(const std::string& command, SubprocessType type, - SubprocessProtocol protocol); + Subprocess(const std::string& command, const char* terminal_type, + SubprocessType type, SubprocessProtocol protocol); ~Subprocess(); const std::string& command() const { return command_; } @@ -207,6 +207,7 @@ class Subprocess { ScopedFd* PassOutput(ScopedFd* sfd, ShellProtocol::Id id); const std::string command_; + const std::string terminal_type_; SubprocessType type_; SubprocessProtocol protocol_; pid_t pid_ = -1; @@ -220,9 +221,12 @@ class Subprocess { DISALLOW_COPY_AND_ASSIGN(Subprocess); }; -Subprocess::Subprocess(const std::string& command, SubprocessType type, - SubprocessProtocol protocol) - : command_(command), type_(type), protocol_(protocol) { +Subprocess::Subprocess(const std::string& command, const char* terminal_type, + SubprocessType type, SubprocessProtocol protocol) + : command_(command), + terminal_type_(terminal_type ? terminal_type : ""), + type_(type), + protocol_(protocol) { } Subprocess::~Subprocess() { @@ -290,6 +294,9 @@ bool Subprocess::ForkAndExec() { setenv("SHELL", pw->pw_shell, 1); setenv("USER", pw->pw_name, 1); } + if (!terminal_type_.empty()) { + setenv("TERM", terminal_type_.c_str(), 1); + } if (is_interactive()) { execl(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr); @@ -644,13 +651,14 @@ void Subprocess::WaitForExit() { } // namespace -int StartSubprocess(const char *name, SubprocessType type, - SubprocessProtocol protocol) { - D("starting %s subprocess (protocol=%s): '%s'", +int StartSubprocess(const char* name, const char* terminal_type, + SubprocessType type, SubprocessProtocol protocol) { + D("starting %s subprocess (protocol=%s, TERM=%s): '%s'", type == SubprocessType::kRaw ? "raw" : "PTY", - protocol == SubprocessProtocol::kNone ? "none" : "shell", name); + protocol == SubprocessProtocol::kNone ? "none" : "shell", + terminal_type, name); - Subprocess* subprocess = new Subprocess(name, type, protocol); + Subprocess* subprocess = new Subprocess(name, terminal_type, type, protocol); if (!subprocess) { LOG(ERROR) << "failed to allocate new subprocess"; return -1; diff --git a/adb/shell_service.h b/adb/shell_service.h index 63c00da15..6f8ea9b01 100644 --- a/adb/shell_service.h +++ b/adb/shell_service.h @@ -141,8 +141,8 @@ enum class SubprocessProtocol { // shell is started, otherwise |name| is executed non-interactively. // // Returns an open FD connected to the subprocess or -1 on failure. -int StartSubprocess(const char* name, SubprocessType type, - SubprocessProtocol protocol); +int StartSubprocess(const char* name, const char* terminal_type, + SubprocessType type, SubprocessProtocol protocol); #endif // !ADB_HOST diff --git a/adb/shell_service_test.cpp b/adb/shell_service_test.cpp index e18f905e6..a012f3e90 100644 --- a/adb/shell_service_test.cpp +++ b/adb/shell_service_test.cpp @@ -69,7 +69,7 @@ void ShellServiceTest::StartTestSubprocess( SHELL_EXIT_NOTIFY_FD = fd[0]; shell_exit_receiver_fd_ = fd[1]; - subprocess_fd_ = StartSubprocess(command, type, protocol); + subprocess_fd_ = StartSubprocess(command, nullptr, type, protocol); ASSERT_TRUE(subprocess_fd_ >= 0); }