Skip to content

Commit af8fa4e

Browse files
cli/composefs: Implement status cmd for compoesfs booted system
This is currently WIP, as it only shows the currently booted image in use and not any staged or rollback deployments. Signed-off-by: Pragyan Poudyal <[email protected]>
1 parent edcf721 commit af8fa4e

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed

lib/src/spec.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ pub struct BootEntryOstree {
162162
pub deploy_serial: u32,
163163
}
164164

165+
166+
/// A bootable entry
167+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
168+
#[serde(rename_all = "camelCase")]
169+
pub struct BootEntryComposefs {
170+
/// The erofs verity
171+
pub verity: String,
172+
}
173+
165174
/// A bootable entry
166175
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
167176
#[serde(rename_all = "camelCase")]
@@ -179,6 +188,8 @@ pub struct BootEntry {
179188
pub store: Option<Store>,
180189
/// If this boot entry is ostree based, the corresponding state
181190
pub ostree: Option<BootEntryOstree>,
191+
/// If this boot entry is composefs based, the corresponding state
192+
pub composefs: Option<BootEntryComposefs>,
182193
}
183194

184195
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
@@ -514,6 +525,7 @@ mod tests {
514525
pinned: false,
515526
store: None,
516527
ostree: None,
528+
composefs: None,
517529
}
518530
}
519531

lib/src/status.rs

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use fn_error_context::context;
99
use ostree::glib;
1010
use ostree_container::OstreeImageReference;
1111
use ostree_ext::container as ostree_container;
12+
use ostree_ext::container_utils::composefs_booted;
1213
use ostree_ext::container_utils::ostree_booted;
1314
use ostree_ext::keyfileext::KeyFileExt;
1415
use ostree_ext::oci_spec;
@@ -164,6 +165,7 @@ fn boot_entry_from_deployment(
164165
// SAFETY: The deployserial is really unsigned
165166
deploy_serial: deployment.deployserial().try_into().unwrap(),
166167
}),
168+
composefs: None,
167169
};
168170
Ok(r)
169171
}
@@ -293,13 +295,53 @@ pub(crate) async fn status(opts: super::cli::StatusOpts) -> Result<()> {
293295
0 | 1 => {}
294296
o => anyhow::bail!("Unsupported format version: {o}"),
295297
};
296-
let mut host = if !ostree_booted()? {
297-
Default::default()
298-
} else {
298+
let mut host = if ostree_booted()? {
299299
let sysroot = super::cli::get_storage().await?;
300300
let booted_deployment = sysroot.booted_deployment();
301301
let (_deployments, host) = get_status(&sysroot, booted_deployment.as_ref())?;
302302
host
303+
} else if composefs_booted()? {
304+
let dir_contents = std::fs::read_dir("/sysroot/composefs/images")?;
305+
306+
let host_spec = HostSpec {
307+
image: Some(ImageReference {
308+
image: "".into(),
309+
transport: "".into(),
310+
signature: None,
311+
}),
312+
boot_order: BootOrder::Default,
313+
};
314+
315+
let mut host = Host::new(host_spec);
316+
317+
let cmdline = crate::kernel::parse_cmdline()?;
318+
let booted = cmdline.iter().find_map(|x| x.strip_prefix("composefs="));
319+
320+
let Some(booted) = booted else {
321+
anyhow::bail!("Failed to find composefs parameter in kernel cmdline");
322+
};
323+
324+
host.status = HostStatus {
325+
staged: None,
326+
booted: Some(BootEntry {
327+
image: None,
328+
cached_update: None,
329+
incompatible: false,
330+
pinned: false,
331+
store: None,
332+
ostree: None,
333+
composefs: Some(crate::spec::BootEntryComposefs {
334+
verity: booted.into(),
335+
}),
336+
}),
337+
rollback: None,
338+
rollback_queued: false,
339+
ty: None,
340+
};
341+
342+
host
343+
} else {
344+
Default::default()
303345
};
304346

305347
// We could support querying the staged or rollback deployments
@@ -434,6 +476,27 @@ fn human_render_slot_ostree(
434476
Ok(())
435477
}
436478

479+
/// Output a rendering of a non-container composefs boot entry.
480+
fn human_render_slot_composefs(
481+
mut out: impl Write,
482+
slot: Slot,
483+
entry: &crate::spec::BootEntry,
484+
erofs_verity: &str,
485+
) -> Result<()> {
486+
// TODO consider rendering more ostree stuff here like rpm-ostree status does
487+
let prefix = match slot {
488+
Slot::Staged => " Staged composefs".into(),
489+
Slot::Booted => format!("{} Booted composefs", crate::glyph::Glyph::BlackCircle),
490+
Slot::Rollback => " Rollback composefs".into(),
491+
};
492+
let prefix_len = prefix.len();
493+
writeln!(out, "{prefix}")?;
494+
write_row_name(&mut out, "Commit", prefix_len)?;
495+
writeln!(out, "{erofs_verity}")?;
496+
tracing::debug!("pinned={}", entry.pinned);
497+
Ok(())
498+
}
499+
437500
fn human_readable_output_booted(mut out: impl Write, host: &Host) -> Result<()> {
438501
let mut first = true;
439502
for (slot_name, status) in [
@@ -451,6 +514,8 @@ fn human_readable_output_booted(mut out: impl Write, host: &Host) -> Result<()>
451514
human_render_slot(&mut out, slot_name, host_status, image)?;
452515
} else if let Some(ostree) = host_status.ostree.as_ref() {
453516
human_render_slot_ostree(&mut out, slot_name, host_status, &ostree.checksum)?;
517+
} else if let Some(composefs) = &host_status.composefs {
518+
human_render_slot_composefs(&mut out, slot_name, host_status, &composefs.verity)?;
454519
} else {
455520
writeln!(out, "Current {slot_name} state is unknown")?;
456521
}

ostree-ext/src/container_utils.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ pub fn ostree_booted() -> io::Result<bool> {
7777
Path::new(&format!("/{OSTREE_BOOTED}")).try_exists()
7878
}
7979

80+
81+
/// Returns true if the system appears to have been booted with composefs.
82+
pub fn composefs_booted() -> io::Result<bool> {
83+
let cmdline = std::fs::read_to_string("/proc/cmdline")?;
84+
Ok(cmdline.contains("composefs="))
85+
}
86+
8087
/// Returns true if the target root appears to have been booted via ostree.
8188
pub fn is_ostree_booted_in(rootfs: &Dir) -> io::Result<bool> {
8289
rootfs.try_exists(OSTREE_BOOTED)

0 commit comments

Comments
 (0)