mirror of
https://github.com/containers/bootc.git
synced 2026-02-05 15:45:53 +01:00
Ensure mount points writable before updating
The /boot and /boot/efi mount points may be read-only, so remount them as read-write if necessary when writing.
This commit is contained in:
committed by
OpenShift Merge Robot
parent
0be1b276a9
commit
b43cbae40b
@@ -2,6 +2,7 @@ use crate::component::{Component, ValidationResult};
|
||||
use crate::coreos;
|
||||
use crate::efi;
|
||||
use crate::model::{ComponentStatus, ComponentUpdatable, ContentMetadata, SavedState, Status};
|
||||
use crate::util;
|
||||
use crate::{component, ipc};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -93,6 +94,10 @@ pub(crate) enum ComponentUpdateResult {
|
||||
},
|
||||
}
|
||||
|
||||
fn ensure_writable_boot() -> Result<()> {
|
||||
util::ensure_writable_mount("/boot")
|
||||
}
|
||||
|
||||
/// daemon implementation of component update
|
||||
pub(crate) fn update(name: &str) -> Result<ComponentUpdateResult> {
|
||||
let mut state = SavedState::load_from_disk("/")?.unwrap_or_default();
|
||||
@@ -109,6 +114,8 @@ pub(crate) fn update(name: &str) -> Result<ComponentUpdateResult> {
|
||||
_ => return Ok(ComponentUpdateResult::AtLatestVersion),
|
||||
};
|
||||
|
||||
ensure_writable_boot()?;
|
||||
|
||||
let mut pending_container = state.pending.take().unwrap_or_default();
|
||||
let interrupted = pending_container.get(component.name()).cloned();
|
||||
pending_container.insert(component.name().into(), update.clone());
|
||||
@@ -140,6 +147,9 @@ pub(crate) fn adopt_and_update(name: &str) -> Result<ContentMetadata> {
|
||||
if state.installed.get(name).is_some() {
|
||||
anyhow::bail!("Component {} is already installed", name);
|
||||
};
|
||||
|
||||
ensure_writable_boot()?;
|
||||
|
||||
let update = if let Some(update) = component.query_update(&sysroot)? {
|
||||
update
|
||||
} else {
|
||||
|
||||
@@ -94,6 +94,7 @@ impl Component for EFI {
|
||||
let updatef = filetree::FileTree::new_from_dir(&updated).context("reading update dir")?;
|
||||
// For adoption, we should only touch files that we know about.
|
||||
let diff = updatef.relative_diff_to(&esp)?;
|
||||
ensure_writable_efi()?;
|
||||
log::trace!("applying adoption diff: {}", &diff);
|
||||
filetree::apply_diff(&updated, &esp, &diff, None).context("applying filesystem changes")?;
|
||||
Ok(InstalledContent {
|
||||
@@ -153,6 +154,7 @@ impl Component for EFI {
|
||||
let destdir = openat::Dir::open(&Path::new("/").join(MOUNT_PATH).join("EFI"))
|
||||
.context("opening EFI dir")?;
|
||||
validate_esp(&destdir)?;
|
||||
ensure_writable_efi()?;
|
||||
log::trace!("applying diff: {}", &diff);
|
||||
filetree::apply_diff(&updated, &destdir, &diff, None)
|
||||
.context("applying filesystem changes")?;
|
||||
@@ -280,3 +282,7 @@ fn validate_esp(dir: &openat::Dir) -> Result<()> {
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_writable_efi() -> Result<()> {
|
||||
util::ensure_writable_mount(&Path::new("/").join(MOUNT_PATH))
|
||||
}
|
||||
|
||||
18
src/util.rs
18
src/util.rs
@@ -3,6 +3,7 @@ use std::collections::HashSet;
|
||||
use anyhow::{bail, Result};
|
||||
use openat_ext::OpenatDirExt;
|
||||
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
pub(crate) trait CommandRunExt {
|
||||
@@ -65,3 +66,20 @@ pub(crate) fn filenames(dir: &openat::Dir) -> Result<HashSet<String>> {
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_writable_mount<P: AsRef<Path>>(p: P) -> Result<()> {
|
||||
use nix::sys::statvfs;
|
||||
let p = p.as_ref();
|
||||
let stat = statvfs::statvfs(p)?;
|
||||
if !stat.flags().contains(statvfs::FsFlags::ST_RDONLY) {
|
||||
return Ok(());
|
||||
}
|
||||
let status = std::process::Command::new("mount")
|
||||
.args(&["-o", "remount,rw"])
|
||||
.arg(p)
|
||||
.status()?;
|
||||
if !status.success() {
|
||||
anyhow::bail!("Failed to remount {:?} writable", p);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user