diff --git a/src/action/common/provision_determinate_nixd.rs b/src/action/common/provision_determinate_nixd.rs index 3f0f4e2dd..9d2d5764f 100644 --- a/src/action/common/provision_determinate_nixd.rs +++ b/src/action/common/provision_determinate_nixd.rs @@ -10,7 +10,7 @@ use crate::{ use super::place_nix_configuration::{NIX_CONF, NIX_CONF_FOLDER}; -const DETERMINATE_NIXD_BINARY_PATH: &str = "/usr/local/bin/determinate-nixd"; +const DETERMINATE_NIXD_BINARY_PATH: &str = "/var/usrlocal/bin/determinate-nixd"; /** Provision the determinate-nixd binary */ diff --git a/src/action/linux/mod.rs b/src/action/linux/mod.rs index 47dfc991a..9d9bc1a6c 100644 --- a/src/action/linux/mod.rs +++ b/src/action/linux/mod.rs @@ -1,11 +1,11 @@ pub(crate) mod ensure_steamos_nix_directory; pub(crate) mod provision_selinux; pub(crate) mod revert_clean_steamos_nix_offload; -pub(crate) mod start_systemd_unit; +pub(crate) mod start_or_enable_systemd_unit; pub(crate) mod systemctl_daemon_reload; pub use ensure_steamos_nix_directory::EnsureSteamosNixDirectory; pub use provision_selinux::ProvisionSelinux; pub use revert_clean_steamos_nix_offload::RevertCleanSteamosNixOffload; -pub use start_systemd_unit::{StartSystemdUnit, StartSystemdUnitError}; +pub use start_or_enable_systemd_unit::{StartOrEnableSystemdUnit, StartSystemdUnitError}; pub use systemctl_daemon_reload::SystemctlDaemonReload; diff --git a/src/action/linux/start_systemd_unit.rs b/src/action/linux/start_or_enable_systemd_unit.rs similarity index 78% rename from src/action/linux/start_systemd_unit.rs rename to src/action/linux/start_or_enable_systemd_unit.rs index ac461ae95..bd65a4ed7 100644 --- a/src/action/linux/start_systemd_unit.rs +++ b/src/action/linux/start_or_enable_systemd_unit.rs @@ -10,17 +10,19 @@ use crate::action::{Action, ActionDescription}; Start a given systemd unit */ #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)] -#[serde(tag = "action_name", rename = "start_systemd_unit")] -pub struct StartSystemdUnit { +#[serde(tag = "action_name", rename = "start_or_enable_systemd_unit")] +pub struct StartOrEnableSystemdUnit { unit: String, enable: bool, + start: bool, } -impl StartSystemdUnit { +impl StartOrEnableSystemdUnit { #[tracing::instrument(level = "debug", skip_all)] pub async fn plan( unit: impl AsRef, enable: bool, + start: bool, ) -> Result, ActionError> { let unit = unit.as_ref(); let mut command = Command::new("systemctl"); @@ -42,6 +44,7 @@ impl StartSystemdUnit { action: Self { unit: unit.to_string(), enable, + start, }, state, }) @@ -49,19 +52,19 @@ impl StartSystemdUnit { } #[async_trait::async_trait] -#[typetag::serde(name = "start_systemd_unit")] -impl Action for StartSystemdUnit { +#[typetag::serde(name = "start_or_enable_systemd_unit")] +impl Action for StartOrEnableSystemdUnit { fn action_tag() -> ActionTag { - ActionTag("start_systemd_unit") + ActionTag("start_or_enable_systemd_unit") } fn tracing_synopsis(&self) -> String { - format!("Enable (and start) the systemd unit `{}`", self.unit) + format!("Enable (and/or start) the systemd unit `{}`", self.unit) } fn tracing_span(&self) -> Span { span!( tracing::Level::DEBUG, - "start_systemd_unit", + "start_or_enable_systemd_unit", unit = %self.unit, ) } @@ -72,10 +75,14 @@ impl Action for StartSystemdUnit { #[tracing::instrument(level = "debug", skip_all)] async fn execute(&mut self) -> Result<(), ActionError> { - let Self { unit, enable } = self; - - match enable { - true => { + let Self { + unit, + enable, + start, + } = self; + + match (enable, start) { + (true, true) => { // TODO(@Hoverbear): Handle proxy vars execute_command( Command::new("systemctl") @@ -88,7 +95,7 @@ impl Action for StartSystemdUnit { .await .map_err(Self::error)?; }, - false => { + (false, true) => { // TODO(@Hoverbear): Handle proxy vars execute_command( Command::new("systemctl") @@ -100,6 +107,21 @@ impl Action for StartSystemdUnit { .await .map_err(Self::error)?; }, + (true, false) => { + // TODO(@Hoverbear): Handle proxy vars + execute_command( + Command::new("systemctl") + .process_group(0) + .arg("enable") + .arg(unit) + .stdin(std::process::Stdio::null()), + ) + .await + .map_err(Self::error)?; + }, + (false, false) => { + tracing::warn!("Told to neither enable nor start unit {}. Noop!", unit); + }, } Ok(()) diff --git a/src/planner/ostree.rs b/src/planner/ostree.rs index 3ad0f557c..4122b44d1 100644 --- a/src/planner/ostree.rs +++ b/src/planner/ostree.rs @@ -7,14 +7,14 @@ use crate::{ }, linux::{ provision_selinux::{DETERMINATE_SELINUX_POLICY_PP_CONTENT, SELINUX_POLICY_PP_CONTENT}, - ProvisionSelinux, StartSystemdUnit, SystemctlDaemonReload, + ProvisionSelinux, StartOrEnableSystemdUnit, SystemctlDaemonReload, }, StatefulAction, }, distribution::Distribution, error::HasExpectedErrors, planner::{Planner, PlannerError}, - settings::{CommonSettings, InitSystem, InstallSettingsError}, + settings::{CommonSettings, InitSettings, InitSystem, InstallSettingsError}, Action, BuiltinPlanner, }; use std::{collections::HashMap, path::PathBuf}; @@ -36,6 +36,8 @@ pub struct Ostree { persistence: PathBuf, #[cfg_attr(feature = "cli", clap(flatten))] pub settings: CommonSettings, + #[cfg_attr(feature = "cli", clap(flatten))] + pub init: InitSettings, } #[async_trait::async_trait] @@ -45,19 +47,23 @@ impl Planner for Ostree { Ok(Self { persistence: PathBuf::from("/var/home/nix"), settings: CommonSettings::default().await?, + init: InitSettings::default().await?, }) } async fn plan(&self) -> Result>>, PlannerError> { let has_selinux = detect_selinux().await?; - let mut plan = vec![ - // Primarily for uninstall - SystemctlDaemonReload::plan() - .await - .map_err(PlannerError::Action)? - .boxed(), - ]; + let mut plan = vec![]; + if self.init.start_daemon { + // Primarily for uninstall + plan.push( + SystemctlDaemonReload::plan() + .await + .map_err(PlannerError::Action)? + .boxed(), + ) + } plan.push( CreateDirectory::plan(&self.persistence, None, None, 0o0755, true) .await @@ -171,7 +177,7 @@ impl Planner for Ostree { } plan.push( - StartSystemdUnit::plan("nix.mount".to_string(), false) + StartOrEnableSystemdUnit::plan("nix.mount".to_string(), false, self.init.start_daemon) .await .map_err(PlannerError::Action)? .boxed(), @@ -229,16 +235,20 @@ impl Planner for Ostree { ); plan.push( - ConfigureUpstreamInitService::plan(InitSystem::Systemd, true) + ConfigureUpstreamInitService::plan(InitSystem::Systemd, self.init.start_daemon) .await .map_err(PlannerError::Action)? .boxed(), ); plan.push( - StartSystemdUnit::plan("ensure-symlinked-units-resolve.service".to_string(), true) - .await - .map_err(PlannerError::Action)? - .boxed(), + StartOrEnableSystemdUnit::plan( + "ensure-symlinked-units-resolve.service".to_string(), + true, + self.init.start_daemon, + ) + .await + .map_err(PlannerError::Action)? + .boxed(), ); plan.push( RemoveDirectory::plan(crate::settings::SCRATCH_DIR) @@ -246,12 +256,15 @@ impl Planner for Ostree { .map_err(PlannerError::Action)? .boxed(), ); - plan.push( - SystemctlDaemonReload::plan() - .await - .map_err(PlannerError::Action)? - .boxed(), - ); + + if self.init.start_daemon { + plan.push( + SystemctlDaemonReload::plan() + .await + .map_err(PlannerError::Action)? + .boxed(), + ); + } Ok(plan) } @@ -260,10 +273,12 @@ impl Planner for Ostree { let Self { persistence, settings, + init, } = self; let mut map = HashMap::default(); map.extend(settings.settings()?); + map.extend(init.settings()?); map.insert( "persistence".to_string(), serde_json::to_value(persistence)?, @@ -302,7 +317,9 @@ impl Planner for Ostree { async fn pre_uninstall_check(&self) -> Result<(), PlannerError> { check_not_wsl1()?; - check_systemd_active()?; + if self.init.init == InitSystem::Systemd && self.init.start_daemon { + check_systemd_active()?; + } Ok(()) } @@ -314,7 +331,9 @@ impl Planner for Ostree { check_not_wsl1()?; - check_systemd_active()?; + if self.init.init == InitSystem::Systemd && self.init.start_daemon { + check_systemd_active()?; + } Ok(()) } diff --git a/src/planner/steam_deck.rs b/src/planner/steam_deck.rs index 8652eac1c..24dad8304 100644 --- a/src/planner/steam_deck.rs +++ b/src/planner/steam_deck.rs @@ -108,7 +108,7 @@ use crate::{ ProvisionDeterminateNixd, ProvisionNix, }, linux::{ - EnsureSteamosNixDirectory, RevertCleanSteamosNixOffload, StartSystemdUnit, + EnsureSteamosNixDirectory, RevertCleanSteamosNixOffload, StartOrEnableSystemdUnit, SystemctlDaemonReload, }, Action, StatefulAction, @@ -265,9 +265,10 @@ impl Planner for SteamDeck { .map_err(PlannerError::Action)?; actions.push(ensure_steamos_nix_directory.boxed()); - let start_nix_mount = StartSystemdUnit::plan("nix.mount".to_string(), true) - .await - .map_err(PlannerError::Action)?; + let start_nix_mount = + StartOrEnableSystemdUnit::plan("nix.mount".to_string(), true, true) + .await + .map_err(PlannerError::Action)?; actions.push(start_nix_mount.boxed()); } @@ -337,7 +338,7 @@ impl Planner for SteamDeck { if requires_nix_bind_mount { actions.push( - StartSystemdUnit::plan("nix.mount".to_string(), false) + StartOrEnableSystemdUnit::plan("nix.mount".to_string(), false, true) .await .map_err(PlannerError::Action)? .boxed(), @@ -371,10 +372,14 @@ impl Planner for SteamDeck { .await .map_err(PlannerError::Action)? .boxed(), - StartSystemdUnit::plan("ensure-symlinked-units-resolve.service".to_string(), true) - .await - .map_err(PlannerError::Action)? - .boxed(), + StartOrEnableSystemdUnit::plan( + "ensure-symlinked-units-resolve.service".to_string(), + true, + true, + ) + .await + .map_err(PlannerError::Action)? + .boxed(), RemoveDirectory::plan(crate::settings::SCRATCH_DIR) .await .map_err(PlannerError::Action)? diff --git a/tests/fixtures/linux/steam-deck.json b/tests/fixtures/linux/steam-deck.json index cc27d0e70..c27e3e8e8 100644 --- a/tests/fixtures/linux/steam-deck.json +++ b/tests/fixtures/linux/steam-deck.json @@ -21,9 +21,10 @@ }, { "action": { - "action_name": "start_systemd_unit", + "action_name": "start_or_enable_systemd_unit", "unit": "nix.mount", - "enable": true + "enable": true, + "start": true }, "state": "Skipped" }, @@ -1148,9 +1149,10 @@ }, { "action": { - "action_name": "start_systemd_unit", + "action_name": "start_or_enable_systemd_unit", "unit": "ensure-symlinked-units-resolve.service", - "enable": true + "enable": true, + "start": true }, "state": "Completed" },