bootc_lib/bootc_composefs/
soft_reboot.rs1use crate::{
2 bootc_composefs::{
3 service::start_finalize_stated_svc, status::composefs_deployment_status_from,
4 },
5 composefs_consts::COMPOSEFS_CMDLINE,
6 store::{BootedComposefs, Storage},
7};
8use anyhow::{Context, Result};
9use bootc_initramfs_setup::setup_root;
10use bootc_kernel_cmdline::utf8::Cmdline;
11use bootc_mount::{bind_mount_from_pidns, PID1};
12use camino::Utf8Path;
13use fn_error_context::context;
14use ostree_ext::systemd_has_soft_reboot;
15use std::{fs::create_dir_all, os::unix::process::CommandExt, path::PathBuf, process::Command};
16
17const NEXTROOT: &str = "/run/nextroot";
18
19#[context("Soft rebooting")]
22pub(crate) async fn prepare_soft_reboot_composefs(
23 storage: &Storage,
24 booted_cfs: &BootedComposefs,
25 deployment_id: &String,
26 reboot: bool,
27) -> Result<()> {
28 if !systemd_has_soft_reboot() {
29 anyhow::bail!("System does not support soft reboots")
30 }
31
32 if *deployment_id == *booted_cfs.cmdline.digest {
33 anyhow::bail!("Cannot soft-reboot to currently booted deployment");
34 }
35
36 let host = composefs_deployment_status_from(storage, booted_cfs.cmdline).await?;
38
39 let all_deployments = host.all_composefs_deployments()?;
40
41 let requred_deployment = all_deployments
42 .iter()
43 .find(|entry| entry.deployment.verity == *deployment_id)
44 .ok_or_else(|| anyhow::anyhow!("Deployment '{deployment_id}' not found"))?;
45
46 if !requred_deployment.soft_reboot_capable {
47 anyhow::bail!("Cannot soft-reboot to deployment with a different kernel state");
48 }
49
50 start_finalize_stated_svc()?;
51
52 let run = Utf8Path::new("/run");
54 bind_mount_from_pidns(PID1, &run, &run, false).context("Bind mounting /run")?;
55
56 create_dir_all(NEXTROOT).context("Creating nextroot")?;
57
58 let cmdline = Cmdline::from(format!("{COMPOSEFS_CMDLINE}={deployment_id}"));
59
60 let args = bootc_initramfs_setup::Args {
61 cmd: vec![],
62 sysroot: PathBuf::from("/sysroot"),
63 config: Default::default(),
64 root_fs: None,
65 cmdline: Some(cmdline),
66 target: Some(NEXTROOT.into()),
67 };
68
69 setup_root(args)?;
70
71 if reboot {
72 let err = Command::new("systemctl").arg("soft-reboot").exec();
74 return Err(anyhow::Error::from(err).context("Failed to exec 'systemctl soft-reboot'"));
75 }
76
77 Ok(())
78}