1
0
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:
Kelvin Fan
2020-12-01 14:38:32 -05:00
committed by OpenShift Merge Robot
parent 0be1b276a9
commit b43cbae40b
3 changed files with 34 additions and 0 deletions

View File

@@ -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 {

View File

@@ -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))
}

View File

@@ -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(())
}