Skip to content

Commit c503391

Browse files
Johan-Liebert1cgwalters
authored andcommitted
cli: Add option to current vs default /etc
Signed-off-by: Pragyan Poudyal <[email protected]>
1 parent 0d199e6 commit c503391

File tree

3 files changed

+70
-36
lines changed

3 files changed

+70
-36
lines changed

crates/etc-merge/src/lib.rs

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -305,16 +305,16 @@ fn get_modifications(
305305
/// [`anyhow::Result`] containing a tuple of directory trees in the order:
306306
///
307307
/// 1. `pristine_etc_files` – Dirtree of the pristine etc state
308-
/// 2. `current_etc_files` – Dirtree of the current etc state
309-
/// 3. `new_etc_files` – Dirtree of the new etc state
308+
/// 2. `current_etc_files` – Dirtree of the current etc state
309+
/// 3. `new_etc_files` – Dirtree of the new etc state (if new_etc directory is passed)
310310
pub fn traverse_etc(
311311
pristine_etc: &CapStdDir,
312312
current_etc: &CapStdDir,
313-
new_etc: &CapStdDir,
313+
new_etc: Option<&CapStdDir>,
314314
) -> anyhow::Result<(
315315
Directory<CustomMetadata>,
316316
Directory<CustomMetadata>,
317-
Directory<CustomMetadata>,
317+
Option<Directory<CustomMetadata>>,
318318
)> {
319319
let mut pristine_etc_files = Directory::default();
320320
recurse_dir(pristine_etc, &mut pristine_etc_files)
@@ -324,8 +324,16 @@ pub fn traverse_etc(
324324
recurse_dir(current_etc, &mut current_etc_files)
325325
.context(format!("Recursing {current_etc:?}"))?;
326326

327-
let mut new_etc_files = Directory::default();
328-
recurse_dir(new_etc, &mut new_etc_files).context(format!("Recursing {new_etc:?}"))?;
327+
let new_etc_files = match new_etc {
328+
Some(new_etc) => {
329+
let mut new_etc_files = Directory::default();
330+
recurse_dir(new_etc, &mut new_etc_files).context(format!("Recursing {new_etc:?}"))?;
331+
332+
Some(new_etc_files)
333+
}
334+
335+
None => None,
336+
};
329337

330338
return Ok((pristine_etc_files, current_etc_files, new_etc_files));
331339
}
@@ -664,7 +672,7 @@ fn merge_modified_files(
664672

665673
let current_inode = dir
666674
.lookup(filename)
667-
.ok_or(anyhow::anyhow!("{filename:?} not found"))?;
675+
.ok_or_else(|| anyhow::anyhow!("{filename:?} not found"))?;
668676

669677
// This will error out if some directory in a chain does not exist
670678
let res = new_etc_dirtree.split(OsStr::new(&file));
@@ -734,30 +742,18 @@ pub fn merge(
734742
for removed in diff.removed {
735743
let stat = new_etc_fd.metadata_optional(&removed)?;
736744

737-
let stat = match stat {
738-
Some(s) => s,
739-
740-
None => {
741-
// File/dir doesn't exist in new_etc
742-
// Basically a no-op
743-
continue;
744-
}
745+
let Some(stat) = stat else {
746+
// File/dir doesn't exist in new_etc
747+
// Basically a no-op
748+
continue;
745749
};
746750

747751
if stat.is_file() || stat.is_symlink() {
748-
match new_etc_fd.remove_file(&removed) {
749-
Ok(..) => { /* no-op */ }
750-
Err(e) => Err(e)?,
751-
}
752-
}
753-
754-
if stat.is_dir() {
752+
new_etc_fd.remove_file(&removed)?;
753+
} else if stat.is_dir() {
755754
// We only add the directory to the removed array, if the entire directory was deleted
756755
// So `remove_dir_all` should be okay here
757-
match new_etc_fd.remove_dir_all(&removed) {
758-
Ok(..) => { /* no-op */ }
759-
Err(e) => Err(e)?,
760-
}
756+
new_etc_fd.remove_dir_all(&removed)?;
761757
}
762758
}
763759

@@ -826,7 +822,7 @@ mod tests {
826822
c.remove_file(deleted_files[0])?;
827823
c.remove_file(deleted_files[1])?;
828824

829-
let (pristine_etc_files, current_etc_files, _) = traverse_etc(&p, &c, &n)?;
825+
let (pristine_etc_files, current_etc_files, _) = traverse_etc(&p, &c, Some(&n))?;
830826
let res = compute_diff(&pristine_etc_files, &current_etc_files)?;
831827

832828
// Test added files
@@ -1010,9 +1006,10 @@ mod tests {
10101006
n.create_dir_all("dir/perms")?;
10111007
n.write("dir/perms/some-file", "Some-file")?;
10121008

1013-
let (pristine_etc_files, current_etc_files, new_etc_files) = traverse_etc(&p, &c, &n)?;
1009+
let (pristine_etc_files, current_etc_files, new_etc_files) =
1010+
traverse_etc(&p, &c, Some(&n))?;
10141011
let diff = compute_diff(&pristine_etc_files, &current_etc_files)?;
1015-
merge(&c, &current_etc_files, &n, &new_etc_files, diff)?;
1012+
merge(&c, &current_etc_files, &n, &new_etc_files.unwrap(), diff)?;
10161013

10171014
assert!(files_eq(&c, &n, "new_file.txt")?);
10181015
assert!(files_eq(&c, &n, "a/new_file.txt")?);
@@ -1082,10 +1079,11 @@ mod tests {
10821079

10831080
n.create_dir_all("file-to-dir")?;
10841081

1085-
let (pristine_etc_files, current_etc_files, new_etc_files) = traverse_etc(&p, &c, &n)?;
1082+
let (pristine_etc_files, current_etc_files, new_etc_files) =
1083+
traverse_etc(&p, &c, Some(&n))?;
10861084
let diff = compute_diff(&pristine_etc_files, &current_etc_files)?;
10871085

1088-
let merge_res = merge(&c, &current_etc_files, &n, &new_etc_files, diff);
1086+
let merge_res = merge(&c, &current_etc_files, &n, &new_etc_files.unwrap(), diff);
10891087

10901088
assert!(merge_res.is_err());
10911089
assert_eq!(

crates/lib/src/bootc_composefs/finalize.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,34 @@ use bootc_initramfs_setup::{mount_composefs_image, open_dir};
1111
use bootc_mount::tempmount::TempMount;
1212
use cap_std_ext::cap_std::{ambient_authority, fs::Dir};
1313
use cap_std_ext::dirext::CapStdExtDirExt;
14-
use etc_merge::{compute_diff, merge, traverse_etc};
14+
use etc_merge::{compute_diff, merge, print_diff, traverse_etc};
1515
use rustix::fs::{fsync, renameat, CWD};
1616
use rustix::path::Arg;
1717

1818
use fn_error_context::context;
1919

20+
pub(crate) async fn get_etc_diff() -> Result<()> {
21+
let host = composefs_deployment_status().await?;
22+
let booted_composefs = host.require_composefs_booted()?;
23+
24+
// Mount the booted EROFS image to get pristine etc
25+
let sysroot = open_dir(CWD, "/sysroot").context("Opening /sysroot")?;
26+
let composefs_fd = mount_composefs_image(&sysroot, &booted_composefs.verity, false)?;
27+
28+
let erofs_tmp_mnt = TempMount::mount_fd(&composefs_fd)?;
29+
30+
let pristine_etc =
31+
Dir::open_ambient_dir(erofs_tmp_mnt.dir.path().join("etc"), ambient_authority())?;
32+
let current_etc = Dir::open_ambient_dir("/etc", ambient_authority())?;
33+
34+
let (pristine_files, current_files, _) = traverse_etc(&pristine_etc, &current_etc, None)?;
35+
let diff = compute_diff(&pristine_files, &current_files)?;
36+
37+
print_diff(&diff, &mut std::io::stdout());
38+
39+
Ok(())
40+
}
41+
2042
pub(crate) async fn composefs_native_finalize() -> Result<()> {
2143
let host = composefs_deployment_status().await?;
2244

@@ -49,7 +71,9 @@ pub(crate) async fn composefs_native_finalize() -> Result<()> {
4971
let new_etc = Dir::open_ambient_dir(new_etc_path, ambient_authority())?;
5072

5173
let (pristine_files, current_files, new_files) =
52-
traverse_etc(&pristine_etc, &current_etc, &new_etc)?;
74+
traverse_etc(&pristine_etc, &current_etc, Some(&new_etc))?;
75+
76+
let new_files = new_files.ok_or(anyhow::anyhow!("Failed to get dirtree for new etc"))?;
5377

5478
let diff = compute_diff(&pristine_files, &current_files)?;
5579
merge(&current_etc, &current_files, &new_etc, &new_files, diff)?;

crates/lib/src/cli.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ use serde::{Deserialize, Serialize};
3131

3232
#[cfg(feature = "composefs-backend")]
3333
use crate::bootc_composefs::{
34-
finalize::composefs_native_finalize, rollback::composefs_rollback, status::composefs_booted,
35-
switch::switch_composefs, update::upgrade_composefs,
34+
finalize::{composefs_native_finalize, get_etc_diff},
35+
rollback::composefs_rollback,
36+
status::composefs_booted,
37+
switch::switch_composefs,
38+
update::upgrade_composefs,
3639
};
3740
use crate::deploy::RequiredHostSpec;
3841
use crate::lints;
@@ -653,6 +656,9 @@ pub(crate) enum Opt {
653656
Internals(InternalsOpts),
654657
#[cfg(feature = "composefs-backend")]
655658
ComposefsFinalizeStaged,
659+
#[cfg(feature = "composefs-backend")]
660+
/// Diff current /etc configuration versus default
661+
ConfigDiff,
656662
}
657663

658664
/// Ensure we've entered a mount namespace, so that we can remount
@@ -1502,12 +1508,15 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
15021508
let current_etc = Dir::open_ambient_dir(current_etc, cap_std::ambient_authority())?;
15031509
let new_etc = Dir::open_ambient_dir(new_etc, cap_std::ambient_authority())?;
15041510

1505-
let (p, c, n) = etc_merge::traverse_etc(&pristine_etc, &current_etc, &new_etc)?;
1511+
let (p, c, n) =
1512+
etc_merge::traverse_etc(&pristine_etc, &current_etc, Some(&new_etc))?;
15061513

15071514
let diff = compute_diff(&p, &c)?;
15081515
print_diff(&diff, &mut std::io::stdout());
15091516

15101517
if merge {
1518+
let n =
1519+
n.ok_or_else(|| anyhow::anyhow!("Failed to get dirtree for new etc"))?;
15111520
etc_merge::merge(&current_etc, &c, &new_etc, &n, diff)?;
15121521
}
15131522

@@ -1525,6 +1534,9 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
15251534

15261535
#[cfg(feature = "composefs-backend")]
15271536
Opt::ComposefsFinalizeStaged => composefs_native_finalize().await,
1537+
1538+
#[cfg(feature = "composefs-backend")]
1539+
Opt::ConfigDiff => get_etc_diff().await,
15281540
}
15291541
}
15301542

0 commit comments

Comments
 (0)