1use std::path::PathBuf;
2
3use bon::Builder;
4
5use crate::common::OnOff;
6use crate::to_command::{ToArg, ToCommand};
7
8#[derive(Default, Builder)]
9pub struct CharNull {
10 id: String,
11}
12
13#[derive(Default, Builder)]
14pub struct CharSocketTcp {
15 id: String,
16 host: Option<String>,
17 port: u16,
18 to: Option<u16>,
19 ipv4: Option<OnOff>,
20 ipv6: Option<OnOff>,
21 nodelay: Option<OnOff>,
22 server: Option<OnOff>,
23 wait: Option<OnOff>,
24 telnet: Option<OnOff>,
25 websocket: Option<OnOff>,
26 reconnect_ms: Option<usize>,
27 mux: Option<OnOff>,
28 logfile: Option<PathBuf>,
29 logappend: Option<OnOff>,
30 tls_creds: Option<String>,
31 tls_authz: Option<String>,
32}
33
34#[derive(Default, Builder)]
35pub struct CharSocketUds {
36 id: String,
37 path: PathBuf,
38 server: Option<OnOff>,
39 wait: Option<OnOff>,
40 telnet: Option<OnOff>,
41 websocket: Option<OnOff>,
42 reconnect_ms: Option<usize>,
43 mux: Option<OnOff>,
44 logfile: Option<PathBuf>,
45 logappend: Option<OnOff>,
46 abstract_opt: Option<OnOff>,
47 tight: Option<OnOff>,
48}
49
50pub enum CharSocket {
51 Tcp(CharSocketTcp),
52 Uds(CharSocketUds),
53}
54
55#[derive(Default, Builder)]
56pub struct CharUdp {
57 id: String,
58 host: Option<String>,
59 port: u16,
60 localaddr: Option<String>,
61 localport: Option<u16>,
62 ipv4: Option<OnOff>,
63 ipv6: Option<OnOff>,
64 mux: Option<OnOff>,
65 logfile: Option<PathBuf>,
66 logappend: Option<OnOff>,
67}
68
69#[derive(Default, Builder)]
70pub struct CharMsMouse {
71 id: String,
72 mux: Option<OnOff>,
73 logfile: Option<PathBuf>,
74 logappend: Option<OnOff>,
75}
76
77#[derive(Default, Builder)]
78pub struct CharHub {
79 id: String,
80 chardevs: Option<Vec<(usize, String)>>,
81}
82#[derive(Default, Builder)]
83pub struct CharVc {
84 id: String,
85 width: Option<usize>,
86 height: Option<usize>,
87 cols: Option<usize>,
88 rows: Option<usize>,
89 mux: Option<OnOff>,
90 logfile: Option<PathBuf>,
91 logappend: Option<OnOff>,
92}
93
94#[derive(Default, Builder)]
95pub struct CharRingBuf {
96 id: String,
97 size: Option<usize>,
98 logfile: Option<PathBuf>,
99 logappend: Option<OnOff>,
100}
101#[derive(Default, Builder)]
102pub struct CharFile {
103 id: String,
104 path: PathBuf,
105 input_path: Option<PathBuf>,
106 mux: Option<OnOff>,
107 logfile: Option<PathBuf>,
108 logappend: Option<OnOff>,
109}
110
111#[derive(Default, Builder)]
112pub struct CharPipe {
113 id: String,
114 mux: Option<OnOff>,
115 logfile: Option<PathBuf>,
116 logappend: Option<OnOff>,
117}
118
119#[derive(Default, Builder)]
120pub struct CharWin32Console {
121 id: String,
122 mux: Option<OnOff>,
123 logfile: Option<PathBuf>,
124 logappend: Option<OnOff>,
125}
126
127#[derive(Default, Builder)]
128pub struct CharWin32Serial {
129 id: String,
130 path: PathBuf,
131 mux: Option<OnOff>,
132 logfile: Option<PathBuf>,
133 logappend: Option<OnOff>,
134}
135
136#[derive(Default, Builder)]
137pub struct CharPty {
138 id: String,
139 mux: Option<OnOff>,
140 logfile: Option<PathBuf>,
141 logappend: Option<OnOff>,
142}
143
144#[derive(Default, Builder)]
145pub struct CharStdio {
146 id: String,
147 mux: Option<OnOff>,
148 signal: Option<OnOff>,
149 logfile: Option<PathBuf>,
150 logappend: Option<OnOff>,
151}
152
153#[derive(Default, Builder)]
154pub struct CharBraille {
155 id: String,
156 mux: Option<OnOff>,
157 logfile: Option<PathBuf>,
158 logappend: Option<OnOff>,
159}
160#[derive(Default, Builder)]
161pub struct CharSerial {
162 id: String,
163 path: PathBuf,
164 mux: Option<OnOff>,
165 logfile: Option<PathBuf>,
166 logappend: Option<OnOff>,
167}
168#[derive(Default, Builder)]
169pub struct CharParallel {
170 id: String,
171 path: PathBuf,
172 mux: Option<OnOff>,
173 logfile: Option<PathBuf>,
174 logappend: Option<OnOff>,
175}
176
177#[derive(Default, Builder)]
178pub struct CharSpice {
179 id: String,
180 name: String,
181 debug: Option<String>,
182 logfile: Option<PathBuf>,
183 logappend: Option<OnOff>,
184}
185
186pub enum CharDev {
187 Null(CharNull),
188 Socket(CharSocket),
189 Udp(CharUdp),
190 MsMouse(CharMsMouse),
191 Hub(CharHub),
192 Vc(CharVc),
193 RingBuf(CharRingBuf),
194 File(CharFile),
195 Pipe(CharPipe),
196 Win32Console(CharWin32Console),
197 Win32Serial(CharWin32Serial),
198 Pty(CharPty),
199 Stdio(CharStdio),
200 Braille(CharBraille),
201 Serial(CharSerial),
202 Parallel(CharParallel),
203 SpiceVmc(CharSpice),
204 SpicePort(CharSpice),
205}
206
207impl ToCommand for CharDev {
208 fn to_command(&self) -> Vec<String> {
209 let mut cmd = vec!["-chardev".to_string()];
210
211 let mut args = vec![];
212 match self {
213 CharDev::Null(null) => {
214 args.push("null".to_string());
215 args.push(format!("id={}", null.id));
216 }
217 CharDev::Socket(socket) => match socket {
218 CharSocket::Tcp(tcp) => {
219 args.push("socket".to_string());
220 args.push(format!("id={}", tcp.id));
221 if let Some(host) = &tcp.host {
222 args.push(format!("host={}", host));
223 }
224 args.push(format!("port={}", tcp.port));
225 if let Some(to) = &tcp.to {
226 args.push(format!("to={}", to));
227 }
228 if let Some(ipv4) = &tcp.ipv4 {
229 args.push(format!("ipv4={}", ipv4.to_arg()));
230 }
231 if let Some(ipv6) = &tcp.ipv6 {
232 args.push(format!("ipv6={}", ipv6.to_arg()));
233 }
234 if let Some(nodelay) = &tcp.nodelay {
235 args.push(format!("nodelay={}", nodelay.to_arg()));
236 }
237 if let Some(server) = &tcp.server {
238 args.push(format!("server={}", server.to_arg()));
239 }
240 if let Some(wait) = &tcp.wait {
241 args.push(format!("wait={}", wait.to_arg()));
242 }
243 if let Some(telnet) = &tcp.telnet {
244 args.push(format!("telnet={}", telnet.to_arg()));
245 }
246 if let Some(websocket) = &tcp.websocket {
247 args.push(format!("websocket={}", websocket.to_arg()));
248 }
249 if let Some(reconnect_ms) = &tcp.reconnect_ms {
250 args.push(format!("reconnect-ms={}", reconnect_ms));
251 }
252 if let Some(mux) = &tcp.mux {
253 args.push(format!("mux={}", mux.to_arg()));
254 }
255 if let Some(logfile) = &tcp.logfile {
256 args.push(format!("logfile={}", logfile.display()));
257 }
258 if let Some(logappend) = &tcp.logappend {
259 args.push(format!("logappend={}", logappend.to_arg()));
260 }
261 if let Some(tls_creds) = &tcp.tls_creds {
262 args.push(format!("tls-creds={}", tls_creds));
263 }
264 if let Some(tls_authz) = &tcp.tls_authz {
265 args.push(format!("tls-authz={}", tls_authz));
266 }
267 }
268 CharSocket::Uds(uds) => {
269 args.push("socket".to_string());
270 args.push(format!("id={}", uds.id));
271 args.push(format!("path={}", uds.path.display()));
272
273 if let Some(server) = &uds.server {
274 args.push(format!("server={}", server.to_arg()));
275 }
276 if let Some(wait) = &uds.wait {
277 args.push(format!("wait={}", wait.to_arg()));
278 }
279 if let Some(telnet) = &uds.telnet {
280 args.push(format!("telnet={}", telnet.to_arg()));
281 }
282 if let Some(websocket) = &uds.websocket {
283 args.push(format!("websocket={}", websocket.to_arg()));
284 }
285 if let Some(reconnect_ms) = &uds.reconnect_ms {
286 args.push(format!("reconnect-ms={}", reconnect_ms));
287 }
288 if let Some(mux) = &uds.mux {
289 args.push(format!("mux={}", mux.to_arg()));
290 }
291 if let Some(logfile) = &uds.logfile {
292 args.push(format!("logfile={}", logfile.display()));
293 }
294 if let Some(logappend) = &uds.logappend {
295 args.push(format!("logappend={}", logappend.to_arg()));
296 }
297 if let Some(abstract_opt) = &uds.abstract_opt {
298 args.push(format!("abstract={}", abstract_opt.to_arg()));
299 }
300 if let Some(tight) = &uds.tight {
301 args.push(format!("tight={}", tight.to_arg()));
302 }
303 }
304 },
305 CharDev::Udp(udp) => {
306 args.push("udp".to_string());
307 args.push(format!("id={}", udp.id));
308
309 if let Some(host) = &udp.host {
310 args.push(format!("host={}", host));
311 }
312 args.push(format!("port={}", udp.port));
313 if let Some(localaddr) = &udp.localaddr {
314 args.push(format!("localaddr={}", localaddr));
315 }
316 if let Some(localport) = &udp.localport {
317 args.push(format!("localport={}", localport));
318 }
319 if let Some(ipv4) = &udp.ipv4 {
320 args.push(format!("ipv4={}", ipv4.to_arg()));
321 }
322 if let Some(ipv6) = &udp.ipv6 {
323 args.push(format!("ipv6={}", ipv6.to_arg()));
324 }
325 if let Some(mux) = &udp.mux {
326 args.push(format!("mux={}", mux.to_arg()));
327 }
328 if let Some(logfile) = &udp.logfile {
329 args.push(format!("logfile={}", logfile.display()));
330 }
331 if let Some(logappend) = &udp.logappend {
332 args.push(format!("logappend={}", logappend.to_arg()));
333 }
334 }
335 CharDev::MsMouse(msmouse) => {
336 args.push("msmouse".to_string());
337 args.push(format!("id={}", msmouse.id));
338 if let Some(mux) = &msmouse.mux {
339 args.push(format!("mux={}", mux.to_arg()));
340 }
341 if let Some(logfile) = &msmouse.logfile {
342 args.push(format!("logfile={}", logfile.display()));
343 }
344 if let Some(logappend) = &msmouse.logappend {
345 args.push(format!("logappend={}", logappend.to_arg()));
346 }
347 }
348 CharDev::Hub(hub) => {
349 args.push("hub".to_string());
350 args.push(format!("id={}", hub.id));
351 if let Some(chardevs) = &hub.chardevs {
352 for (chardev, n) in chardevs {
353 args.push(format!("chardevs.{}={}", n, chardev));
354 }
355 }
356 }
357 CharDev::Vc(vc) => {
358 args.push("vc".to_string());
359 args.push(format!("id={}", vc.id));
360 if let Some(width) = &vc.width {
361 args.push(format!("width={}", width));
362 }
363 if let Some(height) = &vc.height {
364 args.push(format!("height={}", height));
365 }
366 if let Some(cols) = &vc.cols {
367 args.push(format!("cols={}", cols));
368 }
369 if let Some(rows) = &vc.rows {
370 args.push(format!("rows={}", rows));
371 }
372 if let Some(mux) = &vc.mux {
373 args.push(format!("mux={}", mux.to_arg()));
374 }
375 if let Some(logvc) = &vc.logfile {
376 args.push(format!("logfile={}", logvc.display()));
377 }
378 if let Some(logappend) = &vc.logappend {
379 args.push(format!("logappend={}", logappend.to_arg()));
380 }
381 }
382 CharDev::RingBuf(ringbuf) => {
383 args.push("ringbuf".to_string());
384 args.push(format!("id={}", ringbuf.id));
385 if let Some(size) = &ringbuf.size {
386 args.push(format!("size={}", size));
387 }
388 if let Some(logfile) = &ringbuf.logfile {
389 args.push(format!("logfile={}", logfile.display()));
390 }
391 if let Some(logappend) = &ringbuf.logappend {
392 args.push(format!("logappend={}", logappend.to_arg()));
393 }
394 }
395 CharDev::File(file) => {
396 args.push("file".to_string());
397 args.push(format!("id={}", file.id));
398 args.push(format!("path={}", file.path.display()));
399 if let Some(input_path) = &file.input_path {
400 args.push(format!("input-path={}", input_path.display()));
401 }
402 if let Some(mux) = &file.mux {
403 args.push(format!("mux={}", mux.to_arg()));
404 }
405 if let Some(logfile) = &file.logfile {
406 args.push(format!("logfile={}", logfile.display()));
407 }
408 if let Some(logappend) = &file.logappend {
409 args.push(format!("logappend={}", logappend.to_arg()));
410 }
411 }
412 CharDev::Pipe(pipe) => {
413 args.push("pipe".to_string());
414 args.push(format!("id={}", pipe.id));
415 if let Some(mux) = &pipe.mux {
416 args.push(format!("mux={}", mux.to_arg()));
417 }
418 if let Some(logpipe) = &pipe.logfile {
419 args.push(format!("logfile={}", logpipe.display()));
420 }
421 if let Some(logappend) = &pipe.logappend {
422 args.push(format!("logappend={}", logappend.to_arg()));
423 }
424 }
425 CharDev::Win32Console(console) => {
426 args.push("console".to_string());
427 args.push(format!("id={}", console.id));
428 if let Some(mux) = &console.mux {
429 args.push(format!("mux={}", mux.to_arg()));
430 }
431 if let Some(logconsole) = &console.logfile {
432 args.push(format!("logfile={}", logconsole.display()));
433 }
434 if let Some(logappend) = &console.logappend {
435 args.push(format!("logappend={}", logappend.to_arg()));
436 }
437 }
438 CharDev::Win32Serial(serial) => {
439 args.push("serial".to_string());
440 args.push(format!("id={}", serial.id));
441 args.push(format!("path={}", serial.path.display()));
442 if let Some(mux) = &serial.mux {
443 args.push(format!("mux={}", mux.to_arg()));
444 }
445 if let Some(logserial) = &serial.logfile {
446 args.push(format!("logfile={}", logserial.display()));
447 }
448 if let Some(logappend) = &serial.logappend {
449 args.push(format!("logappend={}", logappend.to_arg()));
450 }
451 }
452 CharDev::Pty(pty) => {
453 args.push("pty".to_string());
454 args.push(format!("id={}", pty.id));
455 if let Some(mux) = &pty.mux {
456 args.push(format!("mux={}", mux.to_arg()));
457 }
458 if let Some(logpty) = &pty.logfile {
459 args.push(format!("logfile={}", logpty.display()));
460 }
461 if let Some(logappend) = &pty.logappend {
462 args.push(format!("logappend={}", logappend.to_arg()));
463 }
464 }
465 CharDev::Stdio(stdio) => {
466 args.push("stdio".to_string());
467 args.push(format!("id={}", stdio.id));
468 if let Some(mux) = &stdio.mux {
469 args.push(format!("mux={}", mux.to_arg()));
470 }
471 if let Some(signal) = &stdio.signal {
472 args.push(format!("signal={}", signal.to_arg()));
473 }
474 if let Some(stdio) = &stdio.logfile {
475 args.push(format!("logfile={}", stdio.display()));
476 }
477 if let Some(logappend) = &stdio.logappend {
478 args.push(format!("logappend={}", logappend.to_arg()));
479 }
480 }
481 CharDev::Braille(braille) => {
482 args.push("braille".to_string());
483 args.push(format!("id={}", braille.id));
484 if let Some(mux) = &braille.mux {
485 args.push(format!("mux={}", mux.to_arg()));
486 }
487 if let Some(braille) = &braille.logfile {
488 args.push(format!("logfile={}", braille.display()));
489 }
490 if let Some(logappend) = &braille.logappend {
491 args.push(format!("logappend={}", logappend.to_arg()));
492 }
493 }
494 CharDev::Serial(serial) => {
495 args.push("serial".to_string());
496 args.push(format!("id={}", serial.id));
497 args.push(format!("path={}", serial.path.display()));
498 if let Some(mux) = &serial.mux {
499 args.push(format!("mux={}", mux.to_arg()));
500 }
501 if let Some(serial) = &serial.logfile {
502 args.push(format!("logfile={}", serial.display()));
503 }
504 if let Some(logappend) = &serial.logappend {
505 args.push(format!("logappend={}", logappend.to_arg()));
506 }
507 }
508 CharDev::Parallel(parallel) => {
509 args.push("parallel".to_string());
510 args.push(format!("id={}", parallel.id));
511 args.push(format!("path={}", parallel.path.display()));
512 if let Some(mux) = ¶llel.mux {
513 args.push(format!("mux={}", mux.to_arg()));
514 }
515 if let Some(parallel) = ¶llel.logfile {
516 args.push(format!("logfile={}", parallel.display()));
517 }
518 if let Some(logappend) = ¶llel.logappend {
519 args.push(format!("logappend={}", logappend.to_arg()));
520 }
521 }
522 CharDev::SpiceVmc(spice) => {
523 args.push("spicevmc".to_string());
524 args.push(format!("id={}", spice.id));
525 args.push(format!("name={}", spice.name));
526 if let Some(debug) = &spice.debug {
527 args.push(format!("debug={}", debug));
528 }
529 if let Some(parallel) = &spice.logfile {
530 args.push(format!("logfile={}", parallel.display()));
531 }
532 if let Some(logappend) = &spice.logappend {
533 args.push(format!("logappend={}", logappend.to_arg()));
534 }
535 }
536 CharDev::SpicePort(spice) => {
537 args.push("spiceport".to_string());
538 args.push(format!("id={}", spice.id));
539 args.push(format!("name={}", spice.name));
540 if let Some(debug) = &spice.debug {
541 args.push(format!("debug={}", debug));
542 }
543 if let Some(parallel) = &spice.logfile {
544 args.push(format!("logfile={}", parallel.display()));
545 }
546 if let Some(logappend) = &spice.logappend {
547 args.push(format!("logappend={}", logappend.to_arg()));
548 }
549 }
550 }
551
552 cmd.push(args.join(","));
553
554 cmd
555 }
556}