diff --git a/src/libpriv/rpmostree-core.c b/src/libpriv/rpmostree-core.c index 2114f963..efe7a6bc 100644 --- a/src/libpriv/rpmostree-core.c +++ b/src/libpriv/rpmostree-core.c @@ -3798,6 +3798,49 @@ rpmostree_context_get_kernel_changed (RpmOstreeContext *self) return self->kernel_changed; } +/* We have a messy dance in dealing with /usr/etc and /etc; the + * current model is basically to have it be /etc whenever we're running + * any code. + */ +gboolean +rpmostree_core_undo_usretc (int rootfs_dfd, + gboolean *renamed_etc, + GError **error) +{ + if (!glnx_fstatat_allow_noent (rootfs_dfd, "usr/etc", NULL, 0, error)) + return FALSE; + if (errno == 0) + { + /* In general now, we place contents in /etc when running scripts */ + if (!glnx_renameat (rootfs_dfd, "usr/etc", rootfs_dfd, "etc", error)) + return FALSE; + /* But leave a compat symlink, as we used to bind mount, so scripts + * could still use that too. + */ + if (symlinkat ("../etc", rootfs_dfd, "usr/etc") < 0) + return glnx_throw_errno_prefix (error, "symlinkat"); + *renamed_etc = TRUE; + } + else + { + *renamed_etc = FALSE; + } + + return TRUE; +} + +gboolean +rpmostree_core_redo_usretc (int rootfs_dfd, + GError **error) +{ + /* Remove the symlink and swap back */ + if (!glnx_unlinkat (rootfs_dfd, "usr/etc", 0, error)) + return FALSE; + if (!glnx_renameat (rootfs_dfd, "etc", rootfs_dfd, "usr/etc", error)) + return FALSE; + return TRUE; +} + static gboolean process_one_ostree_layer (RpmOstreeContext *self, int rootfs_dfd, @@ -4129,20 +4172,9 @@ rpmostree_context_assemble (RpmOstreeContext *self, gboolean skip_sanity_check = FALSE; g_variant_dict_lookup (self->spec->dict, "skip-sanity-check", "b", &skip_sanity_check); - if (!glnx_fstatat_allow_noent (tmprootfs_dfd, "usr/etc", NULL, 0, error)) + gboolean renamed_etc = FALSE; + if (!rpmostree_core_undo_usretc (tmprootfs_dfd, &renamed_etc, error)) return FALSE; - gboolean renamed_etc = (errno == 0); - if (renamed_etc) - { - /* In general now, we place contents in /etc when running scripts */ - if (!glnx_renameat (tmprootfs_dfd, "usr/etc", tmprootfs_dfd, "etc", error)) - return FALSE; - /* But leave a compat symlink, as we used to bind mount, so scripts - * could still use that too. - */ - if (symlinkat ("../etc", tmprootfs_dfd, "usr/etc") < 0) - return glnx_throw_errno_prefix (error, "symlinkat"); - } /* NB: we're not running scripts right now for removals, so this is only for overlays and * replacements */ @@ -4388,14 +4420,8 @@ rpmostree_context_assemble (RpmOstreeContext *self, } /* Undo the /etc move above */ - if (renamed_etc) - { - /* Remove the symlink and swap back */ - if (!glnx_unlinkat (tmprootfs_dfd, "usr/etc", 0, error)) - return FALSE; - if (!glnx_renameat (tmprootfs_dfd, "etc", tmprootfs_dfd, "usr/etc", error)) - return FALSE; - } + if (renamed_etc && !rpmostree_core_redo_usretc (tmprootfs_dfd, error)) + return FALSE; /* And clean up var/tmp, we don't want it in commits */ if (!glnx_shutil_rm_rf_at (tmprootfs_dfd, "var/tmp", cancellable, error)) diff --git a/src/libpriv/rpmostree-core.h b/src/libpriv/rpmostree-core.h index 6a00944c..80ba69ce 100644 --- a/src/libpriv/rpmostree-core.h +++ b/src/libpriv/rpmostree-core.h @@ -230,3 +230,11 @@ gboolean rpmostree_context_commit (RpmOstreeContext *self, char **out_commit, GCancellable *cancellable, GError **error); +gboolean +rpmostree_core_undo_usretc (int rootfs_dfd, + gboolean *renamed_etc, + GError **error); + +gboolean +rpmostree_core_redo_usretc (int rootfs_dfd, + GError **error); diff --git a/src/libpriv/rpmostree-kernel.c b/src/libpriv/rpmostree-kernel.c index 47092aa8..d79c3106 100644 --- a/src/libpriv/rpmostree-kernel.c +++ b/src/libpriv/rpmostree-kernel.c @@ -34,6 +34,8 @@ #include #include +#include "rpmostree-passwd-util.h" +#include "rpmostree-core.h" #include "rpmostree-kernel.h" #include "rpmostree-bwrap.h" #include "rpmostree-util.h" @@ -496,6 +498,21 @@ rpmostree_run_dracut (int rootfs_dfd, g_auto(GLnxTmpfile) tmpf = { 0, }; g_autoptr(GBytes) random_cpio_data = NULL; + /* We need to have /etc/passwd since dracut doesn't have altfiles + * today. Though maybe in the future we should add it, but + * in the end we want to use systemd-sysusers of course. + **/ + gboolean renamed_etc = FALSE; + if (!rpmostree_core_undo_usretc (rootfs_dfd, &renamed_etc, error)) + return FALSE; + gboolean have_passwd = FALSE; + if (!rpmostree_passwd_prepare_rpm_layering (rootfs_dfd, + NULL, + &have_passwd, + cancellable, + error)) + return FALSE; + /* Previously we used to error out if argv or rebuild_from_initramfs were both * not set; now we simply use the defaults (which in Fedora today also means * implicitly hostonly). That case is for `rpm-ostree override replace @@ -607,6 +624,12 @@ rpmostree_run_dracut (int rootfs_dfd, if (rebuild_from_initramfs) (void) unlinkat (rootfs_dfd, rebuild_from_initramfs, 0); + if (have_passwd && !rpmostree_passwd_complete_rpm_layering (rootfs_dfd, error)) + goto out; + + if (renamed_etc && !rpmostree_core_redo_usretc (rootfs_dfd, error)) + goto out; + ret = TRUE; *out_initramfs_tmpf = tmpf; tmpf.initialized = FALSE; /* Transfer */ out: diff --git a/src/libpriv/rpmostree-passwd-util.h b/src/libpriv/rpmostree-passwd-util.h index 1d6ac459..6c7a30a5 100644 --- a/src/libpriv/rpmostree-passwd-util.h +++ b/src/libpriv/rpmostree-passwd-util.h @@ -21,6 +21,7 @@ #pragma once #include +#include #include #include diff --git a/tests/vmcheck/test-initramfs.sh b/tests/vmcheck/test-initramfs.sh index 73c9bff0..8601ffb8 100755 --- a/tests/vmcheck/test-initramfs.sh +++ b/tests/vmcheck/test-initramfs.sh @@ -129,5 +129,11 @@ initramfs=$(vm_cmd grep ^initrd /boot/loader/entries/ostree-2-$osname.conf | sed test -n "${initramfs}" vm_cmd lsinitrd $initramfs > lsinitrd.txt assert_not_file_has_content lsinitrd.txt /etc/rpmostree-initramfs-testing - echo "ok initramfs disable" +# while we're here, sanity check we also ship /etc/passwd in the initrd to +# soothe systemd-udevd +for x in passwd group; do + assert_file_has_content lsinitrd.txt " etc/$x" +done +rm -f lsinitrd.txt +echo "ok initramfs has passwd"