1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::thread::sleep;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
7*bb4ee6a4SAndroid Build Coastguard Worker
8*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
10*bb4ee6a4SAndroid Build Coastguard Worker use base::kill_process_group;
11*bb4ee6a4SAndroid Build Coastguard Worker use base::reap_child;
12*bb4ee6a4SAndroid Build Coastguard Worker use base::syslog;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::syslog::LogArgs;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::syslog::LogConfig;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
16*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::device::run_console_device;
17*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::device::run_fs_device;
18*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::device::run_vsock_device;
19*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::device::run_wl_device;
20*bb4ee6a4SAndroid Build Coastguard Worker
21*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::sys::cmdline::Commands;
22*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::sys::cmdline::DeviceSubcommand;
23*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::sys::linux::start_devices;
24*bb4ee6a4SAndroid Build Coastguard Worker use crate::CommandStatus;
25*bb4ee6a4SAndroid Build Coastguard Worker use crate::Config;
26*bb4ee6a4SAndroid Build Coastguard Worker
start_device(command: DeviceSubcommand) -> anyhow::Result<()>27*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn start_device(command: DeviceSubcommand) -> anyhow::Result<()> {
28*bb4ee6a4SAndroid Build Coastguard Worker match command {
29*bb4ee6a4SAndroid Build Coastguard Worker DeviceSubcommand::Console(cfg) => run_console_device(cfg),
30*bb4ee6a4SAndroid Build Coastguard Worker DeviceSubcommand::Fs(cfg) => run_fs_device(cfg),
31*bb4ee6a4SAndroid Build Coastguard Worker DeviceSubcommand::Vsock(cfg) => run_vsock_device(cfg),
32*bb4ee6a4SAndroid Build Coastguard Worker DeviceSubcommand::Wl(cfg) => run_wl_device(cfg),
33*bb4ee6a4SAndroid Build Coastguard Worker }
34*bb4ee6a4SAndroid Build Coastguard Worker }
35*bb4ee6a4SAndroid Build Coastguard Worker
36*bb4ee6a4SAndroid Build Coastguard Worker // Wait for all children to exit. Return true if they have all exited, false
37*bb4ee6a4SAndroid Build Coastguard Worker // otherwise.
wait_all_children() -> bool38*bb4ee6a4SAndroid Build Coastguard Worker fn wait_all_children() -> bool {
39*bb4ee6a4SAndroid Build Coastguard Worker const CHILD_WAIT_MAX_ITER: isize = 100;
40*bb4ee6a4SAndroid Build Coastguard Worker const CHILD_WAIT_MS: u64 = 10;
41*bb4ee6a4SAndroid Build Coastguard Worker for _ in 0..CHILD_WAIT_MAX_ITER {
42*bb4ee6a4SAndroid Build Coastguard Worker loop {
43*bb4ee6a4SAndroid Build Coastguard Worker match reap_child() {
44*bb4ee6a4SAndroid Build Coastguard Worker Ok(0) => break,
45*bb4ee6a4SAndroid Build Coastguard Worker // We expect ECHILD which indicates that there were no children left.
46*bb4ee6a4SAndroid Build Coastguard Worker Err(e) if e.errno() == libc::ECHILD => return true,
47*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
48*bb4ee6a4SAndroid Build Coastguard Worker warn!("error while waiting for children: {}", e);
49*bb4ee6a4SAndroid Build Coastguard Worker return false;
50*bb4ee6a4SAndroid Build Coastguard Worker }
51*bb4ee6a4SAndroid Build Coastguard Worker // We reaped one child, so continue reaping.
52*bb4ee6a4SAndroid Build Coastguard Worker _ => {}
53*bb4ee6a4SAndroid Build Coastguard Worker }
54*bb4ee6a4SAndroid Build Coastguard Worker }
55*bb4ee6a4SAndroid Build Coastguard Worker // There's no timeout option for waitpid which reap_child calls internally, so our only
56*bb4ee6a4SAndroid Build Coastguard Worker // recourse is to sleep while waiting for the children to exit.
57*bb4ee6a4SAndroid Build Coastguard Worker sleep(Duration::from_millis(CHILD_WAIT_MS));
58*bb4ee6a4SAndroid Build Coastguard Worker }
59*bb4ee6a4SAndroid Build Coastguard Worker
60*bb4ee6a4SAndroid Build Coastguard Worker // If we've made it to this point, not all of the children have exited.
61*bb4ee6a4SAndroid Build Coastguard Worker false
62*bb4ee6a4SAndroid Build Coastguard Worker }
63*bb4ee6a4SAndroid Build Coastguard Worker
cleanup()64*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn cleanup() {
65*bb4ee6a4SAndroid Build Coastguard Worker // Reap exit status from any child device processes. At this point, all devices should have been
66*bb4ee6a4SAndroid Build Coastguard Worker // dropped in the main process and told to shutdown. Try over a period of 100ms, since it may
67*bb4ee6a4SAndroid Build Coastguard Worker // take some time for the processes to shut down.
68*bb4ee6a4SAndroid Build Coastguard Worker if !wait_all_children() {
69*bb4ee6a4SAndroid Build Coastguard Worker // We gave them a chance, and it's too late.
70*bb4ee6a4SAndroid Build Coastguard Worker warn!("not all child processes have exited; sending SIGKILL");
71*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = kill_process_group() {
72*bb4ee6a4SAndroid Build Coastguard Worker // We're now at the mercy of the OS to clean up after us.
73*bb4ee6a4SAndroid Build Coastguard Worker warn!("unable to kill all child processes: {}", e);
74*bb4ee6a4SAndroid Build Coastguard Worker }
75*bb4ee6a4SAndroid Build Coastguard Worker }
76*bb4ee6a4SAndroid Build Coastguard Worker }
77*bb4ee6a4SAndroid Build Coastguard Worker
get_library_watcher() -> std::io::Result<()>78*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_library_watcher() -> std::io::Result<()> {
79*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
80*bb4ee6a4SAndroid Build Coastguard Worker }
81*bb4ee6a4SAndroid Build Coastguard Worker
run_command(command: Commands, _log_args: LogArgs) -> anyhow::Result<()>82*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn run_command(command: Commands, _log_args: LogArgs) -> anyhow::Result<()> {
83*bb4ee6a4SAndroid Build Coastguard Worker match command {
84*bb4ee6a4SAndroid Build Coastguard Worker Commands::Devices(cmd) => start_devices(cmd).context("start_devices subcommand failed"),
85*bb4ee6a4SAndroid Build Coastguard Worker }
86*bb4ee6a4SAndroid Build Coastguard Worker }
87*bb4ee6a4SAndroid Build Coastguard Worker
init_log(log_config: LogConfig, _cfg: &Config) -> anyhow::Result<()>88*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn init_log(log_config: LogConfig, _cfg: &Config) -> anyhow::Result<()> {
89*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = syslog::init_with(log_config) {
90*bb4ee6a4SAndroid Build Coastguard Worker eprintln!("failed to initialize syslog: {}", e);
91*bb4ee6a4SAndroid Build Coastguard Worker return Err(anyhow!("failed to initialize syslog: {}", e));
92*bb4ee6a4SAndroid Build Coastguard Worker }
93*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
94*bb4ee6a4SAndroid Build Coastguard Worker }
95*bb4ee6a4SAndroid Build Coastguard Worker
error_to_exit_code(_res: &std::result::Result<CommandStatus, anyhow::Error>) -> i3296*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn error_to_exit_code(_res: &std::result::Result<CommandStatus, anyhow::Error>) -> i32 {
97*bb4ee6a4SAndroid Build Coastguard Worker 1
98*bb4ee6a4SAndroid Build Coastguard Worker }
99