• 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 
17 #include "host/commands/cvd/server.h"
18 
19 #include <mutex>
20 
21 #include "common/libs/fs/shared_buf.h"
22 #include "host/commands/cvd/command_sequence.h"
23 #include "host/commands/cvd/server_command/utils.h"
24 #include "host/commands/cvd/types.h"
25 #include "host/libs/config/inject.h"
26 
27 namespace cuttlefish {
28 
29 static constexpr char kHelpMessage[] = R"(Cuttlefish Virtual Device (CVD) CLI.
30 
31 usage: cvd <selector/driver options> <command> <args>
32 
33 Selector Options:
34   -group_name <name>     Specify the name of the instance group created
35                          or selected.
36   -instance_name <name>  Selects the device of the given name to perform the
37                          commands for.
38   -instance_name <names> Takes the names of the devices to create within an
39                          instance group. The 'names' is comma-separated.
40 
41 Driver Options:
42   --help                 Print this message
43   -disable_default_group If the flag is true, the group's runtime files are
44                          not populated under the user's HOME. Instead the
45                          files are created under an automatically-generated
46                          directory. (default: false)
47   -acquire_file_lock     If the flag is given, the cvd server attempts to
48                          acquire the instance lock file lock. (default: true)
49 
50 Commands:
51   help                   Print this message.
52   help <command>         Print help for a command.
53   start                  Start a device.
54   stop                   Stop a running device.
55   clear                  Stop all running devices and delete all instance and
56                          assembly directories.
57   fleet                  View the current fleet status.
58   kill-server            Kill the cvd_server background process.
59   server-kill            Same as kill-server
60   powerwash              Delivers powerwash command to the selected device
61   restart                Restart the device without reinitializing the disks
62   restart-server         Restart the cvd_server background process.
63   status                 Check and print the state of a running instance.
64   host_bugreport         Capture a host bugreport, including configs, logs, and
65                          tombstones.
66 
67 Args:
68   <command args>         Each command has its own set of args.
69                          See cvd help <command>.
70 
71 Experimental:
72   reset                  See cvd reset --help. Requires cvd >= v1.2
73 )";
74 
75 class CvdHelpHandler : public CvdServerHandler {
76  public:
INJECT(CvdHelpHandler (CommandSequenceExecutor & executor))77   INJECT(CvdHelpHandler(CommandSequenceExecutor& executor))
78       : executor_(executor) {}
79 
CanHandle(const RequestWithStdio & request) const80   Result<bool> CanHandle(const RequestWithStdio& request) const override {
81     auto invocation = ParseInvocation(request.Message());
82     return (invocation.command == "help");
83   }
84 
Handle(const RequestWithStdio & request)85   Result<cvd::Response> Handle(const RequestWithStdio& request) override {
86     std::unique_lock interrupt_lock(interruptible_);
87     if (interrupted_) {
88       return CF_ERR("Interrupted");
89     }
90 
91     cvd::Response response;
92     response.mutable_command_response();  // Sets oneof member
93     response.mutable_status()->set_code(cvd::Status::OK);
94 
95     CF_EXPECT(CanHandle(request));
96 
97     auto [subcmd, subcmd_args] = ParseInvocation(request.Message());
98     const auto supported_subcmd_list = executor_.CmdList();
99 
100     /*
101      * cvd help, cvd help invalid_token, cvd help help
102      */
103     if (subcmd_args.empty() ||
104         !Contains(supported_subcmd_list, subcmd_args.front()) ||
105         subcmd_args.front() == "help") {
106       WriteAll(request.Out(), kHelpMessage);
107       return response;
108     }
109 
110     cvd::Request modified_proto = HelpSubcommandToFlag(request);
111 
112     RequestWithStdio inner_cmd(request.Client(), modified_proto,
113                                request.FileDescriptors(),
114                                request.Credentials());
115 
116     interrupt_lock.unlock();
117     executor_.Execute({inner_cmd}, SharedFD::Open("/dev/null", O_RDWR));
118 
119     return response;
120   }
121 
Interrupt()122   Result<void> Interrupt() override {
123     std::scoped_lock interrupt_lock(interruptible_);
124     interrupted_ = true;
125     CF_EXPECT(executor_.Interrupt());
126     return {};
127   }
128 
CmdList() const129   cvd_common::Args CmdList() const override { return {"help"}; }
130 
131  private:
132   cvd::Request HelpSubcommandToFlag(const RequestWithStdio& request);
133 
134   std::mutex interruptible_;
135   bool interrupted_ = false;
136   CommandSequenceExecutor& executor_;
137 };
138 
HelpSubcommandToFlag(const RequestWithStdio & request)139 cvd::Request CvdHelpHandler::HelpSubcommandToFlag(
140     const RequestWithStdio& request) {
141   cvd::Request modified_proto = request.Message();
142   auto all_args =
143       cvd_common::ConvertToArgs(modified_proto.command_request().args());
144   auto& args = *modified_proto.mutable_command_request()->mutable_args();
145   args.Clear();
146   // there must be one or more "help" in all_args
147   // delete the first "help"
148   bool found_help = false;
149   for (const auto& cmd_arg : all_args) {
150     if (cmd_arg != "help" || found_help) {
151       args.Add(cmd_arg.c_str());
152       continue;
153     }
154     // skip first help
155     found_help = true;
156   }
157   args.Add("--help");
158   return modified_proto;
159 }
160 
CvdHelpComponent()161 fruit::Component<fruit::Required<CommandSequenceExecutor>> CvdHelpComponent() {
162   return fruit::createComponent()
163       .addMultibinding<CvdServerHandler, CvdHelpHandler>();
164 }
165 
166 }  // namespace cuttlefish
167