Skip to content

Commit bc6a00c

Browse files
committed
cvd: Introduce setup command and refactor host validation
- Add a new `cvd setup` command to automatically apply host configuration fixes. - Refactor `ValidateHostConfiguration` to return a list of structured `HostConfigurationAction`s instead of raw command strings, allowing better programmatic handling. - Update `run_cvd` validation to use the new structured validation API. Assisted-by: Jetski <jetski@google.com> Bug: b/512582358
1 parent 018b630 commit bc6a00c

15 files changed

Lines changed: 263 additions & 79 deletions

File tree

base/cvd/cuttlefish/common/libs/utils/users.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,16 @@ Result<std::string> SystemWideUserHome() {
114114
}
115115

116116
Result<std::string> CurrentUserName() {
117-
char buf[LOGIN_NAME_MAX + 1];
118-
CF_EXPECT(getlogin_r(buf, sizeof(buf)) == 0, strerror(errno));
119-
return std::string(buf);
117+
uid_t uid = getuid();
118+
struct passwd pwd;
119+
struct passwd* result;
120+
long val = sysconf(_SC_GETPW_R_SIZE_MAX);
121+
size_t bufsize = (val == -1) ? 16384 : val;
122+
std::vector<char> buffer(bufsize);
123+
int s = getpwuid_r(uid, &pwd, buffer.data(), buffer.size(), &result);
124+
CF_EXPECT(s == 0, "getpwuid_r failed: " << strerror(s));
125+
CF_EXPECT(result != nullptr, "User not found for uid " << uid);
126+
return std::string(pwd.pw_name);
120127
}
121128

122129
} // namespace cuttlefish

base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ cf_cc_library(
2121
"//cuttlefish/host/commands/cvd/instances:instance_manager",
2222
"//cuttlefish/host/commands/cvd/instances/lock",
2323
"//cuttlefish/host/commands/cvd/utils",
24+
"//cuttlefish/host/libs/vm_manager",
2425
"//cuttlefish/result",
25-
"//libbase",
2626
],
2727
)
2828

base/cvd/cuttlefish/host/commands/cvd/cli/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ cf_cc_library(
107107
"//cuttlefish/host/commands/cvd/cli/commands:reset",
108108
"//cuttlefish/host/commands/cvd/cli/commands:restart",
109109
"//cuttlefish/host/commands/cvd/cli/commands:screen_recording",
110+
"//cuttlefish/host/commands/cvd/cli/commands:setup",
110111
"//cuttlefish/host/commands/cvd/cli/commands:snapshot",
111112
"//cuttlefish/host/commands/cvd/cli/commands:start",
112113
"//cuttlefish/host/commands/cvd/cli/commands:status",

base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,3 +510,18 @@ cf_cc_library(
510510
"@jsoncpp",
511511
],
512512
)
513+
514+
cf_cc_library(
515+
name = "setup",
516+
srcs = ["setup.cc"],
517+
hdrs = ["setup.h"],
518+
deps = [
519+
"//cuttlefish/common/libs/utils:subprocess",
520+
"//cuttlefish/host/commands/cvd/cli:command_request",
521+
"//cuttlefish/host/commands/cvd/cli:types",
522+
"//cuttlefish/host/commands/cvd/cli/commands:command_handler",
523+
"//cuttlefish/host/libs/vm_manager",
524+
"//cuttlefish/result",
525+
"@abseil-cpp//absl/strings",
526+
],
527+
)

base/cvd/cuttlefish/host/commands/cvd/cli/commands/command_handler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class CvdCommandHandler {
3535
// used for command help text
3636
virtual Result<std::string> SummaryHelp() const = 0;
3737
virtual bool RequiresDeviceExists() const;
38+
virtual bool RequiresHostConfiguration() const { return true; }
3839
virtual Result<std::string> DetailedHelp(const CommandRequest&) const = 0;
3940
};
4041

base/cvd/cuttlefish/host/commands/cvd/cli/commands/help.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class CvdHelpHandler : public CvdCommandHandler {
9595

9696
Result<std::string> SummaryHelp() const override { return kSummaryHelpText; }
9797

98-
98+
bool RequiresHostConfiguration() const override { return false; }
9999

100100
Result<std::string> DetailedHelp(const CommandRequest& request) const override {
101101
return kDetailedHelpText;
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (C) 2026 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 "cuttlefish/host/commands/cvd/cli/commands/setup.h"
18+
19+
#include <iostream>
20+
#include <memory>
21+
#include <string>
22+
#include <vector>
23+
24+
#include "absl/strings/str_join.h"
25+
26+
#include "cuttlefish/common/libs/utils/subprocess.h"
27+
#include "cuttlefish/host/commands/cvd/cli/command_request.h"
28+
#include "cuttlefish/host/commands/cvd/cli/commands/command_handler.h"
29+
#include "cuttlefish/host/commands/cvd/cli/types.h"
30+
#include "cuttlefish/host/libs/vm_manager/host_configuration.h"
31+
#include "cuttlefish/result/result.h"
32+
33+
namespace cuttlefish {
34+
namespace {
35+
36+
constexpr char kSummaryHelpText[] = "Configure the host for Cuttlefish";
37+
38+
constexpr char kDetailedHelpText[] =
39+
R"(cvd setup - configure host for cuttlefish
40+
41+
Checks host configuration (kernel version, group memberships) and automatically applies fixes (e.g., adding user to kvm and cvdnetwork groups). Some fixes may require sudo permissions.
42+
43+
Usage:
44+
cvd setup
45+
)";
46+
47+
using vm_manager::HostConfigurationAction;
48+
using vm_manager::ValidateHostConfiguration;
49+
50+
class CvdSetupHandler : public CvdCommandHandler {
51+
public:
52+
CvdSetupHandler() = default;
53+
54+
Result<void> Handle(const CommandRequest& request) override {
55+
CF_EXPECT(CanHandle(request));
56+
57+
std::vector<HostConfigurationAction> actions =
58+
CF_EXPECT(ValidateHostConfiguration());
59+
if (actions.empty()) {
60+
std::cout << "Host configuration is already valid. No setup required."
61+
<< std::endl;
62+
return {};
63+
}
64+
65+
std::cout << "Applying host configuration fixes..." << std::endl;
66+
for (const HostConfigurationAction& action : actions) {
67+
if (!action.description.empty()) {
68+
std::cout << "Purpose: " << action.description << std::endl;
69+
}
70+
if (action.command.empty()) {
71+
std::cout
72+
<< "Manual intervention required (no automated command available)."
73+
<< std::endl;
74+
continue;
75+
}
76+
77+
std::cout << "Running: " << absl::StrJoin(action.command, " ")
78+
<< std::endl;
79+
const int status = Execute(action.command);
80+
CF_EXPECTF(status == 0, "Failed to execute command: `{}`, exit code: {}",
81+
absl::StrJoin(action.command, " "), status);
82+
}
83+
84+
std::cout << "Setup completed successfully." << std::endl;
85+
return {};
86+
}
87+
88+
cvd_common::Args CmdList() const override { return {"setup"}; }
89+
90+
Result<std::string> SummaryHelp() const override { return kSummaryHelpText; }
91+
92+
bool RequiresDeviceExists() const override { return false; }
93+
94+
bool RequiresHostConfiguration() const override { return false; }
95+
96+
Result<std::string> DetailedHelp(const CommandRequest&) const override {
97+
return kDetailedHelpText;
98+
}
99+
};
100+
101+
} // namespace
102+
103+
std::unique_ptr<CvdCommandHandler> NewCvdSetupHandler() {
104+
return std::unique_ptr<CvdCommandHandler>(new CvdSetupHandler());
105+
}
106+
107+
} // namespace cuttlefish
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (C) 2026 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+
#pragma once
18+
19+
#include <memory>
20+
21+
#include "cuttlefish/host/commands/cvd/cli/commands/command_handler.h"
22+
23+
namespace cuttlefish {
24+
25+
std::unique_ptr<CvdCommandHandler> NewCvdSetupHandler();
26+
27+
} // namespace cuttlefish

base/cvd/cuttlefish/host/commands/cvd/cli/request_context.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "cuttlefish/host/commands/cvd/cli/commands/reset.h"
4747
#include "cuttlefish/host/commands/cvd/cli/commands/restart.h"
4848
#include "cuttlefish/host/commands/cvd/cli/commands/screen_recording.h"
49+
#include "cuttlefish/host/commands/cvd/cli/commands/setup.h"
4950
#include "cuttlefish/host/commands/cvd/cli/commands/snapshot.h"
5051
#include "cuttlefish/host/commands/cvd/cli/commands/start.h"
5152
#include "cuttlefish/host/commands/cvd/cli/commands/status.h"
@@ -111,6 +112,7 @@ RequestContext::RequestContext(InstanceManager& instance_manager,
111112
NewScreenRecordingCommandHandler(instance_manager));
112113
request_handlers_.emplace_back(
113114
NewCvdSnapshotCommandHandler(instance_manager));
115+
request_handlers_.emplace_back(NewCvdSetupHandler());
114116
request_handlers_.emplace_back(NewCvdStartCommandHandler(instance_manager));
115117
request_handlers_.emplace_back(NewCvdStatusCommandHandler(instance_manager));
116118
request_handlers_.emplace_back(NewCvdVersionHandler());

base/cvd/cuttlefish/host/commands/cvd/cvd.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@
2121
#include <unordered_map>
2222
#include <vector>
2323

24-
#include <android-base/file.h>
25-
2624
#include "cuttlefish/common/libs/utils/flag_parser.h"
2725
#include "cuttlefish/host/commands/cvd/cli/command_request.h"
2826
#include "cuttlefish/host/commands/cvd/cli/frontline_parser.h"
2927
#include "cuttlefish/host/commands/cvd/cli/request_context.h"
3028
#include "cuttlefish/host/commands/cvd/instances/instance_manager.h"
3129
#include "cuttlefish/host/commands/cvd/instances/lock/instance_lock.h"
30+
#include "cuttlefish/host/libs/vm_manager/host_configuration.h"
3231
#include "cuttlefish/result/result.h"
3332

3433
namespace cuttlefish {
@@ -38,6 +37,13 @@ Cvd::Cvd(InstanceManager& instance_manager,
3837
: instance_manager_(instance_manager),
3938
lock_file_manager_(lock_file_manager) {}
4039

40+
static Result<void> EnforceHostConfigured() {
41+
std::vector<vm_manager::HostConfigurationAction> actions =
42+
CF_EXPECT(vm_manager::ValidateHostConfiguration());
43+
CF_EXPECT(actions.empty(), "Run `cvd setup` to configure the host.");
44+
return {};
45+
}
46+
4147
Result<void> Cvd::HandleCommand(
4248
const std::vector<std::string>& cvd_process_args,
4349
const std::unordered_map<std::string, std::string>& env,
@@ -50,12 +56,19 @@ Result<void> Cvd::HandleCommand(
5056
.Build());
5157

5258
RequestContext context(instance_manager_, lock_file_manager_);
53-
auto handler = CF_EXPECT(context.Handler(request));
59+
CvdCommandHandler* handler = CF_EXPECT(context.Handler(request));
60+
5461
if (CF_EXPECT(HasHelpFlag(request.SubcommandArguments()))) {
5562
std::cout << CF_EXPECT(handler->DetailedHelp(request)) << std::endl;
56-
} else {
57-
CF_EXPECT(handler->Handle(request));
63+
return {};
5864
}
65+
66+
if (handler->RequiresHostConfiguration()) {
67+
CF_EXPECT(EnforceHostConfigured());
68+
}
69+
70+
CF_EXPECT(handler->Handle(request));
71+
5972
return {};
6073
}
6174

0 commit comments

Comments
 (0)