qemu_command_builder/
chardev.rs

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