From 75a23646dd51375cd5e28c29f65dfe8dd0e5112d Mon Sep 17 00:00:00 2001 From: DragonSlayer_14 Date: Sat, 19 Sep 2026 21:45:14 +0200 Subject: [PATCH] Fix: Mount-Unit nutzt pro Scope das richtige WantedBy und network-online.target mount_service_unit() schrieb bislang unabhaengig vom Installations-Scope immer "WantedBy=multi-user.target" - fuer eine User-Scope-Installation (systemctl --user) ist dieses Ziel falsch/wirkungslos, da es dort keine Entsprechung hat; die Unit haette nie zuverlaessig automatisch gestartet werden koennen. Nimmt jetzt den Scope entgegen und setzt fuer System "multi-user.target", fuer User "default.target". Ebenso wartete die Unit unabhaengig vom Scope auf network-online.target - auch das ist ein Ziel des System-Managers ohne sinnvolle Entsprechung unter systemctl --user. Die Ordnungsabhaengigkeit (After=/Wants=) wird jetzt nur noch im System-Kontext gesetzt. Co-Authored-By: Claude Sonnet 5 --- src/systemd/mod.rs | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/systemd/mod.rs b/src/systemd/mod.rs index ed265a6..362fcf2 100644 --- a/src/systemd/mod.rs +++ b/src/systemd/mod.rs @@ -32,9 +32,21 @@ fn binary_path() -> String { .unwrap_or_else(|| "/usr/bin/smart-mount".to_string()) } -fn mount_service_unit() -> String { +fn mount_service_unit(scope: Scope) -> String { + let wanted_by = match scope { + Scope::System => "multi-user.target", + Scope::User => "default.target", + }; + // `network-online.target` ist ein Ziel des System-Managers - unter `systemctl --user` gibt + // es dafür keine sinnvolle Entsprechung (die Unit existiert dort nicht bzw. wird nie + // erreicht), die Ordnungsabhängigkeit wäre also für User-Scope-Units wirkungslos statt + // schlicht harmlos. Nur im System-Kontext gesetzt. + let network_wait = match scope { + Scope::System => "After=network-online.target\nWants=network-online.target\n", + Scope::User => "", + }; format!( - "[Unit]\nDescription=smart-mount: mount configured drive pairs at boot\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=oneshot\nExecStart={} mount --all\n\n[Install]\nWantedBy=multi-user.target\n", + "[Unit]\nDescription=smart-mount: mount configured drive pairs at boot\n{network_wait}\n[Service]\nType=oneshot\nExecStart={} mount --all\n\n[Install]\nWantedBy={wanted_by}\n", binary_path() ) } @@ -93,7 +105,7 @@ pub fn install(scope: Scope, watch_interval_secs: u64) -> Result<()> { let dir = unit_dir(scope)?; std::fs::create_dir_all(&dir).map_err(|e| Error::io(&dir, e))?; - std::fs::write(dir.join(MOUNT_SERVICE), mount_service_unit()) + std::fs::write(dir.join(MOUNT_SERVICE), mount_service_unit(scope)) .map_err(|e| Error::io(&dir, e))?; std::fs::write(dir.join(WATCH_SERVICE), watch_service_unit()) .map_err(|e| Error::io(&dir, e))?; @@ -337,6 +349,31 @@ fn cron_schedule_for_interval(interval_secs: u64) -> String { mod tests { use super::*; + #[test] + fn mount_service_unit_system_scope_uses_multi_user_target() { + let unit = mount_service_unit(Scope::System); + assert!(unit.contains("WantedBy=multi-user.target")); + } + + #[test] + fn mount_service_unit_user_scope_uses_default_target() { + let unit = mount_service_unit(Scope::User); + assert!(unit.contains("WantedBy=default.target")); + assert!(!unit.contains("WantedBy=multi-user.target")); + } + + #[test] + fn mount_service_unit_system_scope_waits_for_network_online() { + let unit = mount_service_unit(Scope::System); + assert!(unit.contains("network-online.target")); + } + + #[test] + fn mount_service_unit_user_scope_does_not_reference_network_online_target() { + let unit = mount_service_unit(Scope::User); + assert!(!unit.contains("network-online.target")); + } + #[test] fn managed_cron_block_for_user_crontab_has_no_user_field() { let block = managed_cron_block(120, None);