| /* | 
 |  * Copyright (C) 2018 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include <sys/wait.h> | 
 |  | 
 | #include <android-base/cmsg.h> | 
 | #include <android-base/strings.h> | 
 | #include <cmd.h> | 
 |  | 
 | #include "adb.h" | 
 | #include "adb_io.h" | 
 | #include "adb_utils.h" | 
 | #include "shell_service.h" | 
 |  | 
 | namespace { | 
 |  | 
 | class AdbFdTextOutput : public android::TextOutput { | 
 |   public: | 
 |     explicit AdbFdTextOutput(borrowed_fd fd) : fd_(fd) {} | 
 |  | 
 |   private: | 
 |     android::status_t print(const char* txt, size_t len) override { | 
 |         return WriteFdExactly(fd_, txt, len) ? android::OK : -errno; | 
 |     } | 
 |     void moveIndent(int delta) override { /*not implemented*/ | 
 |     } | 
 |  | 
 |     void pushBundle() override { /*not implemented*/ | 
 |     } | 
 |     void popBundle() override { /*not implemented*/ | 
 |     } | 
 |  | 
 |   private: | 
 |     borrowed_fd fd_; | 
 | }; | 
 |  | 
 | std::vector<std::string_view> parseCmdArgs(std::string_view args) { | 
 |     std::vector<std::string_view> argv; | 
 |  | 
 |     char delim = ABB_ARG_DELIMETER; | 
 |     size_t size = args.size(); | 
 |     size_t base = 0; | 
 |     while (base < size) { | 
 |         size_t found; | 
 |         for (found = base; found < size && args[found] && args[found] != delim; ++found) | 
 |             ; | 
 |         if (found > base) { | 
 |             argv.emplace_back(args.substr(base, found - base)); | 
 |         } | 
 |         base = found + 1; | 
 |     } | 
 |  | 
 |     return argv; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | static int execCmd(std::string_view args, borrowed_fd in, borrowed_fd out, borrowed_fd err) { | 
 |     AdbFdTextOutput oin(out); | 
 |     AdbFdTextOutput oerr(err); | 
 |     return cmdMain(parseCmdArgs(args), oin, oerr, in.get(), out.get(), err.get(), | 
 |                    RunMode::kLibrary); | 
 | } | 
 |  | 
 | int main(int argc, char* const argv[]) { | 
 |     signal(SIGPIPE, SIG_IGN); | 
 |  | 
 |     int fd = STDIN_FILENO; | 
 |     std::string data; | 
 |     while (true) { | 
 |         std::string error; | 
 |         if (!ReadProtocolString(fd, &data, &error)) { | 
 |             PLOG(ERROR) << "Failed to read message: " << error; | 
 |             break; | 
 |         } | 
 |  | 
 |         std::string_view name = data; | 
 |         auto protocol = SubprocessProtocol::kShell; | 
 |         if (android::base::ConsumePrefix(&name, "abb:")) { | 
 |             protocol = SubprocessProtocol::kShell; | 
 |         } else if (android::base::ConsumePrefix(&name, "abb_exec:")) { | 
 |             protocol = SubprocessProtocol::kNone; | 
 |         } else { | 
 |             LOG(FATAL) << "Unknown command prefix for abb: " << data; | 
 |         } | 
 |  | 
 |         unique_fd result = StartCommandInProcess(std::string(name), &execCmd, protocol); | 
 |         if (android::base::SendFileDescriptors(fd, "", 1, result.get()) != 1) { | 
 |             PLOG(ERROR) << "Failed to send an inprocess fd for command: " << data; | 
 |             break; | 
 |         } | 
 |     } | 
 | } |