1 /*
2 * Copyright (C) 2018 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/libs/vm_manager/host_configuration.h"
18
19 #include <string>
20 #include <utility>
21 #include <vector>
22
23 #include <android-base/logging.h>
24 #include <sys/utsname.h>
25
26 #include "common/libs/utils/users.h"
27
28 namespace cuttlefish {
29 namespace vm_manager {
30 namespace {
31
UserInGroup(const std::string & group,std::vector<std::string> * config_commands)32 __attribute__((unused)) bool UserInGroup(
33 const std::string& group, std::vector<std::string>* config_commands) {
34 if (!InGroup(group)) {
35 LOG(ERROR) << "User must be a member of " << group;
36 config_commands->push_back("# Add your user to the " + group + " group:");
37 config_commands->push_back("sudo usermod -aG " + group + " $USER");
38 return false;
39 }
40 return true;
41 }
42
43 constexpr std::pair<int,int> invalid_linux_version = std::pair<int,int>();
44
GetLinuxVersion()45 __attribute__((unused)) std::pair<int, int> GetLinuxVersion() {
46 struct utsname info;
47 if (!uname(&info)) {
48 char* digit = strtok(info.release, "+.-");
49 int major = atoi(digit);
50 if (digit) {
51 digit = strtok(NULL, "+.-");
52 int minor = atoi(digit);
53 return std::pair<int,int>{major, minor};
54 }
55 }
56 LOG(ERROR) << "Failed to detect Linux kernel version";
57 return invalid_linux_version;
58 }
59
LinuxVersionAtLeast(std::vector<std::string> * config_commands,const std::pair<int,int> & version,int major,int minor)60 __attribute__((unused)) bool LinuxVersionAtLeast(
61 std::vector<std::string>* config_commands,
62 const std::pair<int, int>& version, int major, int minor) {
63 if (version.first > major ||
64 (version.first == major && version.second >= minor)) {
65 return true;
66 }
67
68 LOG(ERROR) << "Kernel version must be >=" << major << "." << minor
69 << ", have " << version.first << "." << version.second;
70 config_commands->push_back("# Please upgrade your kernel to >=" +
71 std::to_string(major) + "." +
72 std::to_string(minor));
73 return false;
74 }
75
76 } // namespace
77
ValidateHostConfiguration(std::vector<std::string> * config_commands)78 bool ValidateHostConfiguration(std::vector<std::string>* config_commands) {
79 #ifdef __APPLE__
80 (void)config_commands;
81 return true;
82 #else
83 // if we can't detect the kernel version, just fail
84 auto version = GetLinuxVersion();
85 if (version == invalid_linux_version) {
86 return false;
87 }
88
89 // the check for cvdnetwork needs to happen even if the user is not in kvm, so
90 // we can't just say UserInGroup("kvm") && UserInGroup("cvdnetwork")
91 auto in_cvdnetwork = UserInGroup("cvdnetwork", config_commands);
92
93 // if we're in the virtaccess group this is likely to be a CrOS environment.
94 auto is_cros = InGroup("virtaccess");
95 if (is_cros) {
96 // relax the minimum kernel requirement slightly, as chromeos-4.4 has the
97 // needed backports to enable vhost_vsock
98 auto linux_ver_4_4 = LinuxVersionAtLeast(config_commands, version, 4, 4);
99 return in_cvdnetwork && linux_ver_4_4;
100 } else {
101 // this is regular Linux, so use the Debian group name and be more
102 // conservative with the kernel version check.
103 auto in_kvm = UserInGroup("kvm", config_commands);
104 auto linux_ver_4_8 = LinuxVersionAtLeast(config_commands, version, 4, 8);
105 return in_cvdnetwork && in_kvm && linux_ver_4_8;
106 }
107 #endif
108 }
109
110 } // namespace vm_manager
111 } // namespace cuttlefish
112
113