-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a systemd generator to fixup Anaconda's /etc/fstab
This is a giant and hacky workaround for ostreedev/ostree#3193 The better real fix is probably in either systemd or anaconda (more realistically both) but let's paper over things here for now. Having code to run as a generator will likely be useful in the future anyways. Signed-off-by: Colin Walters <walters@verbum.org>
- Loading branch information
Showing
6 changed files
with
312 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
use std::io::BufRead; | ||
|
||
use anyhow::{Context, Result}; | ||
use cap_std::fs::Dir; | ||
use cap_std_ext::{cap_std, dirext::CapStdExtDirExt}; | ||
use fn_error_context::context; | ||
use rustix::{fd::AsFd, fs::StatVfsMountFlags}; | ||
|
||
const FSTAB_ANACONDA_STAMP: &str = "Created by anaconda"; | ||
|
||
/// Called when the root is read-only composefs to reconcile /etc/fstab | ||
#[context("bootc generator")] | ||
pub(crate) fn fstab_generator_impl(root: &Dir, unit_dir: &Dir) -> Result<()> { | ||
// Do nothing if not ostree-booted | ||
if !root.try_exists("run/ostree-booted")? { | ||
return Ok(()); | ||
} | ||
|
||
if let Some(fd) = root | ||
.open_optional("etc/fstab") | ||
.context("Opening /etc/fstab")? | ||
.map(std::io::BufReader::new) | ||
{ | ||
let mut from_anaconda = false; | ||
// Only read 10 lines just because it should be near the start | ||
for line in fd.lines().take(10) { | ||
let line = line.context("Reading /etc/fstab")?; | ||
if line.contains(FSTAB_ANACONDA_STAMP) { | ||
from_anaconda = true; | ||
break; | ||
} | ||
} | ||
tracing::debug!("/etc/fstab from anaconda: {from_anaconda}"); | ||
if from_anaconda { | ||
generate_fstab_editor(unit_dir)?; | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
/// Main entrypoint for the generator | ||
pub(crate) fn generator(root: &Dir, unit_dir: &Dir) -> Result<()> { | ||
// Right now we only do something if the root is a read-only overlayfs (a composefs really) | ||
let st = rustix::fs::fstatfs(root.as_fd())?; | ||
if st.f_type != libc::OVERLAYFS_SUPER_MAGIC { | ||
tracing::trace!("Root is not overlayfs"); | ||
return Ok(()); | ||
} | ||
let st = rustix::fs::fstatvfs(root.as_fd())?; | ||
if !st.f_flag.contains(StatVfsMountFlags::RDONLY) { | ||
tracing::trace!("Root is writable"); | ||
return Ok(()); | ||
} | ||
fstab_generator_impl(root, unit_dir) | ||
} | ||
|
||
/// Parse /etc/fstab and check if the root mount is out of sync with the composefs | ||
/// state, and if so, fix it. | ||
fn generate_fstab_editor(unit_dir: &Dir) -> Result<()> { | ||
let unit = "bootc-fstab-edit.service"; | ||
unit_dir.atomic_write( | ||
unit, | ||
"[Unit]\n\ | ||
Before=local-fs-pre.target\n\ | ||
[Service]\n\ | ||
ExecStart=bootc internals fixup-etc-fstab | ||
", | ||
)?; | ||
let target = "local-fs-pre.target.wants"; | ||
unit_dir.create_dir_all(target)?; | ||
unit_dir.symlink(&format!("../{unit}"), &format!("{target}/{unit}"))?; | ||
Ok(()) | ||
} | ||
|
||
#[cfg(test)] | ||
fn fixture() -> Result<cap_std_ext::cap_tempfile::TempDir> { | ||
let tempdir = cap_std_ext::cap_tempfile::tempdir(cap_std::ambient_authority())?; | ||
tempdir.create_dir("etc")?; | ||
tempdir.create_dir("run")?; | ||
tempdir.create_dir_all("run/systemd/system")?; | ||
Ok(tempdir) | ||
} | ||
|
||
#[test] | ||
fn test_generator_no_fstab() -> Result<()> { | ||
let tempdir = fixture()?; | ||
let unit_dir = &tempdir.open_dir("run/systemd/system")?; | ||
fstab_generator_impl(&tempdir, &unit_dir).unwrap(); | ||
|
||
assert_eq!(unit_dir.entries()?.count(), 0); | ||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_generator_fstab() -> Result<()> { | ||
let tempdir = fixture()?; | ||
let unit_dir = &tempdir.open_dir("run/systemd/system")?; | ||
// Should still be a no-op | ||
tempdir.atomic_write("etc/fstab", "# Some dummy fstab")?; | ||
fstab_generator_impl(&tempdir, &unit_dir).unwrap(); | ||
assert_eq!(unit_dir.entries()?.count(), 0); | ||
|
||
// Also a no-op, not booted via ostree | ||
tempdir.atomic_write("etc/fstab", &format!("# {FSTAB_ANACONDA_STAMP}"))?; | ||
fstab_generator_impl(&tempdir, &unit_dir).unwrap(); | ||
assert_eq!(unit_dir.entries()?.count(), 0); | ||
|
||
// Now it should generate | ||
tempdir.atomic_write("run/ostree-booted", "ostree booted")?; | ||
fstab_generator_impl(&tempdir, &unit_dir).unwrap(); | ||
assert_eq!(unit_dir.entries()?.count(), 1); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub(crate) mod generator; |