From 061393ca42e26b39fdd93ddfa606e513cc10d75b Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 30 Oct 2023 18:15:59 -0400 Subject: [PATCH] Add `upgrade --apply` Closes: https://github.com/containers/bootc/issues/165 Signed-off-by: Colin Walters --- lib/src/cli.rs | 17 +++++++++++++++-- lib/src/lib.rs | 1 + lib/src/reboot.rs | 23 +++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 lib/src/reboot.rs diff --git a/lib/src/cli.rs b/lib/src/cli.rs index e81d0294f..c6fc8da5f 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -33,9 +33,17 @@ pub(crate) struct UpgradeOpts { #[clap(long)] pub(crate) touch_if_changed: Option, - /// Check if an update is available without applying it - #[clap(long)] + /// Check if an update is available without applying it. + #[clap(long, conflicts_with = "apply")] pub(crate) check: bool, + + /// Restart or reboot into the new target image. + /// + /// Currently, this option always reboots. In the future this command + /// will detect the case where no kernel changes are queued, and perform + /// a userspace-only restart. + #[clap(long, conflicts_with = "check")] + pub(crate) apply: bool, } /// Perform an switch operation @@ -364,6 +372,11 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> { if let Some(path) = opts.touch_if_changed { std::fs::write(&path, "").with_context(|| format!("Writing {path}"))?; } + if opts.apply { + crate::reboot::reboot()?; + } + } else { + tracing::debug!("No changes"); } Ok(()) diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 8edebdcb3..43d3c635b 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -16,6 +16,7 @@ pub mod cli; pub(crate) mod deploy; mod lsm; +mod reboot; mod reexec; mod status; mod utils; diff --git a/lib/src/reboot.rs b/lib/src/reboot.rs new file mode 100644 index 000000000..f86cc9f5f --- /dev/null +++ b/lib/src/reboot.rs @@ -0,0 +1,23 @@ +//! Handling of system restarts/reboot + +use std::io::Write; +use std::process::Command; + +use fn_error_context::context; + +/// Initiate a system reboot. +/// This function will only return in case of error. +#[context("Initiating reboot")] +pub(crate) fn reboot() -> anyhow::Result<()> { + // Flush output streams + let _ = std::io::stdout().flush(); + let _ = std::io::stderr().flush(); + let st = Command::new("reboot").status()?; + if !st.success() { + anyhow::bail!("Failed to reboot: {st:?}"); + } + tracing::debug!("Initiated reboot, sleeping forever..."); + loop { + std::thread::park(); + } +}