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) = ¶llel.mux {
543 args.push(format!("mux={}", mux.to_arg()));
544 }
545 if let Some(parallel) = ¶llel.logfile {
546 args.push(format!("logfile={}", parallel.display()));
547 }
548 if let Some(logappend) = ¶llel.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}