1use crate::accel::Accel;
2use crate::acpitable::AcpiTable;
3use crate::action::Action;
4use crate::addfs::AddFd;
5use crate::audio::Audio;
6use crate::audiodev::AudioDev;
7use crate::blockdev::BlockDev;
8use crate::boot::Boot;
9use crate::chardev::CharDev;
10use crate::compact::Compact;
11use crate::device::Device;
12use crate::display::QemuDisplay;
13use crate::drive::Drive;
14use crate::fsdev::FsDev;
15use crate::fw_cfg::FwCfg;
16use crate::global::Global;
17use crate::icount::Icount;
18use crate::incoming::Incoming;
19use crate::iscsi::Iscsi;
20use crate::memory::Memory;
21use crate::mon::Mon;
22use crate::msg::Msg;
23use crate::name::Name;
24use crate::netdev::NetDev;
25use crate::numa::NUMA;
26use crate::object::Object;
27use crate::overcommit::Overcommit;
28use crate::parsers::{
29 ARG_ACCEL, ARG_ACPITABLE, ARG_ACTION, ARG_ADD_FD, ARG_APPEND, ARG_AUDIO, ARG_AUDIODEV, ARG_BIG_D, ARG_BIG_S, ARG_BIOS, ARG_BLOCKDEV, ARG_BOOT, ARG_CDROM, ARG_CHARDEV, ARG_CHROOT, ARG_COMPAT,
30 ARG_CPU, ARG_DAEMONIZE, ARG_DEBUGCON, ARG_DEVICE, ARG_DFILTER, ARG_DISPLAY, ARG_DRIVE, ARG_DTB, ARG_DUMP_VMSTATE, ARG_ECHR, ARG_ENABLE_KVM, ARG_ENABLE_SYNC_PROFILE, ARG_FDA, ARG_FDB, ARG_FSDEV,
31 ARG_FULL_SCREEN, ARG_FW_CFG, ARG_GDB, ARG_GLOBAL, ARG_HDA, ARG_HDB, ARG_HDC, ARG_HDD, ARG_ICOUNT, ARG_INCOMING, ARG_INITRD, ARG_ISCSI, ARG_JITDUMP, ARG_K, ARG_KERNEL, ARG_L, ARG_LITTLE_D,
32 ARG_LITTLE_S, ARG_LOADVM, ARG_MACHINE, ARG_MEM_PATH, ARG_MEM_PREALLOC, ARG_MEMORY, ARG_MON, ARG_MONITOR, ARG_MSG, ARG_MTDBLOCK, ARG_NAME, ARG_NETDEV, ARG_NO_FD_BOOTCHK, ARG_NO_REBOOT,
33 ARG_NO_SHUTDOWN, ARG_NO_USER_CONFIG, ARG_NODEFAULTS, ARG_NOGRAPHIC, ARG_NUMA, ARG_OBJECT, ARG_ONLY_MIGRATABLE, ARG_OPTION_ROM, ARG_OVERCOMMIT, ARG_PARALLEL, ARG_PERFMAP, ARG_PFLASH, ARG_PIDFILE,
34 ARG_PLUGIN, ARG_PRECONFIG, ARG_QMP, ARG_QMP_PRETTY, ARG_READCONFIG, ARG_RTC, ARG_RUN_WITH, ARG_RUNAS, ARG_SANDBOX, ARG_SD, ARG_SEED, ARG_SERIAL, ARG_SET, ARG_SHIM, ARG_SMBIOS, ARG_SMP,
35 ARG_SNAPSHOT, ARG_SPICE, ARG_TPMDEV, ARG_TRACE, ARG_USB, ARG_USBDEVICE, ARG_UUID, ARG_VGA, ARG_VIRTFS, ARG_VNC, ARG_WIN2K_HACK, ARG_XEN_ATTACH, ARG_XEN_DOMID_RESTRICT, ARG_XEN_ID,
36};
37use crate::plugin::Plugin;
38use crate::rtc::Rtc;
39use crate::runwith::RunWith;
40use crate::sandbox::Sandbox;
41use crate::serial::SpecialDevice;
42use crate::set::Set;
43use crate::shell_string::ShellString;
44use crate::smbios::Smbios;
45use crate::smp::SMP;
46use crate::spice::Spice;
47use crate::tpmdev::TpmDev;
48use crate::trace::Trace;
49use crate::usb::USBDevice;
50use crate::vga::VGA;
51use crate::virtfs::Virtfs;
52use crate::vnc::VNC;
53use crate::{QEMU_BIN_AARCH64, QEMU_BIN_X86_64, QUuid, QemuInstanceBase, QemuInstanceForAarch64, QemuInstanceForX86_64};
54use std::path::PathBuf;
55use std::str::FromStr;
56use winnow::Result;
57
58#[macro_export]
60macro_rules! ff {
61 ($a:expr,$b:ident,$c:ty,$d:expr) => {
62 match $a.next() {
63 None => {
64 return Err(format!("Argument {} expected a token to parse, none found", $b));
65 }
66 Some(v) => match v.parse::<$c>() {
67 Ok(p) => {
68 $d = Some(p);
69 }
70 Err(parse_err) => {
71 return Err(format!("While trying to parse $b an error was seen: {}", parse_err));
72 }
73 },
74 }
75 };
76}
77#[macro_export]
78macro_rules! ffs {
79 ($a:expr,$b:ident,$c:ty,$d:expr) => {
80 match $a.next() {
81 None => {
82 return Err(format!("Argument {} expected a token to parse, none found", $b));
83 }
84 Some(v) => match v.parse::<$c>() {
85 Ok(p) => match $d {
86 Some(ref mut vs) => vs.push(p),
87 None => {
88 $d = Some(vec![p]);
89 }
90 },
91 Err(parse_err) => {
92 return Err(format!("While trying to parse $b an error was seen: {}", parse_err));
93 }
94 },
95 }
96 };
97}
98
99fn parse_common_qemu_args<Machine: FromStr, Cpu: FromStr>(q: &mut QemuInstanceBase<Machine, Cpu>, tokens: impl IntoIterator<Item = String>) -> Result<(), String>
100where
101 <Cpu as FromStr>::Err: std::fmt::Display,
102 <Machine as FromStr>::Err: std::fmt::Display,
103{
104 let mut tokens = tokens.into_iter();
105 while let Some(token) = tokens.next() {
106 match token.as_str() {
107 ARG_CPU => ff!(tokens, ARG_CPU, Cpu, q.cpu),
109 ARG_MACHINE => ff!(tokens, ARG_MACHINE, Machine, q.machine),
110 ARG_ACCEL => ff!(tokens, ARG_ACCEL, Accel, q.accel),
112 ARG_SMP => ff!(tokens, ARG_SMP, SMP, q.smp),
113 ARG_NUMA => ffs!(tokens, ARG_NUMA, NUMA, q.numa),
114 ARG_ADD_FD => ff!(tokens, ARG_ADD_FD, AddFd, q.add_fd),
115 ARG_SET => ffs!(tokens, ARG_SET, Set, q.set),
116 ARG_GLOBAL => ffs!(tokens, ARG_GLOBAL, Global, q.global),
117 ARG_BOOT => ff!(tokens, ARG_BOOT, Boot, q.boot),
118 ARG_MEMORY => ff!(tokens, ARG_MEMORY, Memory, q.m),
119 ARG_MEM_PATH => ff!(tokens, ARG_MEM_PATH, PathBuf, q.mem_path),
120 ARG_MEM_PREALLOC => q.mem_prealloc = Some(true),
121 ARG_K => ff!(tokens, ARG_K, String, q.k),
122 ARG_AUDIO => ff!(tokens, ARG_AUDIO, Audio, q.audio),
123 ARG_AUDIODEV => ff!(tokens, ARG_AUDIODEV, AudioDev, q.audiodev),
124 ARG_DEVICE => ffs!(tokens, ARG_DEVICE, Device, q.device),
125 ARG_NAME => ff!(tokens, ARG_NAME, Name, q.name),
126 ARG_UUID => ff!(tokens, ARG_UUID, newtype_uuid::TypedUuid<QUuid>, q.uuid),
127 ARG_FDA => ff!(tokens, ARG_FDA, PathBuf, q.fda),
128 ARG_FDB => ff!(tokens, ARG_FDB, PathBuf, q.fdb),
129 ARG_HDA => ff!(tokens, ARG_HDA, PathBuf, q.hda),
130 ARG_HDB => ff!(tokens, ARG_HDB, PathBuf, q.hdb),
131 ARG_HDC => ff!(tokens, ARG_HDC, PathBuf, q.hdc),
132 ARG_HDD => ff!(tokens, ARG_HDD, PathBuf, q.hdd),
133 ARG_CDROM => ff!(tokens, ARG_CDROM, PathBuf, q.cdrom),
134 ARG_BLOCKDEV => ffs!(tokens, ARG_BLOCKDEV, BlockDev, q.blockdev),
135 ARG_DRIVE => ffs!(tokens, ARG_DRIVE, Drive, q.drive),
136 ARG_MTDBLOCK => ff!(tokens, ARG_MTDBLOCK, PathBuf, q.mdtblock),
137 ARG_SD => ff!(tokens, ARG_SD, PathBuf, q.sd),
138 ARG_SNAPSHOT => q.snapshot = Some(true),
139 ARG_FSDEV => ff!(tokens, ARG_FSDEV, FsDev, q.fsdev),
140 ARG_VIRTFS => ff!(tokens, ARG_VIRTFS, Virtfs, q.virtfs),
141 ARG_ISCSI => ff!(tokens, ARG_ISCSI, Iscsi, q.iscsi),
142 ARG_USB => q.usb = Some(true),
143 ARG_USBDEVICE => ff!(tokens, ARG_USBDEVICE, USBDevice, q.usbdevice),
144 ARG_DISPLAY => ff!(tokens, ARG_DISPLAY, QemuDisplay, q.display),
145 ARG_NOGRAPHIC => q.nographic = Some(true),
146 ARG_SPICE => ff!(tokens, ARG_SPICE, Spice, q.spice),
147 ARG_VGA => ff!(tokens, ARG_VGA, VGA, q.vga),
148 ARG_FULL_SCREEN => q.full_screen = Some(true),
149 ARG_VNC => ff!(tokens, ARG_VNC, VNC, q.vnc),
151 ARG_WIN2K_HACK => q.win2k_hack = Some(true),
152 ARG_NO_FD_BOOTCHK => q.no_fd_bootchk = Some(true),
153 ARG_ACPITABLE => ff!(tokens, ARG_ACPITABLE, AcpiTable, q.acpitable),
154 ARG_SMBIOS => ffs!(tokens, ARG_SMBIOS, Smbios, q.smbios),
155 ARG_NETDEV => ffs!(tokens, ARG_NETDEV, NetDev, q.netdev),
156 ARG_CHARDEV => ffs!(tokens, ARG_CHARDEV, CharDev, q.chardev),
157 ARG_TPMDEV => ff!(tokens, ARG_TPMDEV, TpmDev, q.tpmdev),
158 ARG_BIOS => ff!(tokens, ARG_BIOS, PathBuf, q.bios),
159 ARG_PFLASH => ff!(tokens, ARG_PFLASH, PathBuf, q.pflash),
160 ARG_KERNEL => ff!(tokens, ARG_KERNEL, PathBuf, q.kernel),
161 ARG_SHIM => ff!(tokens, ARG_SHIM, PathBuf, q.shim),
162 ARG_APPEND => ff!(tokens, ARG_APPEND, ShellString, q.append),
163 ARG_INITRD => ff!(tokens, ARG_INITRD, PathBuf, q.initrd),
164 ARG_DTB => ff!(tokens, ARG_DTB, PathBuf, q.dtb),
165 ARG_COMPAT => ff!(tokens, ARG_COMPAT, Compact, q.compact),
166 ARG_FW_CFG => ff!(tokens, ARG_FW_CFG, FwCfg, q.fw_cfg),
167 ARG_SERIAL => ff!(tokens, ARG_SERIAL, SpecialDevice, q.serial),
168 ARG_PARALLEL => ffs!(tokens, ARG_PARALLEL, SpecialDevice, q.parallel),
169 ARG_MONITOR => ff!(tokens, ARG_MONITOR, SpecialDevice, q.monitor),
170 ARG_QMP => ff!(tokens, ARG_QMP, SpecialDevice, q.qmp),
171 ARG_QMP_PRETTY => ff!(tokens, ARG_QMP_PRETTY, SpecialDevice, q.qmp_pretty),
172 ARG_MON => ffs!(tokens, ARG_MON, Mon, q.mon),
173 ARG_DEBUGCON => ff!(tokens, ARG_DEBUGCON, CharDev, q.debugcon),
174 ARG_PIDFILE => ff!(tokens, ARG_PIDFILE, PathBuf, q.pidfile),
175 ARG_PRECONFIG => q.preconfig = Some(true),
176 ARG_BIG_S => q.big_s = Some(true),
177 ARG_OVERCOMMIT => ff!(tokens, ARG_OVERCOMMIT, Overcommit, q.overcommit),
178 ARG_GDB => ff!(tokens, ARG_GDB, SpecialDevice, q.gdb),
179 ARG_LITTLE_S => q.s = Some(true),
180 ARG_LITTLE_D => ffs!(tokens, ARG_LITTLE_D, String, q.d),
181 ARG_BIG_D => ff!(tokens, ARG_BIG_D, PathBuf, q.big_d),
182 ARG_DFILTER => ffs!(tokens, ARG_DFILTER, String, q.dfilter),
183 ARG_SEED => ff!(tokens, ARG_SEED, usize, q.seed),
184 ARG_L => ff!(tokens, ARG_L, PathBuf, q.big_l),
185 ARG_ENABLE_KVM => q.enable_kvm = Some(true),
186 ARG_XEN_ID => ff!(tokens, ARG_XEN_ID, String, q.xen_id),
187 ARG_XEN_ATTACH => q.xen_attach = Some(true),
188 ARG_XEN_DOMID_RESTRICT => q.xen_domid_restrict = Some(true),
189 ARG_NO_REBOOT => q.no_reboot = Some(true),
190 ARG_NO_SHUTDOWN => q.no_shutdown = Some(true),
191 ARG_ACTION => ff!(tokens, ARG_ACTION, Action, q.action),
192 ARG_LOADVM => ff!(tokens, ARG_LOADVM, String, q.loadvm),
193 ARG_DAEMONIZE => q.daemonize = Some(true),
194 ARG_OPTION_ROM => ff!(tokens, ARG_OPTION_ROM, PathBuf, q.option_rom),
195 ARG_RTC => ff!(tokens, ARG_RTC, Rtc, q.rtc),
196 ARG_ICOUNT => ff!(tokens, ARG_ICOUNT, Icount, q.icount),
197 ARG_ECHR => ff!(tokens, ARG_ECHR, String, q.echr),
199 ARG_INCOMING => ffs!(tokens, ARG_INCOMING, Incoming, q.incoming),
200 ARG_ONLY_MIGRATABLE => q.only_migratable = Some(true),
201 ARG_NODEFAULTS => q.nodefaults = Some(true),
202 ARG_SANDBOX => ff!(tokens, ARG_SANDBOX, Sandbox, q.sandbox),
203 ARG_READCONFIG => ff!(tokens, ARG_READCONFIG, PathBuf, q.readconfig),
204 ARG_NO_USER_CONFIG => q.no_user_config = Some(true),
205 ARG_TRACE => ff!(tokens, ARG_TRACE, Trace, q.trace),
206 ARG_PLUGIN => ff!(tokens, ARG_PLUGIN, Plugin, q.plugin),
207 ARG_RUNAS => ff!(tokens, ARG_RUNAS, String, q.runas),
208 ARG_RUN_WITH => ff!(tokens, ARG_RUN_WITH, RunWith, q.run_with),
209 ARG_CHROOT => ff!(tokens, ARG_CHROOT, PathBuf, q.chroot),
210 ARG_MSG => ff!(tokens, ARG_MSG, Msg, q.msg),
211 ARG_DUMP_VMSTATE => ff!(tokens, ARG_DUMP_VMSTATE, PathBuf, q.dump_vmstate),
212 ARG_ENABLE_SYNC_PROFILE => q.enable_sync_profile = Some(true),
213 ARG_PERFMAP => ff!(tokens, ARG_PERFMAP, PathBuf, q.perfmap),
214 ARG_JITDUMP => ff!(tokens, ARG_JITDUMP, PathBuf, q.jitdump),
215 ARG_OBJECT => ffs!(tokens, ARG_OBJECT, Object, q.object),
216 other => {
217 return Err(format!("unsupported argument: {other}"));
218 }
219 }
220 }
221 Ok(())
222}
223
224fn parse_qemu_command_line<Machine: std::str::FromStr, Cpu: std::str::FromStr>(bin_name: &str, s: &str, q: &mut QemuInstanceBase<Machine, Cpu>) -> Result<(), String>
225where
226 <Cpu as FromStr>::Err: std::fmt::Display,
227 <Machine as FromStr>::Err: std::fmt::Display,
228{
229 let mut tokens = shellish_parse::parse(s, shellish_parse::ParseOptions::new()).map_err(|e| e.to_string())?.into_iter();
230
231 let binary = tokens.next();
232 match binary {
233 None => {
234 return Err(String::from("No next token for determining binary name"));
235 }
236 Some(path) => {
237 if path.contains(bin_name) {
238 q.qemu_binary = PathBuf::from(path);
239 } else {
240 return Err(format!("{} not found in string", bin_name));
241 }
242 }
243 }
244
245 parse_common_qemu_args(q, tokens)?;
246
247 Ok(())
248}
249
250impl FromStr for QemuInstanceForX86_64 {
251 type Err = String;
252
253 fn from_str(s: &str) -> Result<Self, Self::Err> {
254 let mut q = QemuInstanceBase::builder().qemu_binary(PathBuf::from("")).build();
255 parse_qemu_command_line(QEMU_BIN_X86_64, s, &mut q)?;
256 Ok(q)
257 }
258}
259
260impl FromStr for QemuInstanceForAarch64 {
261 type Err = String;
262
263 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
264 let mut q = QemuInstanceBase::builder().qemu_binary(PathBuf::from("")).build();
265 parse_qemu_command_line(QEMU_BIN_AARCH64, s, &mut q)?;
266 Ok(q)
267 }
268}