core,kernel: Set up /etc/passwd for dracut
This fixes a longstanding spew of error messages from the initramfs because we don't have nss-altfiles set up there. Rather than trying to do it, just do the dance of re-synthesizing `/etc/passwd` as it traditionally looks around running dracut, the same as we do for scripts during core layering. Yes, this is all a mess and hopefully I'll get to sysusers soon...
This commit is contained in:
parent
9c4e7590b2
commit
b797a42f3e
@ -3798,6 +3798,49 @@ rpmostree_context_get_kernel_changed (RpmOstreeContext *self)
|
|||||||
return self->kernel_changed;
|
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
|
static gboolean
|
||||||
process_one_ostree_layer (RpmOstreeContext *self,
|
process_one_ostree_layer (RpmOstreeContext *self,
|
||||||
int rootfs_dfd,
|
int rootfs_dfd,
|
||||||
@ -4129,20 +4172,9 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
|||||||
gboolean skip_sanity_check = FALSE;
|
gboolean skip_sanity_check = FALSE;
|
||||||
g_variant_dict_lookup (self->spec->dict, "skip-sanity-check", "b", &skip_sanity_check);
|
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;
|
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
|
/* NB: we're not running scripts right now for removals, so this is only for overlays and
|
||||||
* replacements */
|
* replacements */
|
||||||
@ -4388,14 +4420,8 @@ rpmostree_context_assemble (RpmOstreeContext *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Undo the /etc move above */
|
/* Undo the /etc move above */
|
||||||
if (renamed_etc)
|
if (renamed_etc && !rpmostree_core_redo_usretc (tmprootfs_dfd, error))
|
||||||
{
|
return FALSE;
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* And clean up var/tmp, we don't want it in commits */
|
/* And clean up var/tmp, we don't want it in commits */
|
||||||
if (!glnx_shutil_rm_rf_at (tmprootfs_dfd, "var/tmp", cancellable, error))
|
if (!glnx_shutil_rm_rf_at (tmprootfs_dfd, "var/tmp", cancellable, error))
|
||||||
|
@ -230,3 +230,11 @@ gboolean rpmostree_context_commit (RpmOstreeContext *self,
|
|||||||
char **out_commit,
|
char **out_commit,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
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);
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#include <gio/gunixinputstream.h>
|
#include <gio/gunixinputstream.h>
|
||||||
#include <gio/gunixoutputstream.h>
|
#include <gio/gunixoutputstream.h>
|
||||||
|
|
||||||
|
#include "rpmostree-passwd-util.h"
|
||||||
|
#include "rpmostree-core.h"
|
||||||
#include "rpmostree-kernel.h"
|
#include "rpmostree-kernel.h"
|
||||||
#include "rpmostree-bwrap.h"
|
#include "rpmostree-bwrap.h"
|
||||||
#include "rpmostree-util.h"
|
#include "rpmostree-util.h"
|
||||||
@ -496,6 +498,21 @@ rpmostree_run_dracut (int rootfs_dfd,
|
|||||||
g_auto(GLnxTmpfile) tmpf = { 0, };
|
g_auto(GLnxTmpfile) tmpf = { 0, };
|
||||||
g_autoptr(GBytes) random_cpio_data = NULL;
|
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
|
/* 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
|
* not set; now we simply use the defaults (which in Fedora today also means
|
||||||
* implicitly hostonly). That case is for `rpm-ostree override replace
|
* implicitly hostonly). That case is for `rpm-ostree override replace
|
||||||
@ -607,6 +624,12 @@ rpmostree_run_dracut (int rootfs_dfd,
|
|||||||
if (rebuild_from_initramfs)
|
if (rebuild_from_initramfs)
|
||||||
(void) unlinkat (rootfs_dfd, rebuild_from_initramfs, 0);
|
(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;
|
ret = TRUE;
|
||||||
*out_initramfs_tmpf = tmpf; tmpf.initialized = FALSE; /* Transfer */
|
*out_initramfs_tmpf = tmpf; tmpf.initialized = FALSE; /* Transfer */
|
||||||
out:
|
out:
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
#include <json-glib/json-glib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
@ -129,5 +129,11 @@ initramfs=$(vm_cmd grep ^initrd /boot/loader/entries/ostree-2-$osname.conf | sed
|
|||||||
test -n "${initramfs}"
|
test -n "${initramfs}"
|
||||||
vm_cmd lsinitrd $initramfs > lsinitrd.txt
|
vm_cmd lsinitrd $initramfs > lsinitrd.txt
|
||||||
assert_not_file_has_content lsinitrd.txt /etc/rpmostree-initramfs-testing
|
assert_not_file_has_content lsinitrd.txt /etc/rpmostree-initramfs-testing
|
||||||
|
|
||||||
echo "ok initramfs disable"
|
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"
|
||||||
|
Loading…
Reference in New Issue
Block a user