1
0
mirror of https://github.com/containers/bootc.git synced 2026-02-05 15:45:53 +01:00

composefs: Add option to reset soft reboot state

Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
This commit is contained in:
Pragyan Poudyal
2026-01-12 10:51:59 +05:30
committed by Colin Walters
parent 4c22d1664e
commit 7dd3683034
3 changed files with 66 additions and 7 deletions

View File

@@ -10,25 +10,70 @@ use bootc_initramfs_setup::setup_root;
use bootc_kernel_cmdline::utf8::Cmdline;
use bootc_mount::{PID1, bind_mount_from_pidns};
use camino::Utf8Path;
use cap_std_ext::cap_std::ambient_authority;
use cap_std_ext::cap_std::fs::Dir;
use cap_std_ext::dirext::CapStdExtDirExt;
use fn_error_context::context;
use ostree_ext::systemd_has_soft_reboot;
use rustix::mount::{unmount, UnmountFlags};
use std::{fs::create_dir_all, os::unix::process::CommandExt, path::PathBuf, process::Command};
const NEXTROOT: &str = "/run/nextroot";
#[context("Resetting soft reboot state")]
fn reset_soft_reboot() -> Result<()> {
let run = Utf8Path::new("/run");
bind_mount_from_pidns(PID1, &run, &run, true).context("Bind mounting /run")?;
let run_dir = Dir::open_ambient_dir("/run", ambient_authority()).context("Opening run")?;
let nextroot = run_dir
.open_dir_optional("nextroot")
.context("Opening nextroot")?;
let Some(nextroot) = nextroot else {
tracing::debug!("Nextroot is not a directory");
println!("No deployment staged for soft rebooting");
return Ok(());
};
let nextroot_mounted = nextroot
.is_mountpoint(".")?
.ok_or_else(|| anyhow::anyhow!("Failed to get mount info"))?;
if !nextroot_mounted {
tracing::debug!("Nextroot is not a mountpoint");
println!("No deployment staged for soft rebooting");
return Ok(());
}
unmount(NEXTROOT, UnmountFlags::DETACH).context("Unmounting nextroot")?;
println!("Soft reboot state cleared successfully");
Ok(())
}
/// Checks if the provided deployment is soft reboot capable, and soft reboots the system if
/// argument `reboot` is true
#[context("Soft rebooting")]
pub(crate) async fn prepare_soft_reboot_composefs(
storage: &Storage,
booted_cfs: &BootedComposefs,
deployment_id: &String,
deployment_id: Option<&String>,
reboot: bool,
reset: bool,
) -> Result<()> {
if !systemd_has_soft_reboot() {
anyhow::bail!("System does not support soft reboots")
}
if reset {
return reset_soft_reboot();
}
let deployment_id = deployment_id.ok_or_else(|| anyhow::anyhow!("Expected deployment id"))?;
if *deployment_id == *booted_cfs.cmdline.digest {
anyhow::bail!("Cannot soft-reboot to currently booted deployment");
}

View File

@@ -267,7 +267,7 @@ pub(crate) async fn do_upgrade(
}
if opts.soft_reboot.is_some() {
prepare_soft_reboot_composefs(storage, booted_cfs, &id.to_hex(), true).await?;
prepare_soft_reboot_composefs(storage, booted_cfs, Some(&id.to_hex()), true, false).await?;
}
Ok(())

View File

@@ -618,8 +618,12 @@ pub(crate) enum InternalsOpts {
/// Dump CLI structure as JSON for documentation generation
DumpCliJson,
PrepSoftReboot {
deployment: String,
#[clap(long)]
#[clap(required_unless_present = "reset")]
deployment: Option<String>,
#[clap(long, conflicts_with = "reset")]
reboot: bool,
#[clap(long, conflicts_with = "reboot")]
reset: bool,
reboot: bool,
},
}
@@ -1836,7 +1840,11 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
Ok(())
}
InternalsOpts::PrepSoftReboot { deployment, reboot } => {
InternalsOpts::PrepSoftReboot {
deployment,
reboot,
reset,
} => {
let storage = &get_storage().await?;
match storage.kind()? {
@@ -1845,8 +1853,14 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
anyhow::bail!("soft-reboot only implemented for composefs")
}
BootedStorageKind::Composefs(booted_cfs) => {
prepare_soft_reboot_composefs(&storage, &booted_cfs, &deployment, reboot)
.await
prepare_soft_reboot_composefs(
&storage,
&booted_cfs,
deployment.as_ref(),
reboot,
reset,
)
.await
}
}
}