Skip to main content

podbox/codegen/quadlet/
devices.rs

1//! Device passthrough emitters: GPU, hardware presets, secrets.
2//!
3//! Extracted verbatim from `quadlet.rs`; see `super` for the unit entry
4//! points.
5
6use crate::config::{Config, GpuMode};
7use crate::env::HostEnv;
8
9pub(super) fn emit_gpu(lines: &mut Vec<String>, config: &Config, env: &HostEnv) {
10    match config.integration.gpu {
11        GpuMode::Enabled => {
12            lines.push("AddDevice=/dev/dri".into());
13            lines.push(String::new());
14        }
15        GpuMode::Nvidia => {
16            lines.push("AddDevice=/dev/dri".into());
17            lines.push("AddDevice=-/dev/nvidiactl".into());
18            lines.push("AddDevice=-/dev/nvidia0".into());
19            if env.gpu_has_nvidia_uvm {
20                lines.push("AddDevice=-/dev/nvidia-uvm".into());
21            }
22            lines.push(String::new());
23        }
24        GpuMode::Auto => {
25            if env.gpu_has_dri {
26                lines.push("AddDevice=/dev/dri".into());
27            }
28            if env.gpu_has_nvidia {
29                lines.push("AddDevice=-/dev/nvidiactl".into());
30                lines.push("AddDevice=-/dev/nvidia0".into());
31                if env.gpu_has_nvidia_uvm {
32                    lines.push("AddDevice=-/dev/nvidia-uvm".into());
33                }
34            }
35            if env.gpu_has_dri || env.gpu_has_nvidia {
36                lines.push(String::new());
37            }
38        }
39        GpuMode::Disabled => {}
40    }
41}
42
43pub fn emit_hardware_devices(lines: &mut Vec<String>, config: &Config) {
44    let hw = &config.integration.hardware;
45
46    let mut emitted = false;
47
48    if hw.kvm {
49        lines.push("AddDevice=-/dev/kvm".into());
50        emitted = true;
51    }
52
53    if hw.joystick {
54        lines.push("AddDevice=-/dev/uinput".into());
55        lines.push("AddDevice=-/dev/input".into());
56        emitted = true;
57    }
58
59    if hw.webcam {
60        for i in 0..16 {
61            lines.push(format!("AddDevice=-/dev/video{i}"));
62            lines.push(format!("AddDevice=-/dev/media{i}"));
63        }
64        emitted = true;
65    }
66
67    if hw.serial {
68        for i in 0..8 {
69            lines.push(format!("AddDevice=-/dev/ttyUSB{i}"));
70            lines.push(format!("AddDevice=-/dev/ttyACM{i}"));
71        }
72        emitted = true;
73    }
74
75    if hw.yubikey {
76        lines.push("Volume=-%t/pcscd/pcscd.comm:/run/pcscd/pcscd.comm:ro".into());
77        for i in 0..16 {
78            lines.push(format!("AddDevice=-/dev/hidraw{i}"));
79        }
80        emitted = true;
81    }
82
83    if emitted {
84        lines.push(String::new());
85    }
86}
87
88pub fn emit_secrets(lines: &mut Vec<String>, config: &Config) {
89    use crate::config::{SecretEntry, SecretSource, SecretType};
90
91    let mut emitted = false;
92    for secret in &config.security.secrets {
93        emitted = true;
94        match secret {
95            SecretEntry::Simple(name) => {
96                lines.push(format!("Secret={name},type=env,target={name}"));
97            }
98            SecretEntry::Detailed {
99                name,
100                secret_type,
101                target,
102                mode,
103                source,
104            } => match source {
105                SecretSource::Podman => {
106                    let mut opts = vec![name.clone()];
107                    match secret_type {
108                        SecretType::Env => {
109                            opts.push("type=env".into());
110                            if let Some(t) = target {
111                                opts.push(format!("target={t}"));
112                            }
113                        }
114                        SecretType::Mount => {
115                            opts.push("type=mount".into());
116                            if let Some(t) = target {
117                                opts.push(format!("target={t}"));
118                            }
119                            if let Some(m) = mode {
120                                opts.push(format!("mode={m}"));
121                            }
122                            opts.push("uid=%U".into());
123                            opts.push("gid=%G".into());
124                        }
125                    }
126                    lines.push(format!("Secret={}", opts.join(",")));
127                }
128                SecretSource::Systemd => {
129                    lines.push(format!(
130                        "Environment={}=%d/{}",
131                        target.as_deref().unwrap_or(name),
132                        name
133                    ));
134                }
135            },
136        }
137    }
138    if emitted {
139        lines.push(String::new());
140    }
141}