1use super::*;
2use std::process::{Child, Command};
3use std::time::Duration;
4use wait_timeout::ChildExt;
5
6#[derive(Debug, Clone)]
8pub struct QemuConfig {
9    pub qemu_path: String,
10    pub bios_path: String,
11    pub drives: Vec<QemuDriveConfig>,
12    pub additional_args: Vec<String>,
13}
14
15impl Default for QemuConfig {
16    fn default() -> Self {
17        Self {
18            qemu_path: "qemu-system-x86_64".to_string(),
19            bios_path: "OVMF.fd".to_string(),
20            drives: Vec::new(),
21            additional_args: vec!["-net".to_string(), "none".to_string()],
22        }
23    }
24}
25
26impl QemuConfig {
27    pub fn run(&self) -> Result<QemuProcess> {
29        let mut args = vec!["-bios".to_string(), self.bios_path.clone()];
30        for (index, drive) in self.drives.iter().enumerate() {
31            args.push("-drive".to_string());
32            args.push(format!(
33                "file={},index={},media={},format={}",
34                drive.file, index, drive.media, drive.format
35            ));
36        }
37        args.extend(self.additional_args.iter().cloned());
38
39        let child = Command::new(&self.qemu_path).args(args).spawn()?;
40        Ok(QemuProcess { child })
41    }
42}
43
44#[derive(Debug, Clone)]
46pub struct QemuDriveConfig {
47    pub file: String,
48    pub media: String,
49    pub format: String,
50}
51
52impl QemuDriveConfig {
53    pub fn new(file: &str, media: &str, format: &str) -> Self {
54        Self {
55            file: file.to_string(),
56            media: media.to_string(),
57            format: format.to_string(),
58        }
59    }
60}
61
62pub struct QemuProcess {
63    child: Child,
64}
65
66impl QemuProcess {
67    pub fn wait(&mut self, duration: Duration) -> Option<i32> {
71        self.child
72            .wait_timeout(duration)
73            .expect("Failed to wait on child process")
74            .map(|exit_status| exit_status.code().unwrap_or(0))
75    }
76
77    pub fn kill(&mut self) -> std::io::Result<()> {
79        self.child.kill()
80    }
81}