Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | /* Utility that uses an adb connection as the login shell. */ |
| 18 | |
Ryan Haining | 7338d35 | 2018-10-24 17:41:52 -0700 | [diff] [blame] | 19 | #include "host/libs/config/cuttlefish_config.h" |
| 20 | |
Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 21 | #include <array> |
| 22 | #include <cassert> |
| 23 | #include <cstdio> |
Ryan Haining | 7338d35 | 2018-10-24 17:41:52 -0700 | [diff] [blame] | 24 | #include <cstdlib> |
Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 25 | #include <cstring> |
| 26 | #include <string> |
| 27 | #include <vector> |
Greg Hartman | fb1b5dc | 2018-12-21 09:58:11 -0800 | [diff] [blame] | 28 | |
| 29 | #include <errno.h> |
Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 30 | #include <unistd.h> |
| 31 | |
| 32 | // Many of our users interact with CVDs via ssh. They expect to be able to |
| 33 | // get an Android shell (as opposed to the host shell) with a single command. |
| 34 | // |
| 35 | // Our goals are to: |
| 36 | // |
| 37 | // * Allow the user to select which CVD to connect to |
| 38 | // |
| 39 | // * Avoid modifications to the host-side sshd and the protocol |
| 40 | // |
| 41 | // We accomplish this by using specialized accounts: vsoc-## and cvd-## and |
| 42 | // specific Android serial numbers: |
| 43 | // |
| 44 | // The vsoc-01 account provides a host-side shell that controls the first CVD |
| 45 | // The cvd-01 account is connected to the Andorid shell of the first CVD |
| 46 | // The first CVD has a serial number of CUTTLEFISHCVD01 |
| 47 | // |
| 48 | // The code in the commands/launch directory also follows these conventions by |
| 49 | // default. |
| 50 | // |
| 51 | |
| 52 | namespace { |
Ryan Haining | 7338d35 | 2018-10-24 17:41:52 -0700 | [diff] [blame] | 53 | std::string VsocUser() { |
| 54 | const char* user_cstring = std::getenv("USER"); |
| 55 | assert(user_cstring != nullptr); |
| 56 | std::string user(user_cstring); |
Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 57 | |
Ryan Haining | 7338d35 | 2018-10-24 17:41:52 -0700 | [diff] [blame] | 58 | std::string cvd_prefix = "cvd-"; |
| 59 | if (user.find(cvd_prefix) == 0) { |
| 60 | user.replace(0, cvd_prefix.size(), vsoc::kVsocUserPrefix); |
Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 61 | } |
Ryan Haining | 7338d35 | 2018-10-24 17:41:52 -0700 | [diff] [blame] | 62 | return user; |
Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 63 | } |
| 64 | |
Ryan Haining | 7338d35 | 2018-10-24 17:41:52 -0700 | [diff] [blame] | 65 | std::string CuttlefishConfigLocation() { |
| 66 | return std::string("/home/") + VsocUser() + |
| 67 | "/cuttlefish_runtime/cuttlefish_config.json"; |
| 68 | } |
| 69 | |
Greg Hartman | fb1b5dc | 2018-12-21 09:58:11 -0800 | [diff] [blame] | 70 | std::string CuttlefishFindAdb() { |
| 71 | std::string rval = std::string("/home/") + VsocUser() + "/bin/adb"; |
| 72 | if (TEMP_FAILURE_RETRY(access(rval.c_str(), X_OK)) == -1) { |
| 73 | return "/usr/bin/adb"; |
| 74 | } |
| 75 | return rval; |
| 76 | } |
| 77 | |
Ryan Haining | 7338d35 | 2018-10-24 17:41:52 -0700 | [diff] [blame] | 78 | void SetCuttlefishConfigEnv() { |
| 79 | setenv(vsoc::kCuttlefishConfigEnvVarName, CuttlefishConfigLocation().c_str(), |
| 80 | true); |
| 81 | } |
Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 82 | } // namespace |
| 83 | |
| 84 | int main(int argc, char* argv[]) { |
Ryan Haining | 7338d35 | 2018-10-24 17:41:52 -0700 | [diff] [blame] | 85 | SetCuttlefishConfigEnv(); |
Cody Schuffelen | 47c5785 | 2019-12-13 13:50:50 -0800 | [diff] [blame] | 86 | auto instance = vsoc::CuttlefishConfig::Get() |
| 87 | ->ForDefaultInstance().adb_device_name(); |
Greg Hartman | fb1b5dc | 2018-12-21 09:58:11 -0800 | [diff] [blame] | 88 | std::string adb_path = CuttlefishFindAdb(); |
Ryan Haining | 7338d35 | 2018-10-24 17:41:52 -0700 | [diff] [blame] | 89 | |
Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 90 | std::vector<char*> new_argv = { |
Greg Hartman | fb1b5dc | 2018-12-21 09:58:11 -0800 | [diff] [blame] | 91 | const_cast<char*>(adb_path.c_str()), const_cast<char*>("-s"), |
Ryan Haining | e58ecd9 | 2018-07-13 15:16:14 -0700 | [diff] [blame] | 92 | const_cast<char*>(instance.c_str()), const_cast<char*>("shell"), |
| 93 | const_cast<char*>("/system/bin/sh")}; |
| 94 | |
| 95 | // Some important data is lost before this point, and there are |
| 96 | // no great recovery options: |
| 97 | // * ssh with no arguments comes in with 1 arg of -adbshell. The command |
| 98 | // given above does the right thing if we don't invoke the shell. |
| 99 | if (argc == 1) { |
| 100 | new_argv.back() = nullptr; |
| 101 | } |
| 102 | // * simple shell commands come in with a -c and a single string. The |
| 103 | // problem here is that adb doesn't preserve spaces, so we need |
| 104 | // to do additional escaping. The best compromise seems to be to |
| 105 | // throw double quotes around each string. |
| 106 | for (int i = 1; i < argc; ++i) { |
| 107 | size_t buf_size = std::strlen(argv[i]) + 4; |
| 108 | new_argv.push_back(new char[buf_size]); |
| 109 | std::snprintf(new_argv.back(), buf_size, "\"%s\"", argv[i]); |
| 110 | } |
| 111 | // |
| 112 | // * scp seems to be pathologically broken when paths contain spaces. |
| 113 | // spaces aren't properly escaped by gcloud, so scp will fail with |
| 114 | // "scp: with ambiguous target." We might be able to fix this with |
| 115 | // some creative parsing of the arguments, but that seems like |
| 116 | // overkill. |
| 117 | new_argv.push_back(nullptr); |
| 118 | execv(new_argv[0], new_argv.data()); |
| 119 | // This never should happen |
| 120 | return 2; |
| 121 | } |