diff --git a/rust/src/composepost.rs b/rust/src/composepost.rs index dd66870385..ded47e3957 100644 --- a/rust/src/composepost.rs +++ b/rust/src/composepost.rs @@ -17,11 +17,66 @@ */ use openat; +use std::{io, fs}; +use std::io::{Write, BufRead}; +use std::path::Path; use failure::Fallible; +// IMO should propose this at least in a "utils" bit of the openat crate; +// Like 95% of the time I'm looking at errno (with files) it's for ENOENT, +// and Rust has an elegant way to map that with Option<>. Every other +// error I usually just want to propagate back up. +fn openat_optional(d: &openat::Dir, p: P, f: F) -> io::Result> + where P: openat::AsPath, F: FnOnce(&openat::Dir, P) -> io::Result +{ + match f(d, p) { + Ok(f) => Ok(Some(f)), + Err(e) => { + if e.kind() == io::ErrorKind::NotFound { + Ok(None) + } else { + Err(e) + } + } + } +} + +// rpm-ostree uses /home → /var/home by default as generated by our +// rootfs; we don't expect people to change this. Let's be nice +// and also fixup the $HOME entries generated by `useradd` so +// that `~` shows up as expected in shells, etc. +// +// https://github.com/coreos/fedora-coreos-config/pull/18 +// https://pagure.io/workstation-ostree-config/pull-request/121 +// https://discussion.fedoraproject.org/t/adapting-user-home-in-etc-passwd/487/6 +// https://github.com/justjanne/powerline-go/issues/94 +fn postprocess_useradd(rootfs_dfd: &openat::Dir) -> Fallible<()> +{ + let path = Path::new("usr/etc/default/useradd"); + if let Some(f) = openat_optional(rootfs_dfd, path, openat::Dir::open_file)? { + let mut f = io::BufReader::new(f); + let o = rootfs_dfd.new_unnamed_file(0644)?; + let mut bufw = io::BufWriter::new(&o); + for line in f.lines() { + let line = line?; + if !line.starts_with("HOME=") { + bufw.write(line.as_bytes())?; + } else { + bufw.write("HOME=/var/home".as_bytes())?; + } + bufw.write("\n".as_bytes())?; + } + bufw.flush()?; + rootfs_dfd.remove_file(path)?; + rootfs_dfd.link_file_at(&o, path)?; + } + Ok(()) +} + // This function is called from rpmostree_postprocess_final(); think of // it as the bits of that function that we've chosen to implement in Rust. -fn compose_postprocess_final(_rootfs_dfd: &openat::Dir) -> Fallible<()> { +fn compose_postprocess_final(rootfs_dfd: &openat::Dir) -> Fallible<()> { + postprocess_useradd(rootfs_dfd)?; Ok(()) } diff --git a/tests/compose-tests/libbasic-test.sh b/tests/compose-tests/libbasic-test.sh index 3866b0b68d..11e8dae863 100644 --- a/tests/compose-tests/libbasic-test.sh +++ b/tests/compose-tests/libbasic-test.sh @@ -19,6 +19,11 @@ validate_passwd() { validate_passwd passwd validate_passwd group + +ostree --repo=${repobuild} cat ${treeref} /usr/etc/default/useradd > useradd.txt +assert_file_has_content_literal useradd.txt HOME=/var/home +echo "ok etc/default/useradd" + for path in /usr/share/rpm /usr/lib/sysimage/rpm-ostree-base-db; do ostree --repo=${repobuild} ls -R ${treeref} ${path} > db.txt assert_file_has_content_literal db.txt /Packages