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