summaryrefslogtreecommitdiffstats
path: root/mkosi.images/system
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2024-03-27 11:07:52 +0100
committerDaan De Meyer <daan.j.demeyer@gmail.com>2024-03-27 12:20:50 +0100
commit6327988d65a19ab2d8b9a5fb29116c8ff4c4a606 (patch)
treea6d64e71e95df88f5c2e6463a991a2470864c2db /mkosi.images/system
parentmkosi: Re-enable OpenSUSE build (diff)
downloadsystemd-6327988d65a19ab2d8b9a5fb29116c8ff4c4a606.tar.xz
systemd-6327988d65a19ab2d8b9a5fb29116c8ff4c4a606.zip
mkosi: Merge base and system images
The only reason to have these split up is to be able to build extension images that use the base image as a base tree and install extra packages. Until we have such a use case, let's merge the base and system images to simplify things a bit. We keep the mkosi.images/ directory to not cause too many conflicts with the integration tests PR.
Diffstat (limited to 'mkosi.images/system')
-rw-r--r--mkosi.images/system/mkosi.conf50
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-arch/initrd/mkosi.postinst5
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-arch/mkosi.build.chroot55
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-arch/mkosi.conf47
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-arch/mkosi.prepare24
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-centos-fedora/initrd/mkosi.postinst5
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.build.chroot47
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.conf57
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.prepare66
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-centos/mkosi.conf8
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-debian-ubuntu/initrd/mkosi.postinst5
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.build.chroot89
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.conf61
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.prepare15
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf4
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf.d/amd64.conf8
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf.d/arm64.conf8
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-fedora/mkosi.conf18
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-opensuse/initrd/mkosi.postinst9
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.build.chroot63
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.conf55
-rwxr-xr-xmkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.prepare61
-rw-r--r--mkosi.images/system/mkosi.conf.d/10-ubuntu/mkosi.conf11
-rw-r--r--mkosi.images/system/mkosi.extra/etc/issue2
-rw-r--r--mkosi.images/system/mkosi.extra/usr/lib/systemd/journald.conf.d/50-persistent.conf8
-rwxr-xr-xmkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh20
-rw-r--r--mkosi.images/system/mkosi.extra/usr/lib/systemd/system-preset/00-mkosi.preset30
-rw-r--r--mkosi.images/system/mkosi.extra/usr/lib/systemd/system-preset/99-mkosi.preset4
-rw-r--r--mkosi.images/system/mkosi.extra/usr/lib/systemd/system/mkosi-check-and-shutdown.service15
-rw-r--r--mkosi.images/system/mkosi.extra/usr/lib/tmpfiles.d/99-mkosi.conf3
-rw-r--r--mkosi.images/system/mkosi.extra/usr/lib/tmpfiles.d/locale.conf1
-rw-r--r--mkosi.images/system/mkosi.extra/usr/share/factory/mkosi/gdbinit.d/systemd.gdb3
-rwxr-xr-xmkosi.images/system/mkosi.finalize4
-rwxr-xr-xmkosi.images/system/mkosi.postinst6
-rwxr-xr-xmkosi.images/system/mkosi.postinst.chroot75
-rwxr-xr-xmkosi.images/system/mkosi.sync8
36 files changed, 942 insertions, 8 deletions
diff --git a/mkosi.images/system/mkosi.conf b/mkosi.images/system/mkosi.conf
index 9937ad3a98..ccb719a512 100644
--- a/mkosi.images/system/mkosi.conf
+++ b/mkosi.images/system/mkosi.conf
@@ -1,17 +1,51 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
-[Config]
-Dependencies=base
-
-[Distribution]
-CacheOnly=metadata
-
[Output]
@Format=directory
[Content]
-BaseTrees=%O/base
-Initrds=%O/base.initrd
+Autologin=yes
+Packages=
+ acl
+ bash-completion
+ coreutils
+ diffutils
+ dnsmasq
+ dosfstools
+ e2fsprogs
+ findutils
+ gcc # Sanitizer libraries
+ gdb
+ git
+ grep
+ gzip
+ jq
+ kbd
+ kexec-tools
+ kmod
+ less
+ man
+ mtools
+ nano
+ nftables
+ openssl
+ python3
+ qrencode
+ rsync
+ sed
+ socat
+ strace
+ systemd
+ tar
+ tmux
+ tree
+ udev
+ util-linux
+ valgrind
+ wireguard-tools
+ xfsprogs
+ zsh
+ zstd
[Validation]
@SecureBoot=yes
diff --git a/mkosi.images/system/mkosi.conf.d/10-arch/initrd/mkosi.postinst b/mkosi.images/system/mkosi.conf.d/10-arch/initrd/mkosi.postinst
new file mode 100755
index 0000000000..ad4fe6e9a1
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-arch/initrd/mkosi.postinst
@@ -0,0 +1,5 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+mkosi-install systemd systemd-sysvcompat
diff --git a/mkosi.images/system/mkosi.conf.d/10-arch/mkosi.build.chroot b/mkosi.images/system/mkosi.conf.d/10-arch/mkosi.build.chroot
new file mode 100755
index 0000000000..1c5f582701
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-arch/mkosi.build.chroot
@@ -0,0 +1,55 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -ex
+
+if [ ! -f "pkg/$PKG_SUBDIR/PKGBUILD" ]; then
+ echo "PKGBUILD not found at pkg/$PKG_SUBDIR/PKGBUILD, run mkosi once with -ff to make sure the PKGBUILD is cloned" >&2
+ exit 1
+fi
+
+# We can't configure the source or build directory so we use bind mounts instead to make sure they are in the
+# expected locations.
+mount --mkdir --bind "$SRCDIR" "pkg/$PKG_SUBDIR/systemd-stable/"
+mount --mkdir --bind "$BUILDDIR" "pkg/$PKG_SUBDIR/build/"
+# Because we run with --noextract we are responsible for making sure the source files appear in src/.
+mount --mkdir --rbind "$PWD/pkg/$PKG_SUBDIR" "pkg/$PKG_SUBDIR/src/"
+
+# shellcheck source=/dev/null
+. /etc/makepkg.conf
+
+# Override the default options. Use -Og because -O0 doesn't work with FORTIFY_SOURCE. We specifically disable
+# "strip", "zipman" and "lto" as they slow down builds significantly. OPTIONS= cannot be overridden on the
+# makepkg command line so we append to /etc/makepkg.conf instead. The rootfs is overlaid with a writable
+# tmpfs during the build script so these changes don't end up in the image itself.
+tee --append /etc/makepkg.conf >/dev/null <<EOF
+CFLAGS="$CFLAGS -Og"
+OPTIONS=(!strip docs !libtool !staticlibs emptydirs !zipman purge !debug !lto)
+EOF
+
+# Linting the PKGBUILD takes multiple seconds every build so avoid that by nuking all the linting functions.
+rm /usr/share/makepkg/lint_pkgbuild/*
+
+if [ -d .git/ ] && [ -z "$(git status --porcelain)" ]; then
+ TS="$(git show --no-patch --format=%ct HEAD)"
+else
+ TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
+fi
+
+sed --in-place "pkg/$PKG_SUBDIR/PKGBUILD" \
+ --expression "s/^_tag=.*/_tag=$(cat meson.version)/" \
+ --expression "s/^pkgrel=.*/pkgrel=$(date "+%Y%m%d%H%M%S" --date "@$TS")/"
+
+# We get around makepkg's root check by setting EUID to something else.
+# shellcheck disable=SC2046
+env --chdir="pkg/$PKG_SUBDIR" \
+ EUID=123 \
+ makepkg \
+ --noextract \
+ $( ((WITH_TESTS)) || echo --nocheck) \
+ --force \
+ _systemd_UPSTREAM=1 \
+ _systemd_QUIET=1 \
+ BUILDDIR="$PWD/pkg/$PKG_SUBDIR" \
+ PKGDEST="$PACKAGEDIR" \
+ PKGEXT=".pkg.tar" \
+ MESON_EXTRA_CONFIGURE_OPTIONS="-D mode=developer -D b_sanitize=${SANITIZERS:-none}"
diff --git a/mkosi.images/system/mkosi.conf.d/10-arch/mkosi.conf b/mkosi.images/system/mkosi.conf.d/10-arch/mkosi.conf
new file mode 100644
index 0000000000..9cb45cc954
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-arch/mkosi.conf
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+[Match]
+Distribution=arch
+
+[Config]
+InitrdInclude=initrd/
+
+# TODO: Switch to https://gitlab.archlinux.org/archlinux/packaging/packages/systemd once
+# https://gitlab.archlinux.org/archlinux/packaging/packages/systemd/-/merge_requests/8 is merged.
+[Content]
+Environment=
+ PKG_SUBDIR="arch"
+ SYSTEMD_PACKAGES="systemd systemd-ukify systemd-sysvcompat systemd-resolvconf"
+
+Packages=
+ bpf
+ btrfs-progs
+ compsize
+ cryptsetup
+ dbus
+ dhcp
+ f2fs-tools
+ gnutls
+ iproute
+ linux
+ man-db
+ openbsd-netcat
+ openssh
+ openssl
+ pacman
+ polkit
+ qrencode
+ quota-tools
+ sbsigntools
+ shadow
+ tpm2-tss
+ vim
+
+InitrdPackages=
+ btrfs-progs
+ tpm2-tools
+
+BuildPackages=
+ fakeroot
+ pkgconf
+ debugedit
diff --git a/mkosi.images/system/mkosi.conf.d/10-arch/mkosi.prepare b/mkosi.images/system/mkosi.conf.d/10-arch/mkosi.prepare
new file mode 100755
index 0000000000..24c91e5665
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-arch/mkosi.prepare
@@ -0,0 +1,24 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+if [ ! -f "pkg/$PKG_SUBDIR/PKGBUILD" ]; then
+ echo "PKGBUILD not found at pkg/$PKG_SUBDIR/PKGBUILD, run mkosi once with -ff to make sure the PKGBUILD is cloned" >&2
+ exit 1
+fi
+
+if [ "$1" = "final" ]; then
+ # We get depends and optdepends from .SRCINFO as getting them from the PKGBUILD is rather complex.
+ sed --expression 's/^[ \t]*//' "pkg/$PKG_SUBDIR/.SRCINFO" |
+ grep --regexp '^depends =' --regexp '^optdepends =' |
+ sed --expression 's/^depends = //' --expression 's/^optdepends = //' --expression 's/:.*//' |
+ xargs --delimiter '\n' mkosi-install
+else
+ # We get makedepends from the PKGBUILD as .SRCINFO can't encode conditional dependencies depending on
+ # whether some environment variable is set or not.
+ # shellcheck source=/dev/null
+ UPSTREAM=1 . "pkg/$PKG_SUBDIR/PKGBUILD"
+
+ # shellcheck disable=SC2154
+ mkosi-install "${makedepends[@]}"
+fi
diff --git a/mkosi.images/system/mkosi.conf.d/10-centos-fedora/initrd/mkosi.postinst b/mkosi.images/system/mkosi.conf.d/10-centos-fedora/initrd/mkosi.postinst
new file mode 100755
index 0000000000..0b7a4cb6b7
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-centos-fedora/initrd/mkosi.postinst
@@ -0,0 +1,5 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+mkosi-install systemd systemd-udev
diff --git a/mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.build.chroot b/mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.build.chroot
new file mode 100755
index 0000000000..73c1910f8b
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.build.chroot
@@ -0,0 +1,47 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+if [ ! -f "pkg/$PKG_SUBDIR/systemd.spec" ]; then
+ echo "spec not found at pkg/$PKG_SUBDIR/systemd.spec, run mkosi once with -ff to make sure the spec is cloned" >&2
+ exit 1
+fi
+
+if [ -d .git/ ] && [ -z "$(git status --porcelain)" ]; then
+ TS="$(git show --no-patch --format=%ct HEAD)"
+else
+ TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
+fi
+
+# TODO: Replace meson_build and meson_install overrides with "--undefine __meson_verbose" once
+# https://github.com/mesonbuild/meson/pull/12835 is available.
+# shellcheck disable=SC2046
+rpmbuild \
+ -bb \
+ --build-in-place \
+ --with upstream \
+ $( ((WITH_TESTS)) || echo --nocheck) \
+ --define "_topdir /var/tmp" \
+ --define "_sourcedir pkg/$PKG_SUBDIR" \
+ --define "_rpmdir $PACKAGEDIR" \
+ ${BUILDDIR:+--define} \
+ ${BUILDDIR:+"_vpath_builddir $BUILDDIR"} \
+ --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" \
+ --define "_binary_payload w.ufdio" \
+ --define "debug_package %{nil}" \
+ --define "version_override $(cat meson.version)" \
+ --define "release_override $(date "+%Y%m%d%H%M%S" --date "@$TS")" \
+ --define "_distro_extra_cflags -Og" \
+ --define "meson_build %{shrink:%{__meson} compile -C %{_vpath_builddir} -j %{_smp_build_ncpus} %{nil}}" \
+ --define "meson_install %{shrink:DESTDIR=%{buildroot} %{__meson} install -C %{_vpath_builddir} --no-rebuild --quiet %{nil}}" \
+ --define "meson_extra_configure_options -D mode=developer -D b_sanitize=${SANITIZERS:-none}" \
+ --define "__brp_strip %{nil}" \
+ --define "__brp_compress %{nil}" \
+ --define "__brp_mangle_shebangs %{nil}" \
+ --define "__brp_strip_comment_note %{nil}" \
+ --define "__brp_strip_static_archive %{nil}" \
+ --define "__brp_check_rpaths %{nil}" \
+ --define "__elf_exclude_path ^/usr/lib/systemd/tests/unit-tests/.*$" \
+ --define "__script_requires %{nil}" \
+ --undefine _lto_cflags \
+ "pkg/$PKG_SUBDIR/systemd.spec"
diff --git a/mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.conf b/mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.conf
new file mode 100644
index 0000000000..a9ee4a2906
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.conf
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+[Match]
+Distribution=|centos
+Distribution=|fedora
+
+[Config]
+InitrdInclude=initrd/
+
+[Content]
+Environment=
+ SYSTEMD_PACKAGES="systemd
+ systemd-udev
+ systemd-container
+ systemd-repart
+ systemd-resolved
+ systemd-networkd
+ systemd-boot
+ systemd-tests
+ systemd-ukify
+ systemd-pam
+ systemd-oomd-defaults
+ systemd-journal-remote
+ systemd-networkd-defaults"
+Packages=
+ bpftool
+ cryptsetup
+ dhcp-server
+ dnf
+ gnutls
+ integritysetup
+ iproute
+ iproute-tc
+ kernel-core
+ libasan
+ libcap-ng-utils
+ libubsan
+ man-db
+ netcat
+ openssh-clients
+ openssh-server
+ p11-kit
+ pam
+ passwd
+ polkit
+ procps-ng
+ quota
+ rpm
+ rpm-build
+ rpmautospec
+ util-linux
+ vim-common
+
+InitrdPackages=
+ setools
+ selinux-policy
+ tpm2-tools
diff --git a/mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.prepare b/mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.prepare
new file mode 100755
index 0000000000..5bcb1ad481
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.prepare
@@ -0,0 +1,66 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+if [ ! -f "pkg/$PKG_SUBDIR/systemd.spec" ]; then
+ echo "spec not found at pkg/$PKG_SUBDIR/systemd.spec, run mkosi with -ff to make sure the spec is cloned" >&2
+ exit 1
+fi
+
+if [ "$1" = "final" ]; then
+ DEPS="--requires"
+else
+ DEPS="--buildrequires"
+fi
+
+mkosi-chroot \
+ rpmspec \
+ --with upstream \
+ --query \
+ "$DEPS" \
+ --define "_topdir /var/tmp" \
+ --define "_sourcedir pkg/$PKG_SUBDIR" \
+ "pkg/$PKG_SUBDIR/systemd.spec" |
+ grep --invert-match --regexp systemd --regexp /bin/sh --regexp "rpmlib(" --regexp udev |
+ sort --unique |
+ tee /tmp/buildrequires |
+ xargs --delimiter '\n' mkosi-install
+
+if [ "$1" = "final" ]; then
+ exit 0
+fi
+
+# rpmbuild -br tries to build a source package which means all source files have to exist which isn't the
+# case when using --build-in-place so we get rid of the source file that doesn't exist to make it happy.
+# TODO: Use -bd instead of -br and get rid of this once we don't need to build on CentOS Stream 9 anymore.
+sed '/Source0/d' --in-place "pkg/$PKG_SUBDIR/systemd.spec"
+
+until mkosi-chroot \
+ rpmbuild \
+ -br \
+ --build-in-place \
+ --with upstream \
+ --define "_topdir /var/tmp" \
+ --define "_sourcedir pkg/$PKG_SUBDIR" \
+ --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" \
+ "pkg/$PKG_SUBDIR/systemd.spec"
+do
+ EXIT_STATUS=$?
+ if [ $EXIT_STATUS -ne 11 ]; then
+ exit $EXIT_STATUS
+ fi
+
+ mkosi-chroot \
+ rpm \
+ --query \
+ --package \
+ --requires \
+ /var/tmp/SRPMS/systemd-*.buildreqs.nosrc.rpm |
+ grep --invert-match '^rpmlib(' |
+ sort --unique >/tmp/dynamic-buildrequires
+
+ sort /tmp/buildrequires /tmp/dynamic-buildrequires |
+ uniq --unique |
+ tee --append /tmp/buildrequires |
+ xargs --delimiter '\n' mkosi-install
+done
diff --git a/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.conf b/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.conf
index af4862d4b1..0f57319c2a 100644
--- a/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.conf
+++ b/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.conf
@@ -2,3 +2,11 @@
[Match]
Distribution=centos
+
+[Content]
+Environment=
+ PKG_SUBDIR="centos"
+
+Packages=
+ kernel-modules # For squashfs support
+ rpmautospec-rpm-macros
diff --git a/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/initrd/mkosi.postinst b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/initrd/mkosi.postinst
new file mode 100755
index 0000000000..640cdb1e32
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/initrd/mkosi.postinst
@@ -0,0 +1,5 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+mkosi-install systemd udev
diff --git a/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.build.chroot b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.build.chroot
new file mode 100755
index 0000000000..7fb650f501
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.build.chroot
@@ -0,0 +1,89 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+if [ ! -d "pkg/$PKG_SUBDIR/debian" ]; then
+ echo "deb rules not found at pkg/$PKG_SUBDIR/debian, run mkosi once with -ff to make sure the rules are cloned" >&2
+ exit 1
+fi
+
+# We transplant the debian/ folder from the deb package sources into the upstream sources.
+mount --mkdir --bind "$SRCDIR/pkg/$PKG_SUBDIR/debian" "$SRCDIR"/debian
+
+# We hide the patches/ directory by mounting an empty directory on top so they don't get applied.
+TMP=$(mktemp -d)
+mount --bind "$TMP" "$SRCDIR"/debian/patches
+
+# While the build directory can be specified through DH_OPTIONS, the default one is hardcoded everywhere so
+# we have to use that. Because it is architecture dependent, we query it using dpkg-architecture first.
+DEB_HOST_GNU_TYPE="$(dpkg-architecture --query DEB_HOST_GNU_TYPE)"
+mount --mkdir --bind "$BUILDDIR" "$SRCDIR/obj-$DEB_HOST_GNU_TYPE"
+
+if [ -d .git/ ] && [ -z "$(git status --porcelain)" ]; then
+ TS="$(git show --no-patch --format=%ct HEAD)"
+else
+ TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
+fi
+
+# Add a new changelog entry to update the version. We use a fixed date since a dynamic one causes a full
+# rebuild every time.
+cat >debian/changelog.new <<EOF
+systemd ($(cat meson.version).$(date "+%Y%m%d%H%M%S" --date "@$TS")) UNRELEASED; urgency=low
+
+ * Automatic build from mkosi
+
+ -- systemd test <systemd-devel@lists.freedesktop.org> $(date --rfc-email --date "@$TS")
+
+EOF
+cat debian/changelog >>debian/changelog.new
+mv debian/changelog.new debian/changelog
+
+build() {
+ DEB_BUILD_OPTIONS="$( ((WITH_TESTS)) || echo nocheck) $( ((WITH_DOCS)) || echo nodoc) nostrip terse optimize=-lto" \
+ DEB_BUILD_PROFILES="$( ((WITH_TESTS)) || echo nocheck) $( ((WITH_DOCS)) || echo nodoc) pkg.systemd.upstream" \
+ DEB_CFLAGS_APPEND="-Og" \
+ DPKG_FORCE="unsafe-io" \
+ DPKG_DEB_COMPRESSOR_TYPE="none" \
+ DH_MISSING="--fail-missing" \
+ CONFFLAGS_UPSTREAM="-D mode=developer -D b_sanitize=${SANITIZERS:-none}" \
+ dpkg-buildpackage \
+ --no-pre-clean \
+ --unsigned-changes \
+ --build=binary
+}
+
+if ! build; then
+ # debhelper installs files for each package to debian/<package> so we figure out which files were
+ # packaged by querying all the package names from debian/control and running find on each of the
+ # corresponding package directory in debian/.
+ grep "Package:" debian/control |
+ sed "s/Package: //" |
+ xargs -d '\n' -I {} sh -c "[ -d debian/{} ] && (cd debian/{} && find . ! -type d ! -path "*dh-exec*" -printf '%P\n')" |
+ # Remove compression suffix from compressed manpages as the manpages in debian/tmp will be uncompressed.
+ sed --regexp-extended 's/([0-9])\.gz$/\1/' |
+ sort --unique >/tmp/packaged-files
+
+ # We figure out the installed files by running find on debian/tmp/ which contains the files installed
+ # by meson install.
+ (cd debian/tmp/ && find . ! -type d ! -path "*dh-exec*" -printf '%P\n') >/tmp/installed-files
+
+ if [ -f debian/not-installed ]; then
+ grep --invert-match "^#" debian/not-installed >>/tmp/installed-files
+ fi
+
+ sort --unique --output /tmp/installed-files /tmp/installed-files
+
+ # We get all the installed files that were not packaged by finding entries in the installed file that are
+ # not in the packaged file.
+ comm -23 /tmp/installed-files /tmp/packaged-files > /tmp/unpackaged-files
+ # If there are no unpackaged files something else went wrong.
+ if [ ! -s /tmp/unpackaged-files ]; then
+ exit 1
+ fi
+
+ # Otherwise, we append the unpackaged files to the filelist for the systemd package and retry the build.
+ cat /tmp/unpackaged-files >>debian/systemd.install
+ build
+fi
+
+mv ../*.deb "$PACKAGEDIR"
diff --git a/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.conf b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.conf
new file mode 100644
index 0000000000..07c9b3a805
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.conf
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+[Match]
+Distribution=|debian
+Distribution=|ubuntu
+
+[Config]
+InitrdInclude=initrd/
+
+[Content]
+Environment=
+ PKG_SUBDIR="debian"
+ SYSTEMD_PACKAGES="systemd
+ systemd-userdbd
+ systemd-oomd
+ systemd-sysv
+ systemd-tests
+ systemd-timesyncd
+ systemd-resolved
+ systemd-homed
+ systemd-coredump
+ systemd-journal-remote
+ systemd-container
+ systemd-boot
+ systemd-ukify
+ udev"
+
+Packages=
+ ^libtss2-esys-[0-9.]+-0$
+ ^libtss2-mu-[0-9.]+-0$
+ apt
+ btrfs-progs
+ cryptsetup-bin
+ dbus-broker
+ default-dbus-session-bus
+ dmsetup
+ f2fs-tools
+ fdisk
+ iproute2
+ isc-dhcp-server
+ libcap-ng-utils
+ libtss2-rc0
+ libtss2-tcti-device0
+ man-db
+ netcat-openbsd
+ openssh-client
+ openssh-server
+ passwd
+ policykit-1
+ procps
+ quota
+ sbsigntool
+ tzdata
+ xxd
+
+InitrdPackages=
+ btrfs-progs
+ tpm2-tools
+
+BuildPackages=
+ dpkg-dev
diff --git a/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.prepare b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.prepare
new file mode 100755
index 0000000000..ae0d6fd92f
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.prepare
@@ -0,0 +1,15 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+if [ "$1" = "final" ]; then
+ exit 0
+fi
+
+if [ ! -d "pkg/$PKG_SUBDIR/debian" ]; then
+ echo "deb rules not found at pkg/$PKG_SUBDIR/debian, run mkosi once with -ff to make sure the rules are cloned" >&2
+ exit 1
+fi
+
+cd "pkg/$PKG_SUBDIR"
+DEB_BUILD_PROFILES="pkg.systemd.upstream" apt-get build-dep .
diff --git a/mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf b/mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf
new file mode 100644
index 0000000000..c6b6155dda
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+[Match]
+Distribution=debian
diff --git a/mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf.d/amd64.conf b/mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf.d/amd64.conf
new file mode 100644
index 0000000000..615de52499
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf.d/amd64.conf
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+[Match]
+Architecture=x86-64
+
+[Content]
+Packages=
+ linux-image-cloud-amd64
diff --git a/mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf.d/arm64.conf b/mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf.d/arm64.conf
new file mode 100644
index 0000000000..af923fa442
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-debian/mkosi.conf.d/arm64.conf
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+[Match]
+Architecture=arm64
+
+[Content]
+Packages=
+ linux-image-cloud-arm64
diff --git a/mkosi.images/system/mkosi.conf.d/10-fedora/mkosi.conf b/mkosi.images/system/mkosi.conf.d/10-fedora/mkosi.conf
new file mode 100644
index 0000000000..a0b9f6f0fe
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-fedora/mkosi.conf
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+[Match]
+Distribution=fedora
+
+[Content]
+Environment=
+ PKG_SUBDIR="fedora"
+
+Packages=
+ btrfs-progs
+ compsize
+ f2fs-tools
+ glibc-langpack-en
+ sbsigntools
+
+InitrdPackages=
+ btrfs-progs
diff --git a/mkosi.images/system/mkosi.conf.d/10-opensuse/initrd/mkosi.postinst b/mkosi.images/system/mkosi.conf.d/10-opensuse/initrd/mkosi.postinst
new file mode 100755
index 0000000000..562bebe08e
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-opensuse/initrd/mkosi.postinst
@@ -0,0 +1,9 @@
+#!/bin/sh
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+# OpenSUSE insists on blacklisting erofs by default because its supposedly a legacy filesystem.
+# See https://github.com/openSUSE/suse-module-tools/pull/71
+rm -f "$BUILDROOT/usr/lib/modprobe.d/60-blacklist_fs-erofs.conf"
+
+mkosi-install systemd udev systemd-experimental
diff --git a/mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.build.chroot b/mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.build.chroot
new file mode 100755
index 0000000000..b809a10bb0
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.build.chroot
@@ -0,0 +1,63 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+if [ ! -f "pkg/$PKG_SUBDIR/systemd.spec" ]; then
+ echo "spec not found at pkg/$PKG_SUBDIR/systemd.spec, run mkosi once with -ff to make sure the spec is cloned" >&2
+ exit 1
+fi
+
+if [ -d .git/ ] && [ -z "$(git status --porcelain)" ]; then
+ TS="$(git show --no-patch --format=%ct HEAD)"
+else
+ TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
+fi
+
+# The openSUSE filelists hardcode the manpage compression extension. This causes rpmbuild errors since we
+# disable manpage compression as the files cannot be found. Fix the issue by removing the compression
+# extension.
+find "pkg/$PKG_SUBDIR" -name "files.*" -exec sed --in-place 's/\.gz$//' {} \;
+
+build() {
+ # TODO: Replace meson_build and meson_install overrides with "--undefine __meson_verbose" once
+ # https://github.com/mesonbuild/meson/pull/12835 is available.
+ # shellcheck disable=SC2046
+ rpmbuild \
+ -bb \
+ --build-in-place \
+ --with upstream \
+ $( ((WITH_TESTS)) || echo --nocheck) \
+ --define "_topdir /var/tmp" \
+ --define "_sourcedir pkg/$PKG_SUBDIR" \
+ --define "_rpmdir $PACKAGEDIR" \
+ ${BUILDDIR:+--define} \
+ ${BUILDDIR:+"_vpath_builddir $BUILDDIR"} \
+ --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" \
+ --define "_binary_payload w.ufdio" \
+ --define "debug_package %{nil}" \
+ --define "vendor openSUSE" \
+ --define "version_override $(cat meson.version)" \
+ --define "release_override $(date "+%Y%m%d%H%M%S" --date "@$TS")" \
+ --define "__check_files sh -c '$(rpm --eval %__check_files) | tee /tmp/unpackaged-files'" \
+ --define "meson_build %{shrink:%{__meson} compile -C %{_vpath_builddir} -j %{_smp_build_ncpus} %{nil}}" \
+ --define "meson_install %{shrink:DESTDIR=%{buildroot} %{__meson} install -C %{_vpath_builddir} --no-rebuild --quiet %{nil}}" \
+ --define "meson_extra_configure_options -D mode=developer -D b_sanitize=${SANITIZERS:-none}" \
+ --define "__os_install_post /usr/lib/rpm/brp-suse %{nil}" \
+ --define "__elf_exclude_path ^/usr/lib/systemd/tests/unit-tests/.*$" \
+ --define "__script_requires %{nil}" \
+ "$@" \
+ "pkg/$PKG_SUBDIR/systemd.spec"
+}
+
+if ! build; then
+ if [ ! -s /tmp/unpackaged-files ]; then
+ exit 1
+ fi
+
+ # rpm will append to any existing systemd.lang so delete it explicitly so we don't get duplicate file
+ # warnings.
+ rm systemd.lang
+
+ cat /tmp/unpackaged-files >>"pkg/$PKG_SUBDIR/files.systemd"
+ build --noprep --nocheck
+fi
diff --git a/mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.conf b/mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.conf
new file mode 100644
index 0000000000..45947a395b
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.conf
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+[Match]
+Distribution=opensuse
+
+[Config]
+InitrdInclude=initrd/
+
+[Content]
+Environment=
+ PKG_SUBDIR="opensuse"
+ SYSTEMD_PACKAGES="systemd
+ udev
+ systemd-experimental
+ systemd-boot
+ systemd-container
+ systemd-homed
+ systemd-network
+ systemd-portable
+ systemd-sysvcompat
+ systemd-testsuite"
+
+# We install gawk, gzip, grep, xz, sed, rsync and docbook-xsl-stylesheets here explicitly so that the busybox
+# versions don't get installed instead.
+Packages=
+ bpftool
+ btrfs-progs
+ cryptsetup
+ dbus-broker
+ device-mapper
+ distribution-release
+ docbook-xsl-stylesheets
+ f2fs-tools
+ gawk
+ glibc-locale-base
+ grep
+ gzip
+ kernel-kvmsmall
+ openssh-clients
+ openssh-server
+ pam
+ python3-pefile
+ quota
+ rpm-build
+ rsync
+ sbsigntools
+ sed
+ shadow
+ timezone
+ vim
+ xz
+
+InitrdPackages=
+ btrfs-progs
+ tpm2.0-tools
diff --git a/mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.prepare b/mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.prepare
new file mode 100755
index 0000000000..a35a8f3bba
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.prepare
@@ -0,0 +1,61 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+if [ ! -f "pkg/$PKG_SUBDIR/systemd.spec" ]; then
+ echo "spec not found at pkg/$PKG_SUBDIR/systemd.spec, run mkosi once with -ff to make sure the spec is cloned" >&2
+ exit 1
+fi
+
+if [ "$1" = "final" ]; then
+ DEPS="--requires"
+else
+ DEPS="--buildrequires"
+fi
+
+mkosi-chroot \
+ rpmspec \
+ --with upstream \
+ --query \
+ "$DEPS" \
+ --define "_topdir /var/tmp" \
+ --define "_sourcedir pkg/$PKG_SUBDIR" \
+ "pkg/$PKG_SUBDIR/systemd.spec" |
+ grep --invert-match --regexp systemd --regexp /bin/sh --regexp "rpmlib(" --regexp udev |
+ sort --unique |
+ tee /tmp/buildrequires |
+ xargs --delimiter '\n' mkosi-install
+
+if [ "$1" = "final" ]; then
+ exit 0
+fi
+
+until mkosi-chroot \
+ rpmbuild \
+ -bd \
+ --build-in-place \
+ --with upstream \
+ --define "_topdir /var/tmp" \
+ --define "_sourcedir pkg/$PKG_SUBDIR" \
+ --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" \
+ "pkg/$PKG_SUBDIR/systemd.spec"
+do
+ EXIT_STATUS=$?
+ if [ $EXIT_STATUS -ne 11 ]; then
+ exit $EXIT_STATUS
+ fi
+
+ mkosi-chroot \
+ rpm \
+ --query \
+ --package \
+ --requires \
+ /var/tmp/SRPMS/systemd-*.buildreqs.nosrc.rpm |
+ grep --invert-match '^rpmlib(' |
+ sort --unique >/tmp/dynamic-buildrequires
+
+ sort /tmp/buildrequires /tmp/dynamic-buildrequires |
+ uniq --unique |
+ tee --append /tmp/buildrequires |
+ xargs --delimiter '\n' mkosi-install
+done
diff --git a/mkosi.images/system/mkosi.conf.d/10-ubuntu/mkosi.conf b/mkosi.images/system/mkosi.conf.d/10-ubuntu/mkosi.conf
new file mode 100644
index 0000000000..85126a1a37
--- /dev/null
+++ b/mkosi.images/system/mkosi.conf.d/10-ubuntu/mkosi.conf
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+[Match]
+Distribution=ubuntu
+
+[Content]
+Packages=
+ # We would like to use linux-virtual but it does not have support for SMBIOS credentials.
+ linux-image-generic
+ linux-tools-common
+ linux-tools-generic
diff --git a/mkosi.images/system/mkosi.extra/etc/issue b/mkosi.images/system/mkosi.extra/etc/issue
new file mode 100644
index 0000000000..6aa6fc0ec0
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/etc/issue
@@ -0,0 +1,2 @@
+\S (built from systemd tree)
+Kernel \r on an \m (\l)
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/journald.conf.d/50-persistent.conf b/mkosi.images/system/mkosi.extra/usr/lib/systemd/journald.conf.d/50-persistent.conf
new file mode 100644
index 0000000000..2f953290d3
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/journald.conf.d/50-persistent.conf
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# We only ship /usr in the image so /var/log/journal won't exist on boot which means systemd-journald won't
+# persist any logs as the default Storage= setting is "auto". We can't create /var/log/journal using tmpfiles
+# as systemd-journal-flush.service runs before systemd-tmpfiles-setup.service so instead we explicitly set
+# Storage= to persistent to have systemd-journald create /var/log/journal itself.
+[Journal]
+Storage=persistent
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
new file mode 100755
index 0000000000..d2800a04a9
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
@@ -0,0 +1,20 @@
+#!/bin/bash -eux
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+systemctl --failed --no-legend | tee /failed-services
+
+# Check that secure boot keys were properly enrolled.
+if ! systemd-detect-virt --container && \
+ cmp /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c <(printf '\6\0\0\0\1')
+then
+ cmp /sys/firmware/efi/efivars/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c <(printf '\6\0\0\0\0')
+
+ if command -v sbsign &>/dev/null; then
+ cat /proc/cmdline
+ grep -q this_should_be_here /proc/cmdline
+ (! grep -q this_should_not_be_here /proc/cmdline)
+ fi
+fi
+
+# Exit with non-zero EC if the /failed-services file is not empty (we have -e set)
+[[ ! -s /failed-services ]]
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/system-preset/00-mkosi.preset b/mkosi.images/system/mkosi.extra/usr/lib/systemd/system-preset/00-mkosi.preset
new file mode 100644
index 0000000000..070af4c67a
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/system-preset/00-mkosi.preset
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# mkosi adds its own ssh units via the --ssh switch so disable the default ones.
+disable ssh.service
+disable sshd.service
+
+# These are started manually in integration tests so don't start them by default.
+disable dnsmasq.service
+disable isc-dhcp-server.service
+disable isc-dhcp-server6.service
+
+# Pulled in via dracut-network by kexec-tools on Fedora.
+disable NetworkManager*
+
+# Make sure dbus-broker is started by default on Debian/Ubuntu.
+enable dbus-broker.service
+
+# systemd-networkd is disabled by default on Fedora so make sure it is enabled.
+enable systemd-networkd.service
+enable systemd-networkd-wait-online.service
+
+# We install dnf in some images but it's only going to be used rarely,
+# so let's not have dnf create its cache.
+disable dnf-makecache.*
+
+# We have journald to receive audit data so let's make sure we're not running auditd as well
+disable auditd.service
+
+# systemd-timesyncd is not enabled by default in the default systemd preset so enable it here instead.
+enable systemd-timesyncd.service
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/system-preset/99-mkosi.preset b/mkosi.images/system/mkosi.extra/usr/lib/systemd/system-preset/99-mkosi.preset
new file mode 100644
index 0000000000..710ee7c6f9
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/system-preset/99-mkosi.preset
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# Make sure that services are disabled by default (primarily for Debian/Ubuntu).
+disable *
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/systemd/system/mkosi-check-and-shutdown.service b/mkosi.images/system/mkosi.extra/usr/lib/systemd/system/mkosi-check-and-shutdown.service
new file mode 100644
index 0000000000..7942cbfa77
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/usr/lib/systemd/system/mkosi-check-and-shutdown.service
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Unit]
+Description=Check if any service failed and then shutdown the machine
+After=multi-user.target network-online.target
+Requires=multi-user.target
+Wants=systemd-resolved.service systemd-networkd.service network-online.target
+SuccessAction=exit
+FailureAction=exit
+# On success, exit with 123 so that we can check that we receive the actual exit code from the script on the
+# host.
+SuccessActionExitStatus=123
+
+[Service]
+Type=oneshot
+ExecStart=/usr/lib/systemd/mkosi-check-and-shutdown.sh
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/tmpfiles.d/99-mkosi.conf b/mkosi.images/system/mkosi.extra/usr/lib/tmpfiles.d/99-mkosi.conf
new file mode 100644
index 0000000000..dac79ba4ed
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/usr/lib/tmpfiles.d/99-mkosi.conf
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+C+! /etc - - - - /usr/share/factory/mkosi
diff --git a/mkosi.images/system/mkosi.extra/usr/lib/tmpfiles.d/locale.conf b/mkosi.images/system/mkosi.extra/usr/lib/tmpfiles.d/locale.conf
new file mode 100644
index 0000000000..e1a8e8171a
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/usr/lib/tmpfiles.d/locale.conf
@@ -0,0 +1 @@
+L /etc/default/locale - - - - ../locale.conf
diff --git a/mkosi.images/system/mkosi.extra/usr/share/factory/mkosi/gdbinit.d/systemd.gdb b/mkosi.images/system/mkosi.extra/usr/share/factory/mkosi/gdbinit.d/systemd.gdb
new file mode 100644
index 0000000000..26f882bc2b
--- /dev/null
+++ b/mkosi.images/system/mkosi.extra/usr/share/factory/mkosi/gdbinit.d/systemd.gdb
@@ -0,0 +1,3 @@
+set debuginfod enabled off
+set build-id-verbose 0
+set substitute-path ../src /root/src/systemd
diff --git a/mkosi.images/system/mkosi.finalize b/mkosi.images/system/mkosi.finalize
new file mode 100755
index 0000000000..74b810c152
--- /dev/null
+++ b/mkosi.images/system/mkosi.finalize
@@ -0,0 +1,4 @@
+#!/bin/sh
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+cp --archive --recursive --no-target-directory --reflink=auto "$BUILDROOT"/etc "$BUILDROOT"/usr/share/factory/mkosi
diff --git a/mkosi.images/system/mkosi.postinst b/mkosi.images/system/mkosi.postinst
new file mode 100755
index 0000000000..caaf253ef6
--- /dev/null
+++ b/mkosi.images/system/mkosi.postinst
@@ -0,0 +1,6 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+# shellcheck disable=SC2086
+mkosi-install $SYSTEMD_PACKAGES
diff --git a/mkosi.images/system/mkosi.postinst.chroot b/mkosi.images/system/mkosi.postinst.chroot
new file mode 100755
index 0000000000..d1052694aa
--- /dev/null
+++ b/mkosi.images/system/mkosi.postinst.chroot
@@ -0,0 +1,75 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+if [ -n "$SANITIZERS" ]; then
+ LD_PRELOAD=$(ldd /usr/lib/systemd/systemd | grep libasan.so | awk '{print $3}')
+
+ mkdir -p /etc/systemd/system.conf.d
+
+ cat >/etc/systemd/system.conf.d/10-asan.conf <<EOF
+[Manager]
+ManagerEnvironment=ASAN_OPTIONS=$MKOSI_ASAN_OPTIONS\\
+ UBSAN_OPTIONS=$MKOSI_UBSAN_OPTIONS\\
+ LD_PRELOAD=$LD_PRELOAD
+DefaultEnvironment=ASAN_OPTIONS=$MKOSI_ASAN_OPTIONS\\
+ UBSAN_OPTIONS=$MKOSI_UBSAN_OPTIONS\\
+ LD_PRELOAD=$LD_PRELOAD
+EOF
+
+ # ASAN logs to stderr by default. However, journald's stderr is connected to /dev/null, so we lose
+ # all the ASAN logs. To rectify that, let's connect journald's stdout to the console so that any
+ # sanitizer failures appear directly on the user's console.
+ mkdir -p /etc/systemd/system/systemd-journald.service.d
+ cat >/etc/systemd/system/systemd-journald.service.d/10-stdout-tty.conf <<EOF
+[Service]
+StandardOutput=tty
+EOF
+
+ # Both systemd and util-linux's login call vhangup() on /dev/console which disconnects all users.
+ # This means systemd-journald can't log to /dev/console even if we configure `StandardOutput=tty`. As
+ # a workaround, we modify console-getty.service to disable systemd's vhangup() and disallow login
+ # from calling vhangup() so that journald's ASAN logs correctly end up in the console.
+
+ mkdir -p /etc/systemd/system/console-getty.service.d
+ cat >/etc/systemd/system/console-getty.service.d/10-no-vhangup.conf <<EOF
+[Service]
+TTYVHangup=no
+CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG
+EOF
+ # ASAN and syscall filters aren't compatible with each other.
+ find / -name '*.service' -type f -exec sed -i 's/^\(MemoryDeny\|SystemCall\)/# \1/' {} +
+
+ # `systemd-hwdb update` takes > 50s when built with sanitizers so let's not run it by default.
+ systemctl mask systemd-hwdb-update.service
+fi
+
+if command -v authselect >/dev/null; then
+ # authselect 1.5.0 renamed the minimal profile to the local profile without keeping backwards compat so
+ # let's use the new name if it exists.
+ if [ -d /usr/share/authselect/default/local ]; then
+ PROFILE=local
+ else
+ PROFILE=minimal
+ fi
+
+ authselect select "$PROFILE"
+
+ if authselect list-features "$PROFILE" | grep -q "with-homed"; then
+ authselect enable-feature with-homed
+ fi
+fi
+
+# Let tmpfiles.d/systemd-resolve.conf handle the symlink. /etc/resolv.conf might be mounted over so undo that
+# if that's the case.
+mountpoint -q /etc/resolv.conf && umount /etc/resolv.conf
+rm -f /etc/resolv.conf
+
+# sbsign is not available on CentOS Stream
+if command -v sbsign &>/dev/null; then
+ # Ensure that side-loaded PE addons are loaded if signed, and ignored if not
+ addons_dir=/efi/loader/addons
+ mkdir -p "$addons_dir"
+ ukify build --secureboot-private-key mkosi.key --secureboot-certificate mkosi.crt --cmdline this_should_be_here -o "$addons_dir/good.addon.efi"
+ ukify build --cmdline this_should_not_be_here -o "$addons_dir/bad.addon.efi"
+fi
diff --git a/mkosi.images/system/mkosi.sync b/mkosi.images/system/mkosi.sync
new file mode 100755
index 0000000000..72b5cf7c33
--- /dev/null
+++ b/mkosi.images/system/mkosi.sync
@@ -0,0 +1,8 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+if [ -z "$(ls --almost-all "pkg/$PKG_SUBDIR")" ] || [ -f "pkg/$PKG_SUBDIR/.git" ]; then
+ git submodule sync "pkg/$PKG_SUBDIR"
+ git submodule update --init "pkg/$PKG_SUBDIR"
+fi