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(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) = &parallel.mux {
513                    args.push(format!("mux={}", mux.to_arg()));
514                }
515                if let Some(parallel) = &parallel.logfile {
516                    args.push(format!("logfile={}", parallel.display()));
517                }
518                if let Some(logappend) = &parallel.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}