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);