podbox/quadlet_install/
units.rs1use std::path::Path;
7
8use anyhow::Result;
9
10use crate::systemd;
11
12use super::paths::quadlet_dir;
13
14fn write_custom_units(
17 name: &str,
18 sdir: &Path,
19 socket_content: &str,
20 host_service_content: &str,
21 dbus_proxy_content: Option<&str>,
22 compositor_service_content: Option<&str>,
23) -> Result<()> {
24 std::fs::create_dir_all(sdir)?;
25 std::fs::write(sdir.join(format!("{name}.socket")), socket_content)?;
26 std::fs::write(
27 sdir.join(format!("{name}-host.service")),
28 host_service_content,
29 )?;
30 if let Some(proxy) = dbus_proxy_content {
31 std::fs::write(sdir.join(format!("{name}-proxy.service")), proxy)?;
32 }
33 if let Some(comp) = compositor_service_content {
34 std::fs::write(sdir.join(format!("{name}-compositor.service")), comp)?;
35 }
36 write_clean_stop_dropin(name, sdir)?;
37 Ok(())
38}
39
40fn write_clean_stop_dropin(name: &str, sdir: &Path) -> Result<()> {
47 let dir = sdir.join(format!("{name}.service.d"));
48 std::fs::create_dir_all(&dir)?;
49 std::fs::write(
50 dir.join("99-podbox-clean-stop.conf"),
51 "[Service]\nSuccessExitStatus=0 143 SIGTERM SIGINT\n",
52 )?;
53 Ok(())
54}
55
56pub(crate) fn finalize_units(
58 name: &str,
59 sdir: &Path,
60 socket_content: &str,
61 host_service_content: &str,
62 dbus_proxy_content: Option<&str>,
63 compositor_service_content: Option<&str>,
64 use_wayland_proxy: bool,
65) -> Result<()> {
66 write_custom_units(
67 name,
68 sdir,
69 socket_content,
70 host_service_content,
71 dbus_proxy_content,
72 compositor_service_content,
73 )?;
74 println!("Systemd units installed to {}", sdir.display());
75
76 systemd::daemon_reload()?;
77 systemd::reset_failed(name)?;
78 systemd::stop_socket_and_host(name)?;
79 if use_wayland_proxy {
80 systemd::stop_compositor(name)?;
81 }
82 systemd::enable_now_socket(name)?;
83 Ok(())
84}
85
86pub(crate) fn podman_quadlet_install_files(
91 name: &str,
92 container_content: &str,
93 build_content: Option<&str>,
94) -> Result<()> {
95 let tmp = std::env::temp_dir().join(format!("podbox-install-{name}"));
96 let _ = std::fs::remove_dir_all(&tmp);
97 std::fs::create_dir_all(&tmp)?;
98
99 let container_path = tmp.join(format!("{name}.container"));
100 std::fs::write(&container_path, container_content)?;
101
102 let mut args: Vec<std::ffi::OsString> = vec![
103 "quadlet".into(),
104 "install".into(),
105 "--replace".into(),
106 container_path.into(),
107 ];
108
109 if let Some(bc) = build_content {
110 let build_path = tmp.join(format!("{name}.build"));
111 std::fs::write(&build_path, bc)?;
112 args.push(build_path.into());
113 }
114
115 let output = crate::process::run_piped("podman", &args)?;
116 let _ = std::fs::remove_dir_all(&tmp);
117 if !output.status.success() {
118 let stderr = String::from_utf8_lossy(&output.stderr);
119 anyhow::bail!("podman quadlet install failed: {stderr}");
120 }
121 println!("Quadlet files installed via podman quadlet install.");
122 Ok(())
123}
124
125pub(crate) fn podman_quadlet_install_application(
131 name: &str,
132 container_content: &str,
133 build_content: Option<&str>,
134) -> Result<()> {
135 let tmp = std::env::temp_dir().join(format!("podbox-install-{name}"));
136 let _ = std::fs::remove_dir_all(&tmp);
137 std::fs::create_dir_all(&tmp)?;
138
139 std::fs::write(tmp.join(format!("{name}.container")), container_content)?;
140 if let Some(bc) = build_content {
141 std::fs::write(tmp.join(format!("{name}.build")), bc)?;
142 }
143
144 let args: Vec<std::ffi::OsString> = vec![
145 "quadlet".into(),
146 "install".into(),
147 "--replace".into(),
148 "--application".into(),
149 name.into(),
150 tmp.clone().into(),
151 ];
152
153 let output = crate::process::run_piped("podman", &args)?;
154 let _ = std::fs::remove_dir_all(&tmp);
155 if !output.status.success() {
156 let stderr = String::from_utf8_lossy(&output.stderr);
157 anyhow::bail!("podman quadlet install --application failed: {stderr}");
158 }
159 println!("Quadlet files installed via podman quadlet install --application {name}.");
160 Ok(())
161}
162
163pub(crate) fn remove_flat_units(name: &str) {
168 let qdir = quadlet_dir();
169 for ext in ["container", "build"] {
170 let path = qdir.join(format!("{name}.{ext}"));
171 if !path.exists() {
172 continue;
173 }
174 let args: Vec<std::ffi::OsString> = vec![
176 "quadlet".into(),
177 "rm".into(),
178 format!("{name}.{ext}").into(),
179 ];
180 let _ = crate::process::run_piped("podman", &args);
181 let _ = std::fs::remove_file(&path);
183 }
184}
185
186pub(crate) fn remove_application_dir(name: &str) {
188 let app_dir = quadlet_dir().join(name);
189 if app_dir.is_dir() {
190 let _ = std::fs::remove_dir_all(&app_dir);
191 }
192}