• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2022 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 #include "host/commands/cvd/command_sequence.h"
17 
18 #include <fruit/fruit.h>
19 
20 #include "common/libs/fs/shared_buf.h"
21 #include "host/commands/cvd/server.h"
22 #include "host/commands/cvd/server_client.h"
23 
24 namespace cuttlefish {
25 namespace {
26 
BashEscape(const std::string & input)27 std::string BashEscape(const std::string& input) {
28   bool safe = true;
29   for (const auto& c : input) {
30     if ('0' <= c && c <= '9') {
31       continue;
32     }
33     if ('a' <= c && c <= 'z') {
34       continue;
35     }
36     if ('A' <= c && c <= 'Z') {
37       continue;
38     }
39     if (c == '_' || c == '-' || c == '.' || c == ',' || c == '/') {
40       continue;
41     }
42     safe = false;
43   }
44   using android::base::StringReplace;
45   return safe ? input : "'" + StringReplace(input, "'", "\\'", true) + "'";
46 }
47 
FormattedCommand(const cvd::CommandRequest command)48 std::string FormattedCommand(const cvd::CommandRequest command) {
49   std::stringstream effective_command;
50   effective_command << "Executing `";
51   for (const auto& [name, val] : command.env()) {
52     effective_command << BashEscape(name) << "=" << BashEscape(val) << " ";
53   }
54   for (const auto& argument : command.args()) {
55     effective_command << BashEscape(argument) << " ";
56   }
57   effective_command.seekp(-1, effective_command.cur);
58   effective_command << "`\n";  // Overwrite last space
59   return effective_command.str();
60 }
61 
62 }  // namespace
63 
CommandSequenceExecutor(CvdCommandHandler & inner_handler)64 CommandSequenceExecutor::CommandSequenceExecutor(
65     CvdCommandHandler& inner_handler)
66     : inner_handler_(inner_handler) {}
67 
Interrupt()68 Result<void> CommandSequenceExecutor::Interrupt() {
69   CF_EXPECT(inner_handler_.Interrupt());
70   return {};
71 }
72 
Execute(const std::vector<RequestWithStdio> & requests,SharedFD report)73 Result<void> CommandSequenceExecutor::Execute(
74     const std::vector<RequestWithStdio>& requests, SharedFD report) {
75   std::unique_lock interrupt_lock(interrupt_mutex_);
76   if (interrupted_) {
77     return CF_ERR("Interrupted");
78   }
79   for (const auto& request : requests) {
80     auto& inner_proto = request.Message();
81     CF_EXPECT(inner_proto.has_command_request());
82     auto& command = inner_proto.command_request();
83     std::string str = FormattedCommand(command);
84     CF_EXPECT(WriteAll(report, str) == str.size(), report->StrError());
85 
86     interrupt_lock.unlock();
87     auto response = CF_EXPECT(inner_handler_.Handle(request));
88     interrupt_lock.lock();
89     if (interrupted_) {
90       return CF_ERR("Interrupted");
91     }
92     CF_EXPECT(response.status().code() == cvd::Status::OK,
93               "Reason: \"" << response.status().message() << "\"");
94 
95     static const char kDoneMsg[] = "Done\n";
96     CF_EXPECT(WriteAll(request.Err(), kDoneMsg) == sizeof(kDoneMsg) - 1,
97               request.Err()->StrError());
98   }
99   return {};
100 }
101 
102 }  // namespace cuttlefish
103