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/selector/instance_database_utils.h"
18
19 #include <regex>
20 #include <set>
21 #include <sstream>
22 #include <string_view>
23 #include <vector>
24
25 #include <android-base/file.h>
26 #include <android-base/strings.h>
27
28 #include "common/libs/utils/files.h"
29 #include "host/libs/config/cuttlefish_config.h"
30
31 namespace cuttlefish {
32 namespace selector {
33
GetCuttlefishConfigPath(const std::string & home)34 Result<std::string> GetCuttlefishConfigPath(const std::string& home) {
35 std::string home_realpath;
36 CF_EXPECT(DirectoryExists(home), "Invalid Home Directory");
37 CF_EXPECT(android::base::Realpath(home, &home_realpath));
38 static const char kSuffix[] = "/cuttlefish_assembly/cuttlefish_config.json";
39 std::string config_path = AbsolutePath(home_realpath + kSuffix);
40 CF_EXPECT(FileExists(config_path), "No config file exists");
41 return {config_path};
42 }
43
GenInternalGroupName()44 std::string GenInternalGroupName() {
45 std::string_view internal_name{kCvdNamePrefix}; // "cvd-"
46 internal_name.remove_suffix(1); // "cvd"
47 return std::string(internal_name);
48 }
49
GenDefaultGroupName()50 std::string GenDefaultGroupName() { return GenInternalGroupName(); }
51
LocalDeviceNameRule(const std::string & group_name,const std::string & instance_name)52 std::string LocalDeviceNameRule(const std::string& group_name,
53 const std::string& instance_name) {
54 return group_name + "-" + instance_name;
55 }
56
IsValidGroupName(const std::string & token)57 bool IsValidGroupName(const std::string& token) {
58 std::regex regular_expr("[A-Za-z_][A-Za-z_0-9]*");
59 return std::regex_match(token, regular_expr);
60 }
61
IsValidInstanceName(const std::string & token)62 bool IsValidInstanceName(const std::string& token) {
63 if (token.empty()) {
64 return false;
65 }
66 std::regex base_regular_expr("[A-Za-z_0-9]+");
67 auto pieces = android::base::Split(token, "-");
68 for (const auto& piece : pieces) {
69 if (!std::regex_match(piece, base_regular_expr)) {
70 return false;
71 }
72 }
73 return true;
74 }
75
BreakDeviceName(const std::string & device_name)76 Result<DeviceName> BreakDeviceName(const std::string& device_name) {
77 CF_EXPECT(!device_name.empty());
78 CF_EXPECT(Contains(device_name, '-'));
79 auto dash_pos = device_name.find_first_of('-');
80 // - must be neither the first nor the last character
81 CF_EXPECT(dash_pos != 0 && dash_pos != (device_name.size() - 1));
82 const auto group_name = device_name.substr(0, dash_pos);
83 const auto instance_name = device_name.substr(dash_pos + 1);
84 return DeviceName{.group_name = group_name,
85 .per_instance_name = instance_name};
86 }
87
IsValidDeviceName(const std::string & token)88 bool IsValidDeviceName(const std::string& token) {
89 if (token.empty()) {
90 return false;
91 }
92 auto result = BreakDeviceName(token);
93 if (!result.ok()) {
94 return false;
95 }
96 const auto [group_name, instance_name] = *result;
97 return IsValidGroupName(group_name) && IsValidInstanceName(instance_name);
98 }
99
PotentiallyHostArtifactsPath(const std::string & host_artifacts_path)100 bool PotentiallyHostArtifactsPath(const std::string& host_artifacts_path) {
101 if (host_artifacts_path.empty() || !DirectoryExists(host_artifacts_path)) {
102 return false;
103 }
104 const auto host_bin_path = host_artifacts_path + "/bin";
105 auto contents_result = DirectoryContents(host_bin_path);
106 if (!contents_result.ok()) {
107 return false;
108 }
109 std::vector<std::string> contents = std::move(*contents_result);
110 std::set<std::string> contents_set{std::move_iterator(contents.begin()),
111 std::move_iterator(contents.end())};
112 std::set<std::string> launchers = {"cvd", "launch_cvd"};
113 std::vector<std::string> result;
114 std::set_intersection(launchers.cbegin(), launchers.cend(),
115 contents_set.cbegin(), contents_set.cend(),
116 std::back_inserter(result));
117 return !result.empty();
118 }
119
GenerateTooManyInstancesErrorMsg(const int n,const std::string & field_name)120 std::string GenerateTooManyInstancesErrorMsg(const int n,
121 const std::string& field_name) {
122 std::stringstream s;
123 s << "Only up to " << n << " must match";
124 if (!field_name.empty()) {
125 s << " by the field " << field_name;
126 }
127 return s.str();
128 }
129
130 } // namespace selector
131 } // namespace cuttlefish
132