running_process/boot_autostart/
linux.rs1use std::path::{Path, PathBuf};
10use std::process::Command;
11
12use super::{shell_quote_single, BootAutostartError, UnitPath};
13
14const UNIT_FILENAME: &str = "runpm-daemon.service";
16
17pub fn render_unit(daemon_binary: &Path) -> String {
19 let bin = shell_quote_single(&daemon_binary.to_string_lossy());
20 format!(
21 "[Unit]\n\
22 Description=runpm process supervisor (running-process daemon)\n\
23 After=default.target\n\
24 \n\
25 [Service]\n\
26 Type=simple\n\
27 ExecStart={bin} start\n\
28 ExecStop={bin} stop\n\
29 Restart=on-failure\n\
30 RestartSec=5\n\
31 \n\
32 [Install]\n\
33 WantedBy=default.target\n",
34 )
35}
36
37pub fn unit_path() -> Result<PathBuf, BootAutostartError> {
40 let base = match std::env::var_os("XDG_CONFIG_HOME") {
41 Some(v) if !v.is_empty() => PathBuf::from(v),
42 _ => {
43 let home = std::env::var_os("HOME").ok_or_else(|| {
44 BootAutostartError::Resolve("neither XDG_CONFIG_HOME nor HOME is set".into())
45 })?;
46 PathBuf::from(home).join(".config")
47 }
48 };
49 Ok(base.join("systemd").join("user").join(UNIT_FILENAME))
50}
51
52pub fn install(daemon_binary: &Path) -> Result<UnitPath, BootAutostartError> {
53 let path = unit_path()?;
54 if let Some(parent) = path.parent() {
55 std::fs::create_dir_all(parent)?;
56 }
57 std::fs::write(&path, render_unit(daemon_binary))?;
58
59 let _ = Command::new("systemctl")
65 .args(["--user", "daemon-reload"])
66 .status();
67 match Command::new("systemctl")
68 .args(["--user", "enable", UNIT_FILENAME])
69 .status()
70 {
71 Ok(s) if s.success() => {}
72 Ok(s) => {
73 eprintln!("warning: systemctl --user enable {UNIT_FILENAME} returned non-zero ({s:?})");
74 }
75 Err(e) => {
76 eprintln!("warning: systemctl --user enable {UNIT_FILENAME} failed to spawn: {e}");
77 }
78 }
79
80 Ok(UnitPath(path))
81}
82
83pub fn uninstall() -> Result<(), BootAutostartError> {
84 let path = unit_path()?;
85 let _ = Command::new("systemctl")
86 .args(["--user", "disable", UNIT_FILENAME])
87 .status();
88 if path.exists() {
89 std::fs::remove_file(&path)?;
90 }
91 let _ = Command::new("systemctl")
92 .args(["--user", "daemon-reload"])
93 .status();
94 Ok(())
95}