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 <iostream>
18 
19 #include <android-base/logging.h>
20 #include <android-base/strings.h>
21 
22 #include "common/libs/utils/result.h"
23 #include "host/libs/config/cuttlefish_config.h"
24 #include "host/libs/control_env/grpc_service_handler.h"
25 
26 namespace cuttlefish {
27 namespace {
28 
29 constexpr char kCvdEnvHelpMessage[] =
30     "cvd env: cuttlefish environment controller\n"
31     "  e.g. Wmediumd & OpenWRT for Wifi, GNSS for geolocation\n"
32     "\n"
33     "Please visit following link for the more information.\n"
34     "https://source.android.com/docs/setup/create/"
35     "cuttlefish-control-environment\n"
36     "\n"
37     "Basic usage: cvd [SELECTOR_OPTIONS] env [SUBCOMMAND] [ARGS]\n"
38     "\n"
39     "Subcommands:\n"
40     "  ls: List available services or methods\n"
41     "    Get a list of all services:\n"
42     "      Usage: cvd [SELECTOR_OPTIONS] env ls\n"
43     "    Get a list of all methods for a service:\n"
44     "      Usage: cvd [SELECTOR_OPTIONS] env ls [SERVICE_NAME]\n"
45     "    Get detailed information like request or response message types of a "
46     "method:\n"
47     "      Usage: cvd [SELECTOR_OPTIONS] env ls [SERVICE_NAME] [METHOD_NAME]\n"
48     "  call: Send RPC request to make changes to the environment\n"
49     "      Usage: cvd [SELECTOR_OPTIONS] env call [SERVICE_NAME] [METHOD_NAME] "
50     "[JSON_FORMATTED_PROTO]\n"
51     "  type: Get detailed information on message types\n"
52     "      Usage: cvd [SELECTOR_OPTIONS] env type [SERVICE_NAME] [TYPE_NAME]\n"
53     "\n"
54     "Arguments:\n"
55     "  SERVICE_NAME         : gRPC service name\n"
56     "  METHOD_NAME          : method name in given service\n"
57     "  TYPE_NAME            : Protobuf message type name including request or "
58     "response messages\n"
59     "  JSON_FORMATTED_PROTO : Protobuf message data with JSON format\n"
60     "\n"
61     "* \"cvd [SELECTOR_OPTIONS] env\" can be replaced with: \"cvd_internal_env "
62     "[INTERNAL_DEVICE_NAME]\"\n";
63 
64 constexpr char kServiceControlEnvProxy[] = "ControlEnvProxyService";
65 
ContainHelpOption(int argc,char ** argv)66 bool ContainHelpOption(int argc, char** argv) {
67   for (int i = 0; i < argc; i++) {
68     if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-help") == 0) {
69       return true;
70     }
71   }
72   return false;
73 }
74 
CvdEnvMain(int argc,char ** argv)75 Result<void> CvdEnvMain(int argc, char** argv) {
76   ::android::base::InitLogging(argv, android::base::StderrLogger);
77   if (ContainHelpOption(argc, argv)) {
78     std::cout << kCvdEnvHelpMessage;
79     return {};
80   }
81 
82   CF_EXPECT(argc >= 3, " need to specify a receiver and a command");
83   const auto& receiver = argv[1];
84   const auto& cmd = argv[2];
85 
86   std::vector<std::string> args;
87   for (int i = 3; i < argc; i++) {
88     // Ignore options, not to be applied when calling grpc_cli.
89     if (!android::base::StartsWith(argv[i], '-')) {
90       args.push_back(argv[i]);
91     }
92   }
93   if (args.size() > 0) {
94     CF_EXPECT(args[0].compare(kServiceControlEnvProxy) != 0,
95               "Prohibited service name");
96   }
97 
98   const auto* config = CuttlefishConfig::Get();
99   CF_EXPECT(config != nullptr, "Unable to find the config");
100   const auto& instances = config->Instances();
101   auto receiver_instance = std::find_if(
102       begin(instances), end(instances), [&receiver](const auto& instance) {
103         return receiver == instance.instance_name();
104       });
105 
106   CF_EXPECT(receiver_instance != std::end(instances),
107             "there is no instance of which name is "
108                 << receiver << ". please check instance name by cvd fleet");
109 
110   auto command_output =
111       CF_EXPECT(HandleCmds(receiver_instance->grpc_socket_path(), cmd, args));
112 
113   std::cout << command_output;
114 
115   return {};
116 }
117 
118 }  // namespace
119 }  // namespace cuttlefish
120 
main(int argc,char ** argv)121 int main(int argc, char** argv) {
122   const auto& ret = cuttlefish::CvdEnvMain(argc, argv);
123   CHECK(ret.ok()) << ret.error().FormatForEnv();
124   return 0;
125 }
126