diff --git a/rust/src/composepost.rs b/rust/src/composepost.rs index dd66870385..9bd558e948 100644 --- a/rust/src/composepost.rs +++ b/rust/src/composepost.rs @@ -16,12 +16,71 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -use openat; use failure::Fallible; +use openat; +use std::io::{BufRead, Write}; +use std::path::Path; +use std::{fs, io}; + +/// Helper functions for openat::Dir +trait OpenatDirExt { + // 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 open_file_optional(&self, p: P) -> io::Result>; +} + +impl OpenatDirExt for openat::Dir { + fn open_file_optional(&self, p: P) -> io::Result> { + match self.open_file(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) = rootfs_dfd.open_file_optional(path)? { + let mut f = io::BufReader::new(f); + let tmp_path = path.parent().unwrap().join("useradd.tmp"); + let o = rootfs_dfd.write_file(&tmp_path, 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.local_rename(&tmp_path, 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