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
17 #include "host/commands/cvd/server_command/fetch.h"
18
19 #include "common/libs/fs/shared_buf.h"
20 #include "common/libs/fs/shared_fd.h"
21 #include "common/libs/utils/contains.h"
22 #include "common/libs/utils/result.h"
23 #include "host/commands/cvd/server_command/server_handler.h"
24 #include "host/commands/cvd/server_command/utils.h"
25 #include "host/commands/cvd/types.h"
26
27 namespace cuttlefish {
28
29 class CvdFetchCommandHandler : public CvdServerHandler {
30 public:
INJECT(CvdFetchCommandHandler (SubprocessWaiter & subprocess_waiter))31 INJECT(CvdFetchCommandHandler(SubprocessWaiter& subprocess_waiter))
32 : subprocess_waiter_(subprocess_waiter),
33 fetch_cmd_list_{std::vector<std::string>{"fetch", "fetch_cvd"}} {}
34
35 Result<bool> CanHandle(const RequestWithStdio& request) const override;
36 Result<cvd::Response> Handle(const RequestWithStdio& request) override;
37 Result<void> Interrupt() override;
CmdList() const38 cvd_common::Args CmdList() const override { return fetch_cmd_list_; }
39
40 private:
41 SubprocessWaiter& subprocess_waiter_;
42 std::mutex interruptible_;
43 bool interrupted_ = false;
44 std::vector<std::string> fetch_cmd_list_;
45 };
46
CanHandle(const RequestWithStdio & request) const47 Result<bool> CvdFetchCommandHandler::CanHandle(
48 const RequestWithStdio& request) const {
49 auto invocation = ParseInvocation(request.Message());
50 return Contains(fetch_cmd_list_, invocation.command);
51 }
52
Handle(const RequestWithStdio & request)53 Result<cvd::Response> CvdFetchCommandHandler::Handle(
54 const RequestWithStdio& request) {
55 std::unique_lock interrupt_lock(interruptible_);
56 if (interrupted_) {
57 return CF_ERR("Interrupted");
58 }
59 CF_EXPECT(CanHandle(request));
60
61 Command command("/proc/self/exe");
62 command.SetName("fetch_cvd");
63 command.SetExecutable("/proc/self/exe");
64
65 for (const auto& argument : ParseInvocation(request.Message()).arguments) {
66 command.AddParameter(argument);
67 }
68
69 command.RedirectStdIO(Subprocess::StdIOChannel::kStdIn, request.In());
70 command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, request.Out());
71 command.RedirectStdIO(Subprocess::StdIOChannel::kStdErr, request.Err());
72 SubprocessOptions options;
73
74 const auto& command_request = request.Message().command_request();
75 if (command_request.wait_behavior() == cvd::WAIT_BEHAVIOR_START) {
76 options.ExitWithParent(false);
77 }
78
79 const auto& working_dir = command_request.working_directory();
80 if (!working_dir.empty()) {
81 auto fd = SharedFD::Open(working_dir, O_RDONLY | O_PATH | O_DIRECTORY);
82 if (fd->IsOpen()) {
83 command.SetWorkingDirectory(fd);
84 }
85 }
86
87 CF_EXPECT(subprocess_waiter_.Setup(command.Start(options)));
88
89 if (command_request.wait_behavior() == cvd::WAIT_BEHAVIOR_START) {
90 cvd::Response response;
91 response.mutable_command_response();
92 response.mutable_status()->set_code(cvd::Status::OK);
93 return response;
94 }
95
96 interrupt_lock.unlock();
97
98 auto infop = CF_EXPECT(subprocess_waiter_.Wait());
99
100 return ResponseFromSiginfo(infop);
101 }
102
Interrupt()103 Result<void> CvdFetchCommandHandler::Interrupt() {
104 std::scoped_lock interrupt_lock(interruptible_);
105 interrupted_ = true;
106 CF_EXPECT(subprocess_waiter_.Interrupt());
107 return {};
108 }
109
110 fruit::Component<fruit::Required<InstanceManager, SubprocessWaiter>>
cvdFetchCommandComponent()111 cvdFetchCommandComponent() {
112 return fruit::createComponent()
113 .addMultibinding<CvdServerHandler, CvdFetchCommandHandler>();
114 }
115
116 } // namespace cuttlefish
117