summaryrefslogtreecommitdiffstats
path: root/modules.d
diff options
context:
space:
mode:
Diffstat (limited to 'modules.d')
-rwxr-xr-xmodules.d/bootnet-conf/module-setup.sh13
-rwxr-xr-xmodules.d/bootnet-conf/scripts/gen-bootnet-conf.sh18
-rw-r--r--modules.d/busybox/install-busybox-stage4.sh16
-rw-r--r--modules.d/busybox/install-busybox.sh9
-rw-r--r--modules.d/busybox/module-setup.sh42
-rw-r--r--modules.d/busybox/openslx.config1191
-rwxr-xr-xmodules.d/conf-tgz/hooks/fetch-config-tgz.sh29
-rwxr-xr-xmodules.d/conf-tgz/hooks/unpack-config-tgz.sh41
-rwxr-xr-xmodules.d/conf-tgz/module-setup.sh13
m---------modules.d/dnbd3-rootfs/binaries/dnbd30
m---------modules.d/dnbd3-rootfs/binaries/kernel-qcow2-linux0
m---------modules.d/dnbd3-rootfs/binaries/kernel-qcow2-util-linux0
m---------modules.d/dnbd3-rootfs/binaries/qemu-xmount0
-rw-r--r--modules.d/dnbd3-rootfs/binaries/systemd-preserve-process-marker/Makefile12
-rw-r--r--modules.d/dnbd3-rootfs/binaries/systemd-preserve-process-marker/systemd-preserve-process-marker.c33
m---------modules.d/dnbd3-rootfs/binaries/xmount0
-rwxr-xr-xmodules.d/dnbd3-rootfs/configuration/bash3
-rw-r--r--modules.d/dnbd3-rootfs/helper/build.inc291
-rwxr-xr-xmodules.d/dnbd3-rootfs/hooks/copy-dnbd3-service-into-newroot.sh12
-rwxr-xr-xmodules.d/dnbd3-rootfs/hooks/copy-dracut-systemd-files-into-newroot.sh35
-rwxr-xr-xmodules.d/dnbd3-rootfs/hooks/copy-openslx-configuration-into-newroot.sh18
-rwxr-xr-xmodules.d/dnbd3-rootfs/hooks/enable-sysrq.sh5
-rwxr-xr-xmodules.d/dnbd3-rootfs/hooks/fetch-config.sh50
-rwxr-xr-xmodules.d/dnbd3-rootfs/hooks/load-custom-kernel-modules.sh12
-rwxr-xr-xmodules.d/dnbd3-rootfs/hooks/mount-root-device.sh9
-rwxr-xr-xmodules.d/dnbd3-rootfs/hooks/prepare-root-partition.sh107
-rwxr-xr-xmodules.d/dnbd3-rootfs/hooks/set-dracut-environment-variables.sh16
-rw-r--r--modules.d/dnbd3-rootfs/hooks/shutdown-umount.sh11
-rwxr-xr-xmodules.d/dnbd3-rootfs/module-setup.sh231
-rw-r--r--modules.d/dnbd3-rootfs/services/dnbd3root.service12
-rwxr-xr-xmodules.d/dns/module-setup.sh13
-rwxr-xr-xmodules.d/dns/scripts/gen-resolv-conf.sh11
-rw-r--r--modules.d/haveged/module-setup.sh41
-rwxr-xr-xmodules.d/ib-conf/module-setup.sh13
-rwxr-xr-xmodules.d/ib-conf/scripts/gen-ib-conf.sh29
-rwxr-xr-xmodules.d/kexec-reboot/module-setup.sh18
-rwxr-xr-xmodules.d/kexec-reboot/scripts/kexec-reboot.sh39
-rwxr-xr-xmodules.d/slx-addons/module-setup.sh12
-rw-r--r--modules.d/slx-addons/scripts/setup-addons.sh105
-rwxr-xr-xmodules.d/slx-clock/module-setup.sh20
-rwxr-xr-xmodules.d/slx-clock/scripts/ntp-sync.sh55
-rwxr-xr-xmodules.d/slx-dmsetup/module-setup.sh24
-rwxr-xr-xmodules.d/slx-dmsetup/scripts/dmsetup-slx-device446
-rw-r--r--modules.d/slx-dmsetup/scripts/gen-fstab-persistent52
-rw-r--r--modules.d/slx-dmsetup/scripts/generate-fstab-persistent.sh52
-rw-r--r--modules.d/slx-dmsetup/scripts/generate-fstab-swap.sh33
-rwxr-xr-xmodules.d/slx-dmsetup/scripts/get-partitions-by-id60
-rw-r--r--modules.d/slx-dmsetup/scripts/grow-rootfs.sh45
-rw-r--r--modules.d/slx-drm/hooks/activate-nvidia-drivers.sh42
-rw-r--r--modules.d/slx-drm/hooks/copy-nvidia-drivers.sh28
-rwxr-xr-xmodules.d/slx-drm/module-setup.sh22
-rw-r--r--modules.d/slx-network/TODO1
-rw-r--r--modules.d/slx-network/hooks/activate-bootif-dhcp.sh26
-rw-r--r--modules.d/slx-network/hooks/copy-network-files.sh31
-rw-r--r--modules.d/slx-network/hooks/parse-ipxe-network-kcl.sh95
-rwxr-xr-xmodules.d/slx-network/module-setup.sh40
-rw-r--r--modules.d/slx-network/rdns.c28
-rwxr-xr-xmodules.d/slx-network/scripts/setup-bootif-network.stage3112
-rwxr-xr-xmodules.d/slx-network/scripts/setup-bootif-network.stage456
-rwxr-xr-xmodules.d/slx-network/scripts/udhcpc-trigger.stage3140
-rwxr-xr-xmodules.d/slx-network/scripts/udhcpc-trigger.stage4208
-rw-r--r--modules.d/slx-network/services/udhcpc-bootif.service12
-rwxr-xr-xmodules.d/slx-runmode/module-setup.sh13
-rw-r--r--modules.d/slx-runmode/scripts/runmode.sh13
-rw-r--r--modules.d/slx-splash/data/splash.ppm.gzbin0 -> 11233 bytes
-rwxr-xr-xmodules.d/slx-splash/module-setup.sh14
-rw-r--r--modules.d/slx-splash/scripts/restore-cursor.sh11
-rw-r--r--modules.d/slx-splash/scripts/slx-splash.sh44
-rw-r--r--modules.d/slx-tools/module-setup.sh28
-rwxr-xr-xmodules.d/slx-tpm/module-setup.sh93
-rw-r--r--modules.d/slx-uuid/bad-uuid-defaults.conf8
-rwxr-xr-xmodules.d/slx-uuid/module-setup.sh20
-rw-r--r--modules.d/slx-uuid/scripts/copy-system-uuid-to-newroot.sh6
-rw-r--r--modules.d/slx-uuid/scripts/get-system-uuid.sh69
-rw-r--r--modules.d/systemd-networkd-ext/hooks/configure-dhcp-for-newroot.sh64
-rw-r--r--modules.d/systemd-networkd-ext/hooks/copy-networkd-files-to-newroot.sh33
-rw-r--r--modules.d/systemd-networkd-ext/hooks/parse-kcl-for-networkd.sh251
-rwxr-xr-xmodules.d/systemd-networkd-ext/module-setup.sh77
78 files changed, 4882 insertions, 0 deletions
diff --git a/modules.d/bootnet-conf/module-setup.sh b/modules.d/bootnet-conf/module-setup.sh
new file mode 100755
index 00000000..f1d6697f
--- /dev/null
+++ b/modules.d/bootnet-conf/module-setup.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+check() {
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ return 255
+}
+depends() {
+ echo dnbd3-rootfs
+}
+install() {
+ inst_hook pre-pivot 50 "$moddir/scripts/gen-bootnet-conf.sh"
+}
diff --git a/modules.d/bootnet-conf/scripts/gen-bootnet-conf.sh b/modules.d/bootnet-conf/scripts/gen-bootnet-conf.sh
new file mode 100755
index 00000000..ec82f143
--- /dev/null
+++ b/modules.d/bootnet-conf/scripts/gen-bootnet-conf.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+mac="$(getargs BOOTIF=)"
+mac="$(echo $mac | cut -c 4- | tr '-' ':')"
+if [ -n "${mac}" ]; then
+ cat << EOF >> "${NEWROOT}/etc/sysconfig/network-scripts/ifcfg-bootnet"
+DEVICE=bootnet
+NAME=bootnet
+HWADDR=${mac}
+BOOTPROTO=dhcp
+ONBOOT=yes
+NM_CONTROLLED=yes
+EOF
+else
+ echo "Could not parse MAC"
+fi
diff --git a/modules.d/busybox/install-busybox-stage4.sh b/modules.d/busybox/install-busybox-stage4.sh
new file mode 100644
index 00000000..ad34b75c
--- /dev/null
+++ b/modules.d/busybox/install-busybox-stage4.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+if hash busybox; then
+ # check if the stage4 has a busybox in the same location
+ # as within the initramfs. If so, we keep it and just hope
+ # that everything works out. If there is none, we can copy
+ # our busybox there safely
+ bb_path="$(type -p busybox)"
+ if ! [ -x "${NEWROOT}/${bb_path}" ]; then
+ cp -f "$bb_path" "${NEWROOT}/${bb_path}"
+ fi
+ # finally install the applets under /opt/openslx/bin
+ mkdir -p "${NEWROOT}/opt/openslx/bin"
+ busybox --install -s "${NEWROOT}/opt/openslx/bin"
+fi
+true
diff --git a/modules.d/busybox/install-busybox.sh b/modules.d/busybox/install-busybox.sh
new file mode 100644
index 00000000..6848a735
--- /dev/null
+++ b/modules.d/busybox/install-busybox.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+if hash busybox; then
+ busybox --install -s
+else
+ . /lib/dracut-lib.sh
+ emergency_shell "Failed to initialize busybox, things will go wrong..."
+fi
+true
diff --git a/modules.d/busybox/module-setup.sh b/modules.d/busybox/module-setup.sh
new file mode 100644
index 00000000..807022e9
--- /dev/null
+++ b/modules.d/busybox/module-setup.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+[ -z "$BB_GIT" ] && declare -rg BB_GIT="git://git.busybox.net/busybox"
+[ -z "$BB_BRANCH" ] && declare -rg BB_BRANCH="1_25_1"
+
+build() {
+ local base_url="https://git.openslx.org/openslx-ng/mltk.git/plain/core/modules/busybox/"
+ (
+ set -e
+ git clone --depth 1 "$BB_GIT" --branch "$BB_BRANCH" "${moddir}/src"
+ # apply patches
+ cd "${moddir}/src"
+ for _patch in "$base_url"{fbsplash-center,fbsplash-fillbg,rtcwake-compat}.patch ; do
+ curl "$_patch" | git apply - || derror "Failed to apply: $_patch"
+ done
+
+ cp "${moddir}/openslx.config" > "${target}/.config"
+ yes '' | make oldconfig
+ make -j busybox
+ cd - &> /dev/null
+ )
+}
+check() {
+ if [ ! -x "${moddir}/src/busybox" ] && ! build; then
+ derror "Failed to build busybox."
+ return 1
+ fi
+ return 255
+}
+
+depends() {
+ echo ""
+}
+
+install() {
+ if [ ! -s "${moddir}/src/busybox" ]; then
+ derror "Failed to find busybox binary in build directory!"
+ return 1
+ fi
+ inst "${moddir}/src/busybox" "/bin/busybox"
+ inst_hook cmdline 00 "${moddir}/install-busybox.sh"
+ inst_hook pre-pivot 50 "${moddir}/install-busybox-stage4.sh"
+}
diff --git a/modules.d/busybox/openslx.config b/modules.d/busybox/openslx.config
new file mode 100644
index 00000000..177f2fde
--- /dev/null
+++ b/modules.d/busybox/openslx.config
@@ -0,0 +1,1191 @@
+#
+# Automatically generated make config: don't edit
+# Busybox version: 1.31.0
+# Tue Jul 16 16:43:28 2019
+#
+CONFIG_HAVE_DOT_CONFIG=y
+
+#
+# Settings
+#
+# CONFIG_DESKTOP is not set
+# CONFIG_EXTRA_COMPAT is not set
+# CONFIG_FEDORA_COMPAT is not set
+# CONFIG_INCLUDE_SUSv2 is not set
+CONFIG_LONG_OPTS=y
+CONFIG_SHOW_USAGE=y
+# CONFIG_FEATURE_VERBOSE_USAGE is not set
+CONFIG_FEATURE_COMPRESS_USAGE=y
+CONFIG_LFS=y
+# CONFIG_PAM is not set
+CONFIG_FEATURE_DEVPTS=y
+CONFIG_FEATURE_UTMP=y
+# CONFIG_FEATURE_WTMP is not set
+CONFIG_FEATURE_PIDFILE=y
+CONFIG_PID_FILE_PATH="/var/run"
+CONFIG_BUSYBOX=y
+CONFIG_FEATURE_SHOW_SCRIPT=y
+CONFIG_FEATURE_INSTALLER=y
+CONFIG_INSTALL_NO_USR=y
+CONFIG_FEATURE_SUID=y
+# CONFIG_FEATURE_SUID_CONFIG is not set
+# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
+# CONFIG_FEATURE_PREFER_APPLETS is not set
+CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe"
+# CONFIG_SELINUX is not set
+# CONFIG_FEATURE_CLEAN_UP is not set
+CONFIG_FEATURE_SYSLOG_INFO=y
+CONFIG_FEATURE_SYSLOG=y
+CONFIG_PLATFORM_LINUX=y
+
+#
+# Build Options
+#
+# CONFIG_STATIC is not set
+# CONFIG_PIE is not set
+# CONFIG_NOMMU is not set
+# CONFIG_BUILD_LIBBUSYBOX is not set
+# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
+# CONFIG_FEATURE_INDIVIDUAL is not set
+# CONFIG_FEATURE_SHARED_BUSYBOX is not set
+CONFIG_CROSS_COMPILER_PREFIX=""
+CONFIG_SYSROOT=""
+CONFIG_EXTRA_CFLAGS=""
+CONFIG_EXTRA_LDFLAGS=""
+CONFIG_EXTRA_LDLIBS=""
+# CONFIG_USE_PORTABLE_CODE is not set
+CONFIG_STACK_OPTIMIZATION_386=y
+
+#
+# Installation Options ("make install" behavior)
+#
+CONFIG_INSTALL_APPLET_SYMLINKS=y
+# CONFIG_INSTALL_APPLET_HARDLINKS is not set
+# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
+# CONFIG_INSTALL_APPLET_DONT is not set
+# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
+# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
+# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
+CONFIG_PREFIX="./_install"
+
+#
+# Debugging Options
+#
+# CONFIG_DEBUG is not set
+# CONFIG_DEBUG_PESSIMIZE is not set
+# CONFIG_DEBUG_SANITIZE is not set
+# CONFIG_UNIT_TEST is not set
+# CONFIG_WERROR is not set
+CONFIG_NO_DEBUG_LIB=y
+# CONFIG_DMALLOC is not set
+# CONFIG_EFENCE is not set
+
+#
+# Library Tuning
+#
+# CONFIG_FEATURE_USE_BSS_TAIL is not set
+CONFIG_FLOAT_DURATION=y
+CONFIG_FEATURE_RTMINMAX=y
+CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS=y
+CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
+# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
+CONFIG_PASSWORD_MINLEN=6
+CONFIG_MD5_SMALL=1
+CONFIG_SHA3_SMALL=1
+CONFIG_FEATURE_FAST_TOP=y
+# CONFIG_FEATURE_ETC_NETWORKS is not set
+# CONFIG_FEATURE_ETC_SERVICES is not set
+CONFIG_FEATURE_EDITING=y
+CONFIG_FEATURE_EDITING_MAX_LEN=1024
+# CONFIG_FEATURE_EDITING_VI is not set
+CONFIG_FEATURE_EDITING_HISTORY=15
+CONFIG_FEATURE_EDITING_SAVEHISTORY=y
+# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
+CONFIG_FEATURE_REVERSE_SEARCH=y
+CONFIG_FEATURE_TAB_COMPLETION=y
+# CONFIG_FEATURE_USERNAME_COMPLETION is not set
+CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
+CONFIG_FEATURE_EDITING_WINCH=y
+# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
+CONFIG_LOCALE_SUPPORT=y
+CONFIG_UNICODE_SUPPORT=y
+# CONFIG_UNICODE_USING_LOCALE is not set
+CONFIG_FEATURE_CHECK_UNICODE_IN_ENV=y
+CONFIG_SUBST_WCHAR=63
+CONFIG_LAST_SUPPORTED_WCHAR=767
+# CONFIG_UNICODE_COMBINING_WCHARS is not set
+# CONFIG_UNICODE_WIDE_WCHARS is not set
+# CONFIG_UNICODE_BIDI_SUPPORT is not set
+# CONFIG_UNICODE_NEUTRAL_TABLE is not set
+# CONFIG_UNICODE_PRESERVE_BROKEN is not set
+CONFIG_FEATURE_NON_POSIX_CP=y
+CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y
+CONFIG_FEATURE_USE_SENDFILE=y
+CONFIG_FEATURE_COPYBUF_KB=4
+CONFIG_FEATURE_SKIP_ROOTFS=y
+CONFIG_MONOTONIC_SYSCALL=y
+CONFIG_IOCTL_HEX2STR_ERROR=y
+# CONFIG_FEATURE_HWIB is not set
+
+#
+# Applets
+#
+
+#
+# Archival Utilities
+#
+CONFIG_FEATURE_SEAMLESS_XZ=y
+CONFIG_FEATURE_SEAMLESS_LZMA=y
+CONFIG_FEATURE_SEAMLESS_BZ2=y
+CONFIG_FEATURE_SEAMLESS_GZ=y
+CONFIG_FEATURE_SEAMLESS_Z=y
+CONFIG_AR=y
+# CONFIG_FEATURE_AR_LONG_FILENAMES is not set
+CONFIG_FEATURE_AR_CREATE=y
+# CONFIG_UNCOMPRESS is not set
+CONFIG_GUNZIP=y
+CONFIG_ZCAT=y
+CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
+CONFIG_BUNZIP2=y
+CONFIG_BZCAT=y
+CONFIG_UNLZMA=y
+CONFIG_LZCAT=y
+CONFIG_LZMA=y
+CONFIG_UNXZ=y
+CONFIG_XZCAT=y
+CONFIG_XZ=y
+CONFIG_BZIP2=y
+CONFIG_BZIP2_SMALL=8
+CONFIG_FEATURE_BZIP2_DECOMPRESS=y
+CONFIG_CPIO=y
+# CONFIG_FEATURE_CPIO_O is not set
+# CONFIG_FEATURE_CPIO_P is not set
+# CONFIG_DPKG is not set
+# CONFIG_DPKG_DEB is not set
+CONFIG_GZIP=y
+# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set
+CONFIG_GZIP_FAST=0
+# CONFIG_FEATURE_GZIP_LEVELS is not set
+CONFIG_FEATURE_GZIP_DECOMPRESS=y
+# CONFIG_LZOP is not set
+# CONFIG_UNLZOP is not set
+# CONFIG_LZOPCAT is not set
+# CONFIG_LZOP_COMPR_HIGH is not set
+# CONFIG_RPM is not set
+CONFIG_RPM2CPIO=y
+CONFIG_TAR=y
+CONFIG_FEATURE_TAR_LONG_OPTIONS=y
+CONFIG_FEATURE_TAR_CREATE=y
+CONFIG_FEATURE_TAR_AUTODETECT=y
+CONFIG_FEATURE_TAR_FROM=y
+# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set
+# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
+CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
+# CONFIG_FEATURE_TAR_TO_COMMAND is not set
+# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
+CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
+# CONFIG_FEATURE_TAR_SELINUX is not set
+# CONFIG_UNZIP is not set
+# CONFIG_FEATURE_UNZIP_CDF is not set
+# CONFIG_FEATURE_UNZIP_BZIP2 is not set
+# CONFIG_FEATURE_UNZIP_LZMA is not set
+# CONFIG_FEATURE_UNZIP_XZ is not set
+# CONFIG_FEATURE_LZMA_FAST is not set
+
+#
+# Coreutils
+#
+CONFIG_BASENAME=y
+CONFIG_CAT=y
+CONFIG_FEATURE_CATN=y
+CONFIG_FEATURE_CATV=y
+CONFIG_CHGRP=y
+CONFIG_CHMOD=y
+CONFIG_CHOWN=y
+CONFIG_FEATURE_CHOWN_LONG_OPTIONS
+CONFIG_CHROOT=y
+# CONFIG_CKSUM is not set
+# CONFIG_COMM is not set
+CONFIG_CP=y
+CONFIG_FEATURE_CP_LONG_OPTIONS=y
+# CONFIG_FEATURE_CP_REFLINK is not set
+CONFIG_CUT=y
+CONFIG_DATE=y
+CONFIG_FEATURE_DATE_ISOFMT=y
+CONFIG_FEATURE_DATE_NANO=y
+CONFIG_FEATURE_DATE_COMPAT=y
+CONFIG_DD=y
+CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
+# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
+# CONFIG_FEATURE_DD_IBS_OBS is not set
+CONFIG_FEATURE_DD_STATUS=y
+CONFIG_DF=y
+# CONFIG_FEATURE_DF_FANCY is not set
+CONFIG_DIRNAME=y
+# CONFIG_DOS2UNIX is not set
+# CONFIG_UNIX2DOS is not set
+CONFIG_DU=y
+CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
+CONFIG_ECHO=y
+CONFIG_FEATURE_FANCY_ECHO=y
+CONFIG_ENV=y
+# CONFIG_EXPAND is not set
+# CONFIG_UNEXPAND is not set
+CONFIG_EXPR=y
+CONFIG_EXPR_MATH_SUPPORT_64=y
+CONFIG_FACTOR=y
+CONFIG_FALSE=y
+# CONFIG_FOLD is not set
+CONFIG_HEAD=y
+# CONFIG_FEATURE_FANCY_HEAD is not set
+# CONFIG_HOSTID is not set
+CONFIG_ID=y
+CONFIG_GROUPS=y
+# CONFIG_INSTALL is not set
+# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
+CONFIG_LINK=y
+CONFIG_LN=y
+# CONFIG_LOGNAME is not set
+CONFIG_LS=y
+CONFIG_FEATURE_LS_FILETYPES=y
+CONFIG_FEATURE_LS_FOLLOWLINKS=y
+CONFIG_FEATURE_LS_RECURSIVE=y
+CONFIG_FEATURE_LS_WIDTH=y
+CONFIG_FEATURE_LS_SORTFILES=y
+CONFIG_FEATURE_LS_TIMESTAMPS=y
+CONFIG_FEATURE_LS_USERNAME=y
+CONFIG_FEATURE_LS_COLOR=y
+# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
+CONFIG_MD5SUM=y
+# CONFIG_SHA1SUM is not set
+CONFIG_SHA256SUM=y
+# CONFIG_SHA512SUM is not set
+# CONFIG_SHA3SUM is not set
+
+#
+# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
+#
+CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
+CONFIG_MKDIR=y
+CONFIG_MKFIFO=y
+CONFIG_MKNOD=y
+CONFIG_MKTEMP=y
+CONFIG_MV=y
+CONFIG_NICE=y
+CONFIG_NL=y
+# CONFIG_NOHUP is not set
+CONFIG_NPROC=y
+# CONFIG_OD is not set
+CONFIG_PASTE=y
+# CONFIG_PRINTENV is not set
+CONFIG_PRINTF=y
+CONFIG_PWD=y
+CONFIG_READLINK=y
+CONFIG_FEATURE_READLINK_FOLLOW=y
+CONFIG_REALPATH=y
+CONFIG_RM=y
+CONFIG_RMDIR=y
+# CONFIG_SEQ is not set
+CONFIG_SHRED=y
+CONFIG_SHUF=y
+CONFIG_SLEEP=y
+# CONFIG_FEATURE_FANCY_SLEEP is not set
+CONFIG_SORT=y
+CONFIG_FEATURE_SORT_BIG=y
+# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set
+# CONFIG_SPLIT is not set
+# CONFIG_FEATURE_SPLIT_FANCY is not set
+CONFIG_STAT=y
+CONFIG_FEATURE_STAT_FORMAT=y
+CONFIG_FEATURE_STAT_FILESYSTEM=y
+# CONFIG_STTY is not set
+# CONFIG_SUM is not set
+CONFIG_SYNC=y
+CONFIG_FEATURE_SYNC_FANCY=y
+# CONFIG_FSYNC is not set
+# CONFIG_TAC is not set
+CONFIG_TAIL=y
+CONFIG_FEATURE_FANCY_TAIL=y
+CONFIG_TEE=y
+# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set
+CONFIG_TEST=y
+CONFIG_TEST1=y
+CONFIG_TEST2=y
+# CONFIG_FEATURE_TEST_64 is not set
+CONFIG_TIMEOUT=y
+CONFIG_TOUCH=y
+CONFIG_FEATURE_TOUCH_NODEREF=y
+CONFIG_FEATURE_TOUCH_SUSV3=y
+CONFIG_TR=y
+# CONFIG_FEATURE_TR_CLASSES is not set
+# CONFIG_FEATURE_TR_EQUIV is not set
+CONFIG_TRUE=y
+CONFIG_TRUNCATE=y
+# CONFIG_TTY is not set
+CONFIG_UNAME=y
+CONFIG_UNAME_OSNAME="GNU/Linux"
+CONFIG_BB_ARCH=y
+CONFIG_UNIQ=y
+CONFIG_UNLINK=y
+CONFIG_USLEEP=y
+# CONFIG_UUDECODE is not set
+CONFIG_BASE64=y
+# CONFIG_UUENCODE is not set
+CONFIG_WC=y
+# CONFIG_FEATURE_WC_LARGE is not set
+CONFIG_WHOAMI=y
+CONFIG_WHO=y
+CONFIG_W=y
+# CONFIG_USERS is not set
+# CONFIG_YES is not set
+
+#
+# Common options
+#
+CONFIG_FEATURE_VERBOSE=y
+
+#
+# Common options for cp and mv
+#
+CONFIG_FEATURE_PRESERVE_HARDLINKS=y
+
+#
+# Common options for df, du, ls
+#
+CONFIG_FEATURE_HUMAN_READABLE=y
+
+#
+# Console Utilities
+#
+CONFIG_CHVT=y
+CONFIG_CLEAR=y
+CONFIG_DEALLOCVT=y
+CONFIG_DUMPKMAP=y
+CONFIG_FGCONSOLE=y
+# CONFIG_KBD_MODE is not set
+CONFIG_LOADFONT=y
+CONFIG_SETFONT=y
+CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y
+CONFIG_DEFAULT_SETFONT_DIR=""
+
+#
+# Common options for loadfont and setfont
+#
+CONFIG_FEATURE_LOADFONT_PSF2=y
+CONFIG_FEATURE_LOADFONT_RAW=y
+CONFIG_LOADKMAP=y
+CONFIG_OPENVT=y
+CONFIG_RESET=y
+CONFIG_RESIZE=y
+CONFIG_FEATURE_RESIZE_PRINT=y
+CONFIG_SETCONSOLE=y
+CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y
+CONFIG_SETKEYCODES=y
+CONFIG_SETLOGCONS=y
+# CONFIG_SHOWKEY is not set
+
+#
+# Debian Utilities
+#
+# CONFIG_PIPE_PROGRESS is not set
+# CONFIG_RUN_PARTS is not set
+# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
+# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
+# CONFIG_START_STOP_DAEMON is not set
+# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
+# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
+CONFIG_WHICH=y
+
+#
+# klibc-utils
+#
+# CONFIG_MINIPS is not set
+CONFIG_NUKE=y
+CONFIG_RESUME=y
+CONFIG_RUN_INIT=y
+
+#
+# Editors
+#
+CONFIG_AWK=y
+# CONFIG_FEATURE_AWK_LIBM is not set
+CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
+# CONFIG_CMP is not set
+CONFIG_DIFF=y
+CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
+CONFIG_FEATURE_DIFF_DIR=y
+# CONFIG_ED is not set
+# CONFIG_PATCH is not set
+CONFIG_SED=y
+CONFIG_VI=y
+CONFIG_FEATURE_VI_MAX_LEN=1024
+CONFIG_FEATURE_VI_8BIT=y
+CONFIG_FEATURE_VI_COLON=y
+CONFIG_FEATURE_VI_YANKMARK=y
+CONFIG_FEATURE_VI_SEARCH=y
+CONFIG_FEATURE_VI_REGEX_SEARCH=y
+CONFIG_FEATURE_VI_USE_SIGNALS=y
+CONFIG_FEATURE_VI_DOT_CMD=y
+CONFIG_FEATURE_VI_READONLY=y
+CONFIG_FEATURE_VI_SETOPTS=y
+CONFIG_FEATURE_VI_SET=y
+CONFIG_FEATURE_VI_WIN_RESIZE=y
+CONFIG_FEATURE_VI_ASK_TERMINAL=y
+CONFIG_FEATURE_VI_UNDO=y
+CONFIG_FEATURE_VI_UNDO_QUEUE=y
+CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
+# CONFIG_FEATURE_ALLOW_EXEC is not set
+
+#
+# Finding Utilities
+#
+CONFIG_FIND=y
+CONFIG_FEATURE_FIND_PRINT0=y
+CONFIG_FEATURE_FIND_MTIME=y
+CONFIG_FEATURE_FIND_MMIN=y
+CONFIG_FEATURE_FIND_PERM=y
+CONFIG_FEATURE_FIND_TYPE=y
+CONFIG_FEATURE_FIND_EXECUTABLE=y
+CONFIG_FEATURE_FIND_XDEV=y
+CONFIG_FEATURE_FIND_MAXDEPTH=y
+CONFIG_FEATURE_FIND_NEWER=y
+CONFIG_FEATURE_FIND_INUM=y
+CONFIG_FEATURE_FIND_EXEC=y
+CONFIG_FEATURE_FIND_EXEC_PLUS=y
+CONFIG_FEATURE_FIND_USER=y
+CONFIG_FEATURE_FIND_GROUP=y
+CONFIG_FEATURE_FIND_NOT=y
+CONFIG_FEATURE_FIND_DEPTH=y
+CONFIG_FEATURE_FIND_PAREN=y
+CONFIG_FEATURE_FIND_SIZE=y
+CONFIG_FEATURE_FIND_PRUNE=y
+CONFIG_FEATURE_FIND_QUIT=y
+CONFIG_FEATURE_FIND_DELETE=y
+CONFIG_FEATURE_FIND_PATH=y
+CONFIG_FEATURE_FIND_REGEX=y
+# CONFIG_FEATURE_FIND_CONTEXT is not set
+# CONFIG_FEATURE_FIND_LINKS is not set
+CONFIG_GREP=y
+CONFIG_EGREP=y
+CONFIG_FGREP=y
+CONFIG_FEATURE_GREP_CONTEXT=y
+CONFIG_XARGS=y
+# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set
+CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
+CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y
+CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y
+
+#
+# Init Utilities
+#
+# CONFIG_BOOTCHARTD is not set
+# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
+# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
+CONFIG_HALT=y
+CONFIG_POWEROFF=y
+CONFIG_REBOOT=y
+CONFIG_FEATURE_WAIT_FOR_INIT=y
+CONFIG_FEATURE_CALL_TELINIT=y
+CONFIG_TELINIT_PATH="/sbin/telinit"
+# CONFIG_INIT is not set
+CONFIG_LINUXRC=y
+# CONFIG_FEATURE_USE_INITTAB is not set
+# CONFIG_FEATURE_KILL_REMOVED is not set
+CONFIG_FEATURE_KILL_DELAY=0
+# CONFIG_FEATURE_INIT_SCTTY is not set
+# CONFIG_FEATURE_INIT_SYSLOG is not set
+CONFIG_FEATURE_INIT_QUIET=y
+# CONFIG_FEATURE_INIT_COREDUMPS is not set
+CONFIG_INIT_TERMINAL_TYPE=""
+CONFIG_FEATURE_INIT_MODIFY_CMDLINE=y
+
+#
+# Login/Password Management Utilities
+#
+CONFIG_FEATURE_SHADOWPASSWDS=y
+# CONFIG_USE_BB_PWD_GRP is not set
+# CONFIG_USE_BB_SHADOW is not set
+CONFIG_USE_BB_CRYPT=y
+CONFIG_USE_BB_CRYPT_SHA=y
+CONFIG_ADDGROUP=y
+CONFIG_FEATURE_ADDUSER_TO_GROUP=y
+# CONFIG_ADD_SHELL is not set
+# CONFIG_REMOVE_SHELL is not set
+CONFIG_ADDUSER=y
+# CONFIG_FEATURE_CHECK_NAMES is not set
+CONFIG_LAST_ID=60000
+CONFIG_FIRST_SYSTEM_ID=100
+CONFIG_LAST_SYSTEM_ID=999
+# CONFIG_CHPASSWD is not set
+CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="des"
+# CONFIG_CRYPTPW is not set
+CONFIG_MKPASSWD=y
+# CONFIG_DELUSER is not set
+# CONFIG_DELGROUP is not set
+# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
+CONFIG_GETTY=y
+# CONFIG_LOGIN is not set
+# CONFIG_LOGIN_SESSION_AS_CHILD is not set
+# CONFIG_LOGIN_SCRIPTS is not set
+# CONFIG_FEATURE_NOLOGIN is not set
+# CONFIG_FEATURE_SECURETTY is not set
+CONFIG_PASSWD=y
+CONFIG_FEATURE_PASSWD_WEAK_CHECK=y
+CONFIG_SU=y
+CONFIG_FEATURE_SU_SYSLOG=y
+CONFIG_FEATURE_SU_CHECKS_SHELLS=y
+# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
+# CONFIG_SULOGIN is not set
+# CONFIG_VLOCK is not set
+
+#
+# Linux Ext2 FS Progs
+#
+# CONFIG_CHATTR is not set
+# CONFIG_FSCK is not set
+# CONFIG_LSATTR is not set
+# CONFIG_TUNE2FS is not set
+
+#
+# Linux Module Utilities
+#
+# CONFIG_MODPROBE_SMALL is not set
+# CONFIG_DEPMOD is not set
+CONFIG_INSMOD=y
+CONFIG_LSMOD=y
+# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
+CONFIG_MODINFO=y
+CONFIG_MODPROBE=y
+CONFIG_FEATURE_MODPROBE_BLACKLIST=y
+CONFIG_RMMOD=y
+
+#
+# Options common to multiple modutils
+#
+CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS=y
+# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
+# CONFIG_FEATURE_2_4_MODULES is not set
+# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
+# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
+# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
+CONFIG_FEATURE_CHECK_TAINTED_MODULE=y
+# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
+CONFIG_FEATURE_MODUTILS_ALIAS=y
+CONFIG_FEATURE_MODUTILS_SYMBOLS=y
+CONFIG_DEFAULT_MODULES_DIR="/lib/modules"
+CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
+
+#
+# Linux System Utilities
+#
+# CONFIG_ACPID is not set
+# CONFIG_FEATURE_ACPID_COMPAT is not set
+CONFIG_BLKDISCARD=y
+CONFIG_BLKID=y
+# CONFIG_FEATURE_BLKID_TYPE is not set
+CONFIG_BLOCKDEV=y
+# CONFIG_CAL is not set
+# CONFIG_CHRT is not set
+CONFIG_DMESG=y
+CONFIG_FEATURE_DMESG_PRETTY=y
+CONFIG_EJECT=y
+CONFIG_FEATURE_EJECT_SCSI=y
+CONFIG_FALLOCATE=y
+CONFIG_FATATTR=y
+CONFIG_FBSET=y
+CONFIG_FEATURE_FBSET_FANCY=y
+# CONFIG_FEATURE_FBSET_READMODE is not set
+# CONFIG_FDFORMAT is not set
+CONFIG_FDISK=y
+# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
+CONFIG_FEATURE_FDISK_WRITABLE=y
+# CONFIG_FEATURE_AIX_LABEL is not set
+# CONFIG_FEATURE_SGI_LABEL is not set
+# CONFIG_FEATURE_SUN_LABEL is not set
+# CONFIG_FEATURE_OSF_LABEL is not set
+CONFIG_FEATURE_GPT_LABEL=y
+# CONFIG_FEATURE_FDISK_ADVANCED is not set
+# CONFIG_FINDFS is not set
+CONFIG_FLOCK=y
+# CONFIG_FDFLUSH is not set
+# CONFIG_FREERAMDISK is not set
+# CONFIG_FSCK_MINIX is not set
+CONFIG_FSFREEZE=y
+# CONFIG_FSTRIM is not set
+# CONFIG_GETOPT is not set
+# CONFIG_FEATURE_GETOPT_LONG is not set
+# CONFIG_HEXDUMP is not set
+# CONFIG_FEATURE_HEXDUMP_REVERSE is not set
+# CONFIG_HD is not set
+CONFIG_XXD=y
+CONFIG_HWCLOCK=y
+CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS=y
+# CONFIG_IONICE is not set
+# CONFIG_IPCRM is not set
+# CONFIG_IPCS is not set
+# CONFIG_LAST is not set
+# CONFIG_FEATURE_LAST_FANCY is not set
+# CONFIG_LOSETUP is not set
+CONFIG_LSPCI=y
+CONFIG_LSUSB=y
+# CONFIG_MDEV is not set
+# CONFIG_FEATURE_MDEV_CONF is not set
+# CONFIG_FEATURE_MDEV_RENAME is not set
+# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
+# CONFIG_FEATURE_MDEV_EXEC is not set
+# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
+# CONFIG_FEATURE_MDEV_DAEMON is not set
+# CONFIG_MESG is not set
+# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
+CONFIG_MKE2FS=y
+CONFIG_MKFS_EXT2=y
+# CONFIG_MKFS_MINIX is not set
+# CONFIG_FEATURE_MINIX2 is not set
+# CONFIG_MKFS_REISER is not set
+CONFIG_MKDOSFS=y
+CONFIG_MKFS_VFAT=y
+CONFIG_MKSWAP=y
+# CONFIG_FEATURE_MKSWAP_UUID is not set
+CONFIG_MORE=y
+CONFIG_MOUNT=y
+# CONFIG_FEATURE_MOUNT_FAKE is not set
+# CONFIG_FEATURE_MOUNT_VERBOSE is not set
+CONFIG_FEATURE_MOUNT_HELPERS=y
+# CONFIG_FEATURE_MOUNT_LABEL is not set
+CONFIG_FEATURE_MOUNT_NFS=y
+CONFIG_FEATURE_MOUNT_CIFS=y
+CONFIG_FEATURE_MOUNT_FLAGS=y
+CONFIG_FEATURE_MOUNT_FSTAB=y
+CONFIG_FEATURE_MOUNT_OTHERTAB=y
+# CONFIG_MOUNTPOINT is not set
+CONFIG_NOLOGIN=y
+CONFIG_NOLOGIN_DEPENDENCIES=y
+CONFIG_NSENTER=y
+# CONFIG_PIVOT_ROOT is not set
+CONFIG_RDATE=y
+# CONFIG_RDEV is not set
+# CONFIG_READPROFILE is not set
+# CONFIG_RENICE is not set
+# CONFIG_REV is not set
+CONFIG_RTCWAKE=y
+# CONFIG_SCRIPT is not set
+# CONFIG_SCRIPTREPLAY is not set
+# CONFIG_SETARCH is not set
+CONFIG_LINUX32=y
+CONFIG_LINUX64=y
+CONFIG_SETPRIV=y
+CONFIG_FEATURE_SETPRIV_DUMP=y
+CONFIG_FEATURE_SETPRIV_CAPABILITIES=y
+CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES=y
+CONFIG_SETSID=y
+CONFIG_SWAPON=y
+CONFIG_FEATURE_SWAPON_DISCARD=y
+CONFIG_FEATURE_SWAPON_PRI=y
+CONFIG_SWAPOFF=y
+CONFIG_FEATURE_SWAPONOFF_LABEL=y
+CONFIG_SWITCH_ROOT=y
+# CONFIG_TASKSET is not set
+# CONFIG_FEATURE_TASKSET_FANCY is not set
+CONFIG_UEVENT=y
+CONFIG_UMOUNT=y
+# CONFIG_FEATURE_UMOUNT_ALL is not set
+CONFIG_UNSHARE=y
+# CONFIG_WALL is not set
+
+#
+# Common options for mount/umount
+#
+CONFIG_FEATURE_MOUNT_LOOP=y
+CONFIG_FEATURE_MOUNT_LOOP_CREATE=y
+# CONFIG_FEATURE_MTAB_SUPPORT is not set
+CONFIG_VOLUMEID=y
+
+#
+# Filesystem/Volume identification
+#
+CONFIG_FEATURE_VOLUMEID_BCACHE=y
+CONFIG_FEATURE_VOLUMEID_BTRFS=y
+CONFIG_FEATURE_VOLUMEID_CRAMFS=y
+CONFIG_FEATURE_VOLUMEID_EXFAT=y
+CONFIG_FEATURE_VOLUMEID_EXT=y
+CONFIG_FEATURE_VOLUMEID_F2FS=y
+CONFIG_FEATURE_VOLUMEID_FAT=y
+CONFIG_FEATURE_VOLUMEID_HFS=y
+CONFIG_FEATURE_VOLUMEID_ISO9660=y
+CONFIG_FEATURE_VOLUMEID_JFS=y
+# CONFIG_FEATURE_VOLUMEID_LFS is not set
+CONFIG_FEATURE_VOLUMEID_LINUXRAID=y
+CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y
+CONFIG_FEATURE_VOLUMEID_LUKS=y
+CONFIG_FEATURE_VOLUMEID_MINIX=y
+CONFIG_FEATURE_VOLUMEID_NILFS=y
+CONFIG_FEATURE_VOLUMEID_NTFS=y
+CONFIG_FEATURE_VOLUMEID_OCFS2=y
+CONFIG_FEATURE_VOLUMEID_REISERFS=y
+CONFIG_FEATURE_VOLUMEID_ROMFS=y
+# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
+CONFIG_FEATURE_VOLUMEID_SYSV=y
+CONFIG_FEATURE_VOLUMEID_UBIFS=y
+CONFIG_FEATURE_VOLUMEID_UDF=y
+CONFIG_FEATURE_VOLUMEID_XFS=y
+
+#
+# Miscellaneous Utilities
+#
+# CONFIG_ADJTIMEX is not set
+# CONFIG_BBCONFIG is not set
+# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
+CONFIG_BC=y
+# CONFIG_DC is not set
+CONFIG_FEATURE_DC_BIG=y
+# CONFIG_FEATURE_DC_LIBM is not set
+CONFIG_FEATURE_BC_INTERACTIVE=y
+CONFIG_FEATURE_BC_LONG_OPTIONS=y
+# CONFIG_BEEP is not set
+CONFIG_FEATURE_BEEP_FREQ=0
+CONFIG_FEATURE_BEEP_LENGTH_MS=0
+# CONFIG_CHAT is not set
+# CONFIG_FEATURE_CHAT_NOFAIL is not set
+# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
+# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
+# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
+# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
+# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
+# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
+# CONFIG_CONSPY is not set
+# CONFIG_CROND is not set
+# CONFIG_FEATURE_CROND_D is not set
+# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
+# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
+CONFIG_FEATURE_CROND_DIR=""
+# CONFIG_CRONTAB is not set
+# CONFIG_DEVFSD is not set
+# CONFIG_DEVFSD_MODLOAD is not set
+# CONFIG_DEVFSD_FG_NP is not set
+# CONFIG_DEVFSD_VERBOSE is not set
+# CONFIG_FEATURE_DEVFS is not set
+# CONFIG_DEVMEM is not set
+CONFIG_FBSPLASH=y
+# CONFIG_FLASHCP is not set
+# CONFIG_FLASH_ERASEALL is not set
+# CONFIG_FLASH_LOCK is not set
+# CONFIG_FLASH_UNLOCK is not set
+CONFIG_HDPARM=y
+CONFIG_FEATURE_HDPARM_GET_IDENTITY=y
+CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y
+CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y
+CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y
+CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y
+CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y
+CONFIG_HEXEDIT=y
+CONFIG_I2CGET=y
+CONFIG_I2CSET=y
+CONFIG_I2CDUMP=y
+CONFIG_I2CDETECT=y
+CONFIG_I2CTRANSFER=y
+CONFIG_INOTIFYD=y
+# CONFIG_LESS is not set
+CONFIG_FEATURE_LESS_MAXLINES=0
+# CONFIG_FEATURE_LESS_BRACKETS is not set
+# CONFIG_FEATURE_LESS_FLAGS is not set
+# CONFIG_FEATURE_LESS_TRUNCATE is not set
+# CONFIG_FEATURE_LESS_MARKS is not set
+# CONFIG_FEATURE_LESS_REGEXP is not set
+# CONFIG_FEATURE_LESS_WINCH is not set
+# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
+# CONFIG_FEATURE_LESS_DASHCMD is not set
+# CONFIG_FEATURE_LESS_LINENUMS is not set
+# CONFIG_FEATURE_LESS_RAW is not set
+# CONFIG_FEATURE_LESS_ENV is not set
+CONFIG_LSSCSI=y
+# CONFIG_MAKEDEVS is not set
+# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
+# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
+# CONFIG_MAN is not set
+# CONFIG_MICROCOM is not set
+# CONFIG_MT is not set
+# CONFIG_NANDWRITE is not set
+# CONFIG_NANDDUMP is not set
+CONFIG_PARTPROBE=y
+# CONFIG_RAIDAUTORUN is not set
+CONFIG_READAHEAD=y
+# CONFIG_RFKILL is not set
+# CONFIG_RUNLEVEL is not set
+# CONFIG_RX is not set
+CONFIG_SETFATTR=y
+CONFIG_SETSERIAL=y
+CONFIG_STRINGS=y
+CONFIG_TIME=y
+CONFIG_TS=y
+CONFIG_TTYSIZE=y
+CONFIG_UBIRENAME=y
+# CONFIG_UBIATTACH is not set
+# CONFIG_UBIDETACH is not set
+CONFIG_UBIMKVOL=y
+CONFIG_UBIRMVOL=y
+CONFIG_UBIRSVOL=y
+CONFIG_UBIUPDATEVOL=y
+# CONFIG_VOLNAME is not set
+CONFIG_WATCHDOG=y
+
+#
+# Networking Utilities
+#
+CONFIG_FEATURE_IPV6=y
+# CONFIG_FEATURE_UNIX_LOCAL is not set
+# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set
+# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
+# CONFIG_FEATURE_TLS_SHA1 is not set
+CONFIG_ARP=y
+CONFIG_ARPING=y
+CONFIG_BRCTL=y
+CONFIG_FEATURE_BRCTL_FANCY=y
+CONFIG_FEATURE_BRCTL_SHOW=y
+# CONFIG_DNSD is not set
+# CONFIG_ETHER_WAKE is not set
+# CONFIG_FTPD is not set
+# CONFIG_FEATURE_FTPD_WRITE is not set
+# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
+# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
+CONFIG_FTPGET=y
+CONFIG_FTPPUT=y
+# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
+CONFIG_HOSTNAME=y
+CONFIG_DNSDOMAINNAME=y
+# CONFIG_HTTPD is not set
+# CONFIG_FEATURE_HTTPD_RANGES is not set
+# CONFIG_FEATURE_HTTPD_SETUID is not set
+# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
+# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
+# CONFIG_FEATURE_HTTPD_CGI is not set
+# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
+# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
+# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
+# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
+# CONFIG_FEATURE_HTTPD_PROXY is not set
+# CONFIG_FEATURE_HTTPD_GZIP is not set
+# CONFIG_IFCONFIG is not set
+# CONFIG_FEATURE_IFCONFIG_STATUS is not set
+# CONFIG_FEATURE_IFCONFIG_SLIP is not set
+# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
+# CONFIG_FEATURE_IFCONFIG_HW is not set
+# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
+# CONFIG_IFENSLAVE is not set
+# CONFIG_IFPLUGD is not set
+CONFIG_IFUP=y
+CONFIG_IFDOWN=y
+CONFIG_IFUPDOWN_IFSTATE_PATH=""
+# CONFIG_FEATURE_IFUPDOWN_IP is not set
+# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
+# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
+# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
+# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
+# CONFIG_INETD is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
+# CONFIG_FEATURE_INETD_RPC is not set
+CONFIG_IP=y
+# CONFIG_IPADDR is not set
+# CONFIG_IPLINK is not set
+# CONFIG_IPROUTE is not set
+# CONFIG_IPTUNNEL is not set
+# CONFIG_IPRULE is not set
+CONFIG_IPNEIGH=y
+CONFIG_FEATURE_IP_ADDRESS=y
+CONFIG_FEATURE_IP_LINK=y
+CONFIG_FEATURE_IP_ROUTE=y
+CONFIG_FEATURE_IP_ROUTE_DIR="/etc/iproute2"
+CONFIG_FEATURE_IP_TUNNEL=y
+# CONFIG_FEATURE_IP_RULE is not set
+CONFIG_FEATURE_IP_NEIGH=y
+# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
+CONFIG_IPCALC=y
+CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
+CONFIG_FEATURE_IPCALC_FANCY=y
+# CONFIG_FAKEIDENTD is not set
+# CONFIG_NAMEIF is not set
+# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
+CONFIG_NBDCLIENT=y
+CONFIG_NC=y
+# CONFIG_NETCAT is not set
+# CONFIG_NC_SERVER is not set
+# CONFIG_NC_EXTRA is not set
+# CONFIG_NC_110_COMPAT is not set
+CONFIG_NETSTAT=y
+CONFIG_FEATURE_NETSTAT_WIDE=y
+CONFIG_FEATURE_NETSTAT_PRG=y
+CONFIG_NSLOOKUP=y
+CONFIG_FEATURE_NSLOOKUP_BIG=y
+CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS=y
+# CONFIG_NTPD is not set
+# CONFIG_FEATURE_NTPD_SERVER is not set
+# CONFIG_FEATURE_NTPD_CONF is not set
+# CONFIG_FEATURE_NTP_AUTH is not set
+CONFIG_PING=y
+CONFIG_PING6=y
+CONFIG_FEATURE_FANCY_PING=y
+# CONFIG_PSCAN is not set
+CONFIG_ROUTE=y
+# CONFIG_SLATTACH is not set
+CONFIG_SSL_CLIENT=y
+CONFIG_TC=y
+CONFIG_FEATURE_TC_INGRESS=y
+CONFIG_TCPSVD=y
+# CONFIG_UDPSVD is not set
+CONFIG_TELNET=y
+CONFIG_FEATURE_TELNET_TTYPE=y
+CONFIG_FEATURE_TELNET_AUTOLOGIN=y
+CONFIG_FEATURE_TELNET_WIDTH=y
+# CONFIG_TELNETD is not set
+# CONFIG_FEATURE_TELNETD_STANDALONE is not set
+# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
+CONFIG_TFTP=y
+# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
+CONFIG_FEATURE_TFTP_HPA_COMPAT=y
+# CONFIG_TFTPD is not set
+CONFIG_FEATURE_TFTP_GET=y
+# CONFIG_FEATURE_TFTP_PUT is not set
+# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
+# CONFIG_TFTP_DEBUG is not set
+CONFIG_TLS=y
+# CONFIG_TRACEROUTE is not set
+# CONFIG_TRACEROUTE6 is not set
+# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
+# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
+CONFIG_TUNCTL=y
+CONFIG_FEATURE_TUNCTL_UG=y
+CONFIG_VCONFIG=y
+CONFIG_WGET=y
+CONFIG_FEATURE_WGET_LONG_OPTIONS=y
+CONFIG_FEATURE_WGET_STATUSBAR=y
+CONFIG_FEATURE_WGET_AUTHENTICATION=y
+CONFIG_FEATURE_WGET_TIMEOUT=y
+CONFIG_FEATURE_WGET_HTTPS=y
+CONFIG_FEATURE_WGET_OPENSSL=y
+CONFIG_WHOIS=y
+CONFIG_ZCIP=y
+CONFIG_UDHCPD=y
+# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
+CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y
+CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases"
+CONFIG_DUMPLEASES=y
+CONFIG_DHCPRELAY=y
+CONFIG_UDHCPC=y
+CONFIG_FEATURE_UDHCPC_ARPING=y
+CONFIG_FEATURE_UDHCPC_SANITIZEOPT=y
+CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"
+# CONFIG_UDHCPC6 is not set
+# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
+# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
+# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
+# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
+
+#
+# Common options for DHCP applets
+#
+# CONFIG_FEATURE_UDHCP_PORT is not set
+CONFIG_UDHCP_DEBUG=0
+CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80
+CONFIG_FEATURE_UDHCP_RFC3397=y
+CONFIG_FEATURE_UDHCP_8021Q=y
+CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
+
+#
+# Print Utilities
+#
+CONFIG_LPD=y
+CONFIG_LPR=y
+CONFIG_LPQ=y
+
+#
+# Mail Utilities
+#
+# CONFIG_MAKEMIME is not set
+# CONFIG_POPMAILDIR is not set
+# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
+# CONFIG_REFORMIME is not set
+# CONFIG_FEATURE_REFORMIME_COMPAT is not set
+# CONFIG_SENDMAIL is not set
+CONFIG_FEATURE_MIME_CHARSET=""
+
+#
+# Process Utilities
+#
+CONFIG_FREE=y
+CONFIG_FUSER=y
+CONFIG_IOSTAT=y
+CONFIG_KILL=y
+CONFIG_KILLALL=y
+# CONFIG_KILLALL5 is not set
+CONFIG_LSOF=y
+CONFIG_MPSTAT=y
+CONFIG_NMETER=y
+# CONFIG_PGREP is not set
+# CONFIG_PKILL is not set
+CONFIG_PIDOF=y
+# CONFIG_FEATURE_PIDOF_SINGLE is not set
+# CONFIG_FEATURE_PIDOF_OMIT is not set
+CONFIG_PMAP=y
+CONFIG_POWERTOP=y
+CONFIG_FEATURE_POWERTOP_INTERACTIVE=y
+CONFIG_PS=y
+CONFIG_FEATURE_PS_WIDE=y
+CONFIG_FEATURE_PS_LONG=y
+# CONFIG_FEATURE_PS_TIME is not set
+# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
+# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
+CONFIG_PSTREE=y
+CONFIG_PWDX=y
+CONFIG_SMEMCAP=y
+CONFIG_BB_SYSCTL=y
+CONFIG_TOP=y
+CONFIG_FEATURE_TOP_INTERACTIVE=y
+CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
+CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
+CONFIG_FEATURE_TOP_SMP_CPU=y
+CONFIG_FEATURE_TOP_DECIMALS=y
+CONFIG_FEATURE_TOP_SMP_PROCESS=y
+CONFIG_FEATURE_TOPMEM=y
+CONFIG_UPTIME=y
+# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
+# CONFIG_WATCH is not set
+# CONFIG_FEATURE_SHOW_THREADS is not set
+
+#
+# Runit Utilities
+#
+# CONFIG_CHPST is not set
+# CONFIG_SETUIDGID is not set
+# CONFIG_ENVUIDGID is not set
+# CONFIG_ENVDIR is not set
+# CONFIG_SOFTLIMIT is not set
+# CONFIG_RUNSV is not set
+# CONFIG_RUNSVDIR is not set
+# CONFIG_FEATURE_RUNSVDIR_LOG is not set
+# CONFIG_SV is not set
+CONFIG_SV_DEFAULT_SERVICE_DIR=""
+CONFIG_SVC=y
+CONFIG_SVOK=y
+# CONFIG_SVLOGD is not set
+# CONFIG_CHCON is not set
+# CONFIG_GETENFORCE is not set
+# CONFIG_GETSEBOOL is not set
+# CONFIG_LOAD_POLICY is not set
+# CONFIG_MATCHPATHCON is not set
+# CONFIG_RUNCON is not set
+# CONFIG_SELINUXENABLED is not set
+# CONFIG_SESTATUS is not set
+# CONFIG_SETENFORCE is not set
+# CONFIG_SETFILES is not set
+# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
+# CONFIG_RESTORECON is not set
+# CONFIG_SETSEBOOL is not set
+
+#
+# Shells
+#
+CONFIG_SH_IS_ASH=y
+# CONFIG_SH_IS_HUSH is not set
+# CONFIG_SH_IS_NONE is not set
+# CONFIG_BASH_IS_ASH is not set
+# CONFIG_BASH_IS_HUSH is not set
+CONFIG_BASH_IS_NONE=y
+CONFIG_ASH=y
+CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
+CONFIG_ASH_INTERNAL_GLOB=y
+CONFIG_ASH_BASH_COMPAT=y
+# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
+CONFIG_ASH_BASH_NOT_FOUND_HOOK=y
+CONFIG_ASH_JOB_CONTROL=y
+CONFIG_ASH_ALIAS=y
+CONFIG_ASH_RANDOM_SUPPORT=y
+CONFIG_ASH_EXPAND_PRMT=y
+# CONFIG_ASH_IDLE_TIMEOUT is not set
+# CONFIG_ASH_MAIL is not set
+CONFIG_ASH_ECHO=y
+CONFIG_ASH_PRINTF=y
+CONFIG_ASH_TEST=y
+CONFIG_ASH_HELP=y
+CONFIG_ASH_GETOPTS=y
+CONFIG_ASH_CMDCMD=y
+CONFIG_CTTYHACK=y
+# CONFIG_HUSH is not set
+# CONFIG_HUSH_BASH_COMPAT is not set
+# CONFIG_HUSH_BRACE_EXPANSION is not set
+# CONFIG_HUSH_LINENO_VAR is not set
+# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
+# CONFIG_HUSH_INTERACTIVE is not set
+# CONFIG_HUSH_SAVEHISTORY is not set
+# CONFIG_HUSH_JOB is not set
+# CONFIG_HUSH_TICK is not set
+# CONFIG_HUSH_IF is not set
+# CONFIG_HUSH_LOOPS is not set
+# CONFIG_HUSH_CASE is not set
+# CONFIG_HUSH_FUNCTIONS is not set
+# CONFIG_HUSH_LOCAL is not set
+# CONFIG_HUSH_RANDOM_SUPPORT is not set
+# CONFIG_HUSH_MODE_X is not set
+# CONFIG_HUSH_ECHO is not set
+# CONFIG_HUSH_PRINTF is not set
+# CONFIG_HUSH_TEST is not set
+# CONFIG_HUSH_HELP is not set
+# CONFIG_HUSH_EXPORT is not set
+# CONFIG_HUSH_EXPORT_N is not set
+# CONFIG_HUSH_READONLY is not set
+# CONFIG_HUSH_KILL is not set
+# CONFIG_HUSH_WAIT is not set
+# CONFIG_HUSH_COMMAND is not set
+# CONFIG_HUSH_TRAP is not set
+# CONFIG_HUSH_TYPE is not set
+# CONFIG_HUSH_TIMES is not set
+# CONFIG_HUSH_READ is not set
+# CONFIG_HUSH_SET is not set
+# CONFIG_HUSH_UNSET is not set
+# CONFIG_HUSH_ULIMIT is not set
+# CONFIG_HUSH_UMASK is not set
+# CONFIG_HUSH_GETOPTS is not set
+# CONFIG_HUSH_MEMLEAK is not set
+
+#
+# Options common to all shells
+#
+CONFIG_FEATURE_SH_MATH=y
+CONFIG_FEATURE_SH_MATH_64=y
+CONFIG_FEATURE_SH_MATH_BASE=y
+CONFIG_FEATURE_SH_EXTRA_QUIET=y
+# CONFIG_FEATURE_SH_STANDALONE is not set
+# CONFIG_FEATURE_SH_NOFORK is not set
+CONFIG_FEATURE_SH_READ_FRAC=y
+CONFIG_FEATURE_SH_HISTFILESIZE=y
+CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y
+
+#
+# System Logging Utilities
+#
+CONFIG_KLOGD=y
+
+#
+# klogd should not be used together with syslog to kernel printk buffer
+#
+CONFIG_FEATURE_KLOGD_KLOGCTL=y
+CONFIG_LOGGER=y
+CONFIG_LOGREAD=y
+CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y
+CONFIG_SYSLOGD=y
+# CONFIG_FEATURE_ROTATE_LOGFILE is not set
+CONFIG_FEATURE_REMOTE_LOG=y
+# CONFIG_FEATURE_SYSLOGD_DUP is not set
+CONFIG_FEATURE_SYSLOGD_CFG=y
+CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256
+CONFIG_FEATURE_IPC_SYSLOG=y
+CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16
+CONFIG_FEATURE_KMSG_SYSLOG=y
diff --git a/modules.d/conf-tgz/hooks/fetch-config-tgz.sh b/modules.d/conf-tgz/hooks/fetch-config-tgz.sh
new file mode 100755
index 00000000..1c8ace61
--- /dev/null
+++ b/modules.d/conf-tgz/hooks/fetch-config-tgz.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+
+ slx_server="$(getarg slxsrv=)"
+ slx_server_base="$(getarg slxbase=)"
+
+ if [ -z "$SLX_NO_CONFIG_TGZ" ]; then
+ # build config.tgz url
+ conftgz_url="http://${slx_server#@}/${slx_server_base}/config.tgz"
+
+ # check if system's uuid was set
+ if [ -s "/run/system-uuid" ]; then
+ uuid="$(cat /run/system-uuid)"
+ if [ -n "$uuid" ]; then
+ conftgz_url="${conftgz_url}?uuid=${uuid}"
+ fi
+ fi
+ info "Download config.tgz from '$conftgz_url'..."
+ slx-tools download_retry -s "${conftgz_url}" > "/etc/config.tgz"
+
+ if [[ ! -s "/etc/config.tgz" ]]; then
+ warn \
+ "Downloading 'config.tgz' from '${slx_server}' failed with: $return_code"
+ # TODO handle error
+ fi
+ fi
diff --git a/modules.d/conf-tgz/hooks/unpack-config-tgz.sh b/modules.d/conf-tgz/hooks/unpack-config-tgz.sh
new file mode 100755
index 00000000..a0da0cd3
--- /dev/null
+++ b/modules.d/conf-tgz/hooks/unpack-config-tgz.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+# tarcopy <source_dir> <target_dir>
+tarcopy() {
+ [ -d "$1" -a -d "$2" ] || return 1
+ cd "$1"
+ local filelist="$(mktemp)"
+ find . \! -type d > "$filelist"
+ tar -c -p -T "$filelist" | tar -xp -C "$2"
+ rm -f -- "$filelist"
+ cd - &>/dev/null
+}
+
+# this module unpacks the config.tgz
+temporary_extract_directory="$(mktemp -d)"
+ if [[ -e "/etc/config.tgz" ]]; then
+ tar --extract --preserve-permissions \
+ --file="/etc/config.tgz" \
+ --directory="$temporary_extract_directory"
+ fi
+ warn "Failed to extract '/etc/config.tgz' to '$temporary_extract_directory'."
+ warn "$exceptions_last_traceback"
+# extracted to temporary directory, now check for SLX_LOCAL_CONFIGURATION
+
+source "/etc/openslx"
+if [[ -n "$SLX_LOCAL_CONFIGURATION" ]]; then
+ if [[ ! -d "${temporary_extract_directory}/openslx-configs/${SLX_LOCAL_CONFIGURATION}" ]]; then
+ warn "SLX_LOCAL_CONFIGURATION is set but no corresponding folder found in '/etc/config.tgz'. Ignoring..."
+ else
+ tarcopy "${temporary_extract_directory}/openslx-configs/${SLX_LOCAL_CONFIGURATION}" "${temporary_extract_directory}"
+ fi
+fi
+ # purge openslx-configs/
+ rm -rf "${temporary_extract_directory}/openslx-configs"
+ tarcopy "${temporary_extract_directory}" "$NEWROOT"
+
+
+ # TODO error handling
diff --git a/modules.d/conf-tgz/module-setup.sh b/modules.d/conf-tgz/module-setup.sh
new file mode 100755
index 00000000..a07539cb
--- /dev/null
+++ b/modules.d/conf-tgz/module-setup.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+check() {
+ return 255
+}
+depends() {
+ echo dnbd3-rootfs slx-tools
+}
+install() {
+ inst_hook pre-mount 20 "$moddir/hooks/fetch-config-tgz.sh"
+ inst_hook pre-pivot 20 "$moddir/hooks/unpack-config-tgz.sh"
+ # TODO check if busybox is enough
+ inst_multiple tar mktemp gzip
+}
diff --git a/modules.d/dnbd3-rootfs/binaries/dnbd3 b/modules.d/dnbd3-rootfs/binaries/dnbd3
new file mode 160000
+Subproject a6ddfe1212a2df72cacb0f44cc872b1bd0363c3
diff --git a/modules.d/dnbd3-rootfs/binaries/kernel-qcow2-linux b/modules.d/dnbd3-rootfs/binaries/kernel-qcow2-linux
new file mode 160000
+Subproject 0761b3e9e03ed63b4adfd8b4a82f334352729a4
diff --git a/modules.d/dnbd3-rootfs/binaries/kernel-qcow2-util-linux b/modules.d/dnbd3-rootfs/binaries/kernel-qcow2-util-linux
new file mode 160000
+Subproject 0692b963aa3cb846d8abab5ef5247c4dbb3fec9
diff --git a/modules.d/dnbd3-rootfs/binaries/qemu-xmount b/modules.d/dnbd3-rootfs/binaries/qemu-xmount
new file mode 160000
+Subproject 4873cd023da8511ed9792a318d1456c94904612
diff --git a/modules.d/dnbd3-rootfs/binaries/systemd-preserve-process-marker/Makefile b/modules.d/dnbd3-rootfs/binaries/systemd-preserve-process-marker/Makefile
new file mode 100644
index 00000000..406ec50f
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/binaries/systemd-preserve-process-marker/Makefile
@@ -0,0 +1,12 @@
+CC=gcc
+OPTS=-c -Wall
+SOURCES=$(wildcard *.c)
+OBJECTS=$(SOURCES:.c=.o)
+BINS=$(SOURCES:.c=)
+
+all: $(BINS)
+
+$(BINS): $(OBJECTS)
+
+clean:
+ rm -f $(BINS) $(OBJECTS)
diff --git a/modules.d/dnbd3-rootfs/binaries/systemd-preserve-process-marker/systemd-preserve-process-marker.c b/modules.d/dnbd3-rootfs/binaries/systemd-preserve-process-marker/systemd-preserve-process-marker.c
new file mode 100644
index 00000000..8f0fc108
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/binaries/systemd-preserve-process-marker/systemd-preserve-process-marker.c
@@ -0,0 +1,33 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+void print_array(int argc, char *argv[]) {
+ // Helper function to print given array with given length.
+ int i = 0;
+ int j = 0;
+ for (i = 0; i < argc; i ++) {
+ j = 0;
+ while(argv[i][j] != '\0')
+ printf("%c", argv[i][j++]);
+ printf(" ");
+ }
+ printf("\n");
+}
+int main(int argc, char *argv[]) {
+ int count;
+ // Last item acts as null pointer.
+ char **copy = calloc(sizeof(char *), argc);
+ // Slice first given command line argument.
+ for (count = 0; count < argc - 1; count++)
+ copy[count] = strdup(argv[count + 1]);
+ // Adding systemd indicator to preserve wrapped process during changing
+ // root filesystem. We mark wrapper and child process.
+ argv[0][0] = '@';
+ copy[0][0] = '@';
+ if (-1 == execvp(argv[1], copy)) {
+ perror("Executing child process failed.");
+ return -1;
+ }
+}
diff --git a/modules.d/dnbd3-rootfs/binaries/xmount b/modules.d/dnbd3-rootfs/binaries/xmount
new file mode 160000
+Subproject 015137556fce1e21273f198ae0b9158157f74f7
diff --git a/modules.d/dnbd3-rootfs/configuration/bash b/modules.d/dnbd3-rootfs/configuration/bash
new file mode 100755
index 00000000..adefda40
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/configuration/bash
@@ -0,0 +1,3 @@
+alias poweroff='poweroff --force'
+alias halt='poweroff'
+alias reboot='reboot --force'
diff --git a/modules.d/dnbd3-rootfs/helper/build.inc b/modules.d/dnbd3-rootfs/helper/build.inc
new file mode 100644
index 00000000..b3f9561c
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/helper/build.inc
@@ -0,0 +1,291 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+
+declare -rg _mainmoddir="$(dirname "${BASH_SOURCE[0]}")/.." 2> /dev/null
+
+declare -rg _supported_qcow_handlers=("xmount" "kernel")
+build_initialize_components() {
+ local qcow_handler="$_QCOW_HANDLER"
+ IFS='|' _pattern="^(${_supported_qcow_handlers[*]})$" export _pattern
+ if [[ ! "$qcow_handler" =~ $_pattern ]] ; then
+ echo "Unknown qcow handler '$qcow_handler' - will built all known."
+ echo "Supported handlers: ${_supported_qcow_handlers[*]}"
+ fi
+ _deps_base_dir="${_mainmoddir}/binaries"
+ # We might want to move the "binaries" repos from the dnbd3-rootfs module to main repo one day...
+ # TODO check for its existence using modinfo -k <kernel_version>
+ if [[ ! -f "${_deps_base_dir}/dnbd3/build/dnbd3.ko" ]] || \
+ [[ ! -f "${_deps_base_dir}/dnbd3/build/dnbd3-client" ]]; then
+ echo "Could not find dnbd3, building it..."
+ if ! CMAKE_FLAGS="-DKERNEL_DIR=${kernel_headers}" \
+ build_compile_dnbd3 "${_deps_base_dir}/dnbd3/"; then
+ echo "Failed to build dnbd3."
+ return 1
+ fi
+ fi
+ # take care of the qcow handler
+ if [ -z "$qcow_handler" ] || [ "$qcow_handler" = "xmount" ]; then
+ if [[ ! -f "${_deps_base_dir}/xmount/trunk/build/src/xmount" ]]; then
+ echo "Could not find xmount binary, building it..."
+ if ! build_compile_xmount "${_deps_base_dir}/xmount/"; then
+ echo "Failed to build xmount binary."
+ return 1
+ fi
+ fi
+ if [[ ! -f "${_deps_base_dir}/qemu-xmount/libxmount_input_qemu.so" ]]; then
+ echo "Could not find xmount qemu library, building it..."
+ if ! build_compile_qemu_xmount "${_deps_base_dir}/qemu-xmount/"; then
+ echo "Failed to build xmount qemu library."
+ return 1
+ fi
+ fi
+ fi
+ if [ -z "$qcow_handler" ] || [ "$qcow_handler" = "kernel" ]; then
+ if [ ! -f "${_deps_base_dir}/kernel-qcow2-linux/drivers/block/loop/loop.ko" ] \
+ || [ ! -f "${_deps_base_dir}/kernel-qcow2-linux/drivers/block/loop/loop_file_fmt_qcow.ko" ] \
+ || [ ! -f "${_deps_base_dir}/kernel-qcow2-linux/drivers/block/loop/loop_file_fmt_raw.ko" ]; then
+ echo "Could not find loop kernel modules, building them..."
+ if ! build_compile_kernel_qcow "${_deps_base_dir}/kernel-qcow2-linux"; then
+ echo "Failed to build qcow loop kernel modules."
+ return 1
+ fi
+ fi
+ if [ ! -f "${_deps_base_dir}/kernel-qcow2-util-linux/losetup" ]; then
+ echo "Could not find losetup with qcow2 support, building it..."
+ if ! build_compile_losetup_qcow "${_deps_base_dir}/kernel-qcow2-util-linux"; then
+ echo "Failed to build losetup with qcow support."
+ return 1
+ fi
+ fi
+ fi
+
+ # always compile this helper since it does not cost much to do so
+ if [[ ! -f "${_deps_base_dir}/systemd-preserve-process-marker/systemd-preserve-process-marker" ]]; then
+ echo "Could not find systemd-preserve-process-marker binary, building it ..."
+ if ! build_compile_systemd_preserve_process_marker \
+ "${_deps_base_dir}/systemd-preserve-process-marker/"; then
+ echo "Failed to build systemd-preserve-process-marker"
+ return 1
+ fi
+ fi
+ echo "Compilation of dnbd3-rootfs dependencies succeeded."
+ return 0
+}
+
+clean_components() {
+ local __doc__='
+ Removes all compiled kernel specific files.
+ NOTE: This method is triggered manually and not supported by dracut itself.
+
+ Example:
+
+ `clean`
+ '
+ local _submoddir="${_mainmoddir}/binaries"
+ build_clean_xmount "${_submoddir}/xmount/"
+ build_clean_qemu_xmount "${_submoddir}/qemu-xmount/"
+ build_clean_dnbd3 "${_submoddir}/dnbd3/"
+ build_clean_losetup_qcow "${_submoddir}/kernel-qcow2-util-linux"
+ build_clean_dnbd3 "${_submoddir}/dnbd3/"
+ build_clean_systemd_preserve_process_marker \
+ "${_submoddir}/systemd-preserve-process-marker/"
+ return 0
+}
+# endregion
+
+build_compile_qemu_xmount() {
+ local __doc__='
+ Compiles qemu libxmount.
+ NOTE: expects xmount installation under
+ $1/../xmount/trunk/build/release_build/
+
+ Provides the following file:
+ "$1/libxmount_input_qemu.so"
+
+ Example:
+
+ `build_compile_qemu_xmount /qemu_source /xmount/installation`
+ '
+ pushd "$1"
+ local xmount_installation="../xmount/trunk/build/release_build/usr"
+ [ ! -z "$2" ] && xmount_installation="$2"
+ ./configure --enable-xmount-input --python="$(which python2)" \
+ --extra-cflags="-std=gnu99" \
+ --disable-werror \
+ --extra-cflags="-fPIC" \
+ --extra-cflags="-I${xmount_installation}/include" \
+ --extra-cflags="-I${xmount_installation}/include/xmount" \
+ --disable-fdt --target-list=""
+ make -j libxmount_input_qemu.so
+ local ret=$?
+ popd
+ return $ret
+}
+build_clean_qemu_xmount() {
+ local __doc__='Clean the build of `build_compile_qemu_xmount`.'
+ pushd "$1"
+ make clean
+ local ret=$?
+ popd
+ return $ret
+}
+build_compile_xmount() {
+ local __doc__='
+ Compiles xmount.
+
+ Provides the xmount installation under:
+ "$1/trunk/build/release_build/"
+
+ Example:
+
+ `build_compile_xmount /xmount_source /xmount_source/build /usr`
+ '
+ pushd "$1"
+
+ local destination_directory="./release_build"
+ [ ! -z "$2" ] && destination_directory="$2"
+ local install_prefix="/usr"
+ [ ! -z "$3" ] && install_prefix="$3"
+
+ mkdir --parents trunk/build
+ cd trunk/build || return 1
+ cmake -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_INSTALL_PREFIX="$install_prefix" ..
+ make -j
+ make install DESTDIR="$destination_directory"
+ local ret=$?
+ popd
+ return $ret
+}
+build_clean_xmount() {
+ local __doc__='Clean the build of `build_compile_xmount`.'
+ rm --recursive --force "$1/trunk/build"
+}
+build_compile_dnbd3() {
+ local __doc__='
+ Compiles dnbd3 kernel module and client.
+
+ Provides the following file:
+ "$1/build/dnbd3.ko"
+ "$1/build/dnbd3-client"
+
+ Examples:
+
+ `build_compile_dnbd3 path/to/dnbd3/source/`
+
+ Passing the kernel version to cmake:
+ `CMAKE_FLAGS="-DKERNEL_VERSION=4.14.6-openslx+" \
+ build_compile_dnbd3 path/to/dnbd3/source/`
+ '
+ pushd "$1"
+ # NOTE: The generic way would be: "./build.sh" but this tries to build
+ # more than we really need and takes more time.
+ mkdir --parents build
+ cd build
+ # Inject CMAKE_FLAGS as a way to control how cmake is called,
+ # e.g. to pass the kernel version
+ cmake ${CMAKE_FLAGS} \
+ -DBUILD_FUSE_CLIENT=OFF \
+ -DBUILD_KERNEL_MODULE=ON \
+ -DBUILD_SERVER=OFF \
+ -DBUILD_STRESSTEST=OFF \
+ ../
+ make -j dnbd3 dnbd3-client
+ local ret=$?
+ popd
+ return $ret
+}
+build_clean_dnbd3() {
+ local __doc__='Clean the build of `build_compile_dnbd3`.'
+ rm --recursive --force "$1/build"
+ return $?
+}
+build_compile_kernel_qcow() {
+ pushd "$1"
+ # https://lab.ks.uni-freiburg.de/projects/kernel-qcow2/wiki
+ if [ -z "$kernel_headers" ]; then
+ echo "Kernel header directory not set, ignoring."
+ return 1
+ fi
+ mkdir -p "${kernel_headers}/drivers/block/loop"
+ for _file in \
+ include/uapi/linux/loop.h \
+ drivers/block/Kconfig \
+ drivers/block/loop/loop_main.h \
+ drivers/block/loop/loop_file_fmt.h \
+ drivers/block/loop/Kconfig; do
+ cp -f "${_file}" "${kernel_headers}/${_file}"
+ done
+ (
+ set -o errexit
+ make -C "$kernel_headers" CONFIG_BLK_DEV_LOOP=m \
+ M=$(pwd)/drivers/block/loop loop.ko
+ make -C "$kernel_headers" CONFIG_BLK_DEV_LOOP_FILE_FMT_RAW=m \
+ M=$(pwd)/drivers/block/loop loop_file_fmt_raw.ko
+ make -C "$kernel_headers" CONFIG_BLK_DEV_LOOP_FILE_FMT_QCOW=m \
+ M=$(pwd)/drivers/block/loop loop_file_fmt_qcow.ko
+ )
+ local ret=$?
+ popd
+ return $ret
+}
+build_clean_kernel_qcow() {
+ if [ -z "$kernel_headers" ]; then
+ echo "Kernel header directory not set, ignoring."
+ return 1
+ fi
+ pushd "$kernel_headers"
+ make -C "$kernel_headers" M=$(pwd)/drivers/block/loop clean
+ local ret=$?
+ popd
+ return $ret
+}
+build_compile_losetup_qcow() {
+ pushd "$1"
+ (
+ set -o errexit
+ ./autogen.sh
+ ./configure
+ make -j losetup
+ gcc -I./libsmartcols/src -O2 -o .libs/losetup sys-utils/losetup-losetup.o .libs/libcommon.a .libs/libsmartcols.a
+ )
+ local ret=$?
+ popd
+ return $ret
+}
+build_clean_losetup_qcow() {
+ pushd "$1"
+ make clean
+ local ret=$?
+ popd
+ return $ret
+}
+build_compile_systemd_preserve_process_marker() {
+ local __doc__='
+ Compiles simple c program.
+
+ Examples:
+
+ `build_compile_systemd_preserve_process_marker path/to/program/folder`
+ '
+ pushd "$1"
+ make
+ local ret=$?
+ popd
+ return $ret
+}
+build_clean_systemd_preserve_process_marker() {
+ local __doc__='
+ Clean the build of
+ `build_compile_systemd_preserve_process_marker`.
+ '
+ pushd "$1"
+ make clean
+ local ret=$?
+ popd
+ return $ret
+}
+# region vim modline
+# vim: set tabstop=4 shiftwidth=4 expandtab:
+# vim: foldmethod=marker foldmarker=region,endregion:
+# endregion
diff --git a/modules.d/dnbd3-rootfs/hooks/copy-dnbd3-service-into-newroot.sh b/modules.d/dnbd3-rootfs/hooks/copy-dnbd3-service-into-newroot.sh
new file mode 100755
index 00000000..ddfe4992
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/copy-dnbd3-service-into-newroot.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+systemd_system_unit_path="$(dirname \
+ "$(systemctl show -p FragmentPath dracut-mount.service | cut -c 14-)")"
+new_systemd_system_unit_path="${NEWROOT}/lib/systemd/system"
+cp "${systemd_system_unit_path}/dnbd3root.service" \
+ "${new_systemd_system_unit_path}/dnbd3root.service"
+mkdir --parents "${new_systemd_system_unit_path}/sysinit.target.wants"
+ln --symbolic '../dnbd3root.service' \
+ "${new_systemd_system_unit_path}/sysinit.target.wants/dnbd3root.service"
diff --git a/modules.d/dnbd3-rootfs/hooks/copy-dracut-systemd-files-into-newroot.sh b/modules.d/dnbd3-rootfs/hooks/copy-dracut-systemd-files-into-newroot.sh
new file mode 100755
index 00000000..5de1f2e9
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/copy-dracut-systemd-files-into-newroot.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+# Needed to be able to go back to dracut at system shutdown.
+temporary_directory_path="$(mktemp --directory)"
+mount --options bind / "$temporary_directory_path"
+cp --recursive --no-target-directory "$temporary_directory_path" /run/initramfs
+umount "$temporary_directory_path"
+rm --dir "$temporary_directory_path"
+
+# Dracut may not be installed on the new root. Thus copy all services over.
+dracut_mount_unit_path="$(systemctl show -p FragmentPath dracut-mount.service \
+ | cut -c 14-)"
+systemd_system_unit_path="${dracut_mount_unit_path%/*}"
+new_systemd_system_unit_path="${NEWROOT}/lib/systemd/system"
+
+mkdir --parents "$new_systemd_system_unit_path/initrd.target.wants"
+for file in \
+ dracut-cmdline.service \
+ dracut-initqueue.service \
+ dracut-mount.service \
+ dracut-pre-mount.service \
+ dracut-pre-pivot.service \
+ dracut-pre-trigger.service \
+ dracut-pre-udev.service
+do
+ cp "${systemd_system_unit_path}/${file}" \
+ "${new_systemd_system_unit_path}/${file}"
+ # "ln" returns an error if the link already exists.
+ source_path="../${file}"
+ target_path="${new_systemd_system_unit_path}/initrd.target.wants/${file}"
+ ln --symbolic "$source_path" "$targetPath" &>/dev/null || \
+ warn "Failed to link \"$source_path\" to \"$target_path\"."
+done
diff --git a/modules.d/dnbd3-rootfs/hooks/copy-openslx-configuration-into-newroot.sh b/modules.d/dnbd3-rootfs/hooks/copy-openslx-configuration-into-newroot.sh
new file mode 100755
index 00000000..ff01474f
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/copy-openslx-configuration-into-newroot.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+source "/etc/openslx"
+
+mkdir --parents "${NEWROOT}/opt/openslx"
+cp "/etc/openslx" "${NEWROOT}/opt/openslx/config"
+
+echo "## Generated by '$0' in stage3" >> "${NEWROOT}/opt/openslx/config"
+cat "/run/openslx/network.conf" >> "${NEWROOT}/opt/openslx/config"
+
+# Set root/demo password for stage4, if set
+if [ -n "${SLX_ROOT_PASS}" ]; then
+ sed -i "s#^root:[^:]*:#root:$SLX_ROOT_PASS:#" $NEWROOT/etc/shadow
+fi
+if [ -n "${SLX_DEMO_PASS}" ] && grep -q '^demo' $NEWROOT/etc/shadow; then
+ sed -i "s#^demo:[^:]*:#demo:$SLX_DEMO_PASS:#" $NEWROOT/etc/shadow
+fi
diff --git a/modules.d/dnbd3-rootfs/hooks/enable-sysrq.sh b/modules.d/dnbd3-rootfs/hooks/enable-sysrq.sh
new file mode 100755
index 00000000..323ec45e
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/enable-sysrq.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+
+# Enables magic sysrq kernel supported key combinations.
+echo 1 > /proc/sys/kernel/sysrq
diff --git a/modules.d/dnbd3-rootfs/hooks/fetch-config.sh b/modules.d/dnbd3-rootfs/hooks/fetch-config.sh
new file mode 100755
index 00000000..a11332a7
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/fetch-config.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+# region imports
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+# endregion
+
+slx_server="$(getarg slxsrv=)"
+slx_server_base="$(getarg slxbase=)"
+
+# build config_url
+config_url="http://${slx_server#@}/${slx_server_base}/config"
+
+# check if system's uuid was set
+if [ -s "/run/system-uuid" ]; then
+ uuid=$(cat "/run/system-uuid")
+ if [ -n "$uuid" ]; then
+ config_url="${config_url}?uuid=${uuid}"
+ fi
+fi
+
+config_path="/etc/openslx.tmp"
+
+echo "Downloading '$config_url'..."
+slx-tools download_retry -s "$config_url" > "$config_path"
+
+if [ ! -s "$config_path" ] ; then
+ warn "Downloading OpenSLX configuration file from '$config_url' failed with: $return_code"
+ emergency_shell "CRITICAL: System unusable."
+fi
+
+if ! ash -n "$config_path"; then
+ warn "Downloaded OpenSLX configuration failed syntax check!"
+ emergency_shell "CRITICAL: System unusable."
+fi
+
+# remember kcl server and base
+{
+ echo "SLX_KCL_SERVERS='$slx_server'"
+ echo "SLX_BASE_PATH='$slx_server_base'"
+ echo "# Config fetched from $config_url"
+ echo "CONFIG_DOWNLOAD_TIME=$(sed -r 's/^([0-9]+)\.([0-9]+).*$/\1\2/' /proc/uptime)"
+ echo '#_RCONFIG_TAG'
+} > /etc/openslx
+
+# finally copy remote config into it
+cat "$config_path" >> /etc/openslx
+
+# slxsrv overrides SLX_DNBD3_SERVERS if prefixed with @
+[ "${slx_server#@}" != "${slx_server}" ] && sed -i "s/^SLX_DNBD3_SERVERS=.*/SLX_DNBD3_SERVERS='${slx_server#@}'/" "/etc/openslx"
+true
diff --git a/modules.d/dnbd3-rootfs/hooks/load-custom-kernel-modules.sh b/modules.d/dnbd3-rootfs/hooks/load-custom-kernel-modules.sh
new file mode 100755
index 00000000..b3d3eb75
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/load-custom-kernel-modules.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+for kmod in dnbd3 \
+ "loop max_loop=8" \
+ loop_file_fmt_qcow \
+ loop_file_fmt_raw; do
+ if ! modprobe ${kmod}; then
+ warn "Failed to load kernel module: $kmod"
+ ! :
+ fi
+done
diff --git a/modules.d/dnbd3-rootfs/hooks/mount-root-device.sh b/modules.d/dnbd3-rootfs/hooks/mount-root-device.sh
new file mode 100755
index 00000000..6f31bbac
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/mount-root-device.sh
@@ -0,0 +1,9 @@
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+source "/etc/openslx"
+mount "$SLX_DNBD3_DEVICE_COW" "$NEWROOT" $SLX_MOUNT_ROOT_OPTIONS
+if [ -n "$SLX_GENERATE_FSTAB_SCRIPT" ]; then
+ eval "$SLX_GENERATE_FSTAB_SCRIPT"
+else
+ echo "" > "$NEWROOT/etc/fstab"
+fi
diff --git a/modules.d/dnbd3-rootfs/hooks/prepare-root-partition.sh b/modules.d/dnbd3-rootfs/hooks/prepare-root-partition.sh
new file mode 100755
index 00000000..aa782184
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/prepare-root-partition.sh
@@ -0,0 +1,107 @@
+#!/usr/bin/env bash
+type emergency_shell > /dev/null 2>&1 || source /lib/dracut-lib.sh
+source /etc/openslx
+
+export PATH="/usr/local/bin:$PATH"
+export LD_LIBRARY_PATH="/usr/local/lib"
+
+
+# hardcode dnbd device path
+declare -rg _dnbd3_dev="/dev/dnbd0"
+
+# all outputs are redirected to stderr, since this functions should
+# only echo the path to the unpacked container to stdout.
+container_unpack_xmount() {
+ local in_device="$1"
+ local out_path="/mnt/xmount"
+ mkdir -p "$out_path"
+ # check tools first
+ if ! hash xmount systemd-preserve-process-marker; then
+ warn "Missing xmount deps, will try raw..." 1>&2
+ elif ! systemd-preserve-process-marker xmount \
+ --in qemu "$in_device" \
+ --out raw "$out_path" &>/dev/null; then
+ warn "xmount call failed, assuming raw image." 1>&2
+ else
+ in_device="${out_path}/${_dnbd3_dev##*/}.dd"
+ fi
+ local out_device="$(losetup -f)"
+ if ! losetup "$out_device" "$in_device" --partscan; then
+ warn "Failed to attach '$in_device' to '$out_device'."
+ return 1
+ fi
+ udevadm settle
+ echo "$out_device"
+}
+
+container_unpack_losetup() {
+ local in_device="$1"
+ local out_device="$(losetup -f)"
+ if ! losetup -r -t QCOW "$out_device" "$in_device" --partscan; then
+ warn "Failed to attach '$in_device' to '$out_device'."
+ return
+ fi
+ udevadm settle
+ echo "$out_device"
+}
+# endregion
+
+(
+IFS=", "
+for host in ${SLX_DNBD3_SERVERS} FAIL; do
+ if [ "$host" = "FAIL" ]; then
+ emergency_shell "Failed to connect '${SLX_DNBD3_IMAGE}' "\
+ "${SLX_DNBD3_RID:+(revision: $SLX_DNBD3_RID)} "
+ "from one of '$SLX_DNBD3_SERVERS' to '$_dnbd3_dev'."
+ fi
+ info "Trying host \"$host\"."
+ if systemd-preserve-process-marker dnbd3-client \
+ --host "$host" \
+ --image "${SLX_DNBD3_IMAGE}" \
+ --device "$_dnbd3_dev" \
+ ${SLX_DNBD3_RID:+--rid "$SLX_DNBD3_RID"}; then
+ break
+ fi
+done
+)
+# endregion
+# region unpack dnbd3 image
+[ -z "$SLX_QCOW_HANDLER" ] && SLX_QCOW_HANDLER="xmount"
+if [ "$SLX_QCOW_HANDLER" = "xmount" ]; then
+ read_only_device="$(container_unpack_xmount "$_dnbd3_dev")"
+elif [ "$SLX_QCOW_HANDLER" = "kernel" ]; then
+ read_only_device="$(container_unpack_losetup "$_dnbd3_dev")"
+else
+ warn "Unsupported QCOW handler: $SLX_QCOW_HANDLER"
+fi
+
+# Fail fast if unpacking dnbd3 image failed.
+[ -z "$read_only_device" ] && exit 1
+
+# endregion
+# region find system partition within dnbd3 image
+if [ -z "$SLX_SYSTEM_PARTITION_PREPARATION_SCRIPT" ]; then
+ if [ -z "$SLX_SYSTEM_PARTITION_IDENTIFIER" ]; then
+ # if empty use whole device
+ read_only_partition="$read_only_device"
+ true
+ else
+ read_only_partition="$(slx-tools dev_find_partitions \
+ "$read_only_device" "$SLX_SYSTEM_PARTITION_IDENTIFIER")"
+ fi
+else
+ eval "$SLX_SYSTEM_PARTITION_PREPARATION_SCRIPT"
+fi
+if [[ ! $? || -z "$read_only_partition" ]]; then
+ warn "Failed to find unique device with identifier" \
+ "\"${SLX_SYSTEM_PARTITION_IDENTIFIER}\"; matched devices:" \
+ "\"${read_only_partition}\""
+ exit 1
+fi
+info "Using read-only partition: $read_only_partition"
+# endregion
+
+# region add rw layer to dnbd3 image
+# don't be fooled to think we are done, the next part is crucial
+dmsetup-slx-device "$read_only_partition"
+# endregion
diff --git a/modules.d/dnbd3-rootfs/hooks/set-dracut-environment-variables.sh b/modules.d/dnbd3-rootfs/hooks/set-dracut-environment-variables.sh
new file mode 100755
index 00000000..ad80349b
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/set-dracut-environment-variables.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+
+# Set rootok and root as dracut expects them to be set by the module preparing
+# the root filesystem.
+
+# Tell dracut that we parsed the command line and all needed parameters are
+# available.
+rootok=1
+# Tell dracut where the final root fs will be located.
+root=block:/dev/devicemapper/root
+
+# region vim modline
+# vim: set tabstop=4 shiftwidth=4 expandtab:
+# vim: foldmethod=marker foldmarker=region,endregion:
+# endregion
diff --git a/modules.d/dnbd3-rootfs/hooks/shutdown-umount.sh b/modules.d/dnbd3-rootfs/hooks/shutdown-umount.sh
new file mode 100644
index 00000000..ab78733c
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/hooks/shutdown-umount.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+source /etc/openslx
+
+export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+
+umount /oldroot
+dmsetup --noudevsync remove root
+losetup --detach-all
+umount /mnt/*
+dnbd3-client --device "$SLX_DNBD3_DEVICE" --close
diff --git a/modules.d/dnbd3-rootfs/module-setup.sh b/modules.d/dnbd3-rootfs/module-setup.sh
new file mode 100755
index 00000000..77543a54
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/module-setup.sh
@@ -0,0 +1,231 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+
+
+_parse_dracut_args() {
+ local __doc__='
+ Set log level via dracut logging options and returns current debug state.
+
+ >>> echo "$_debug"
+ 1
+ >>> _parse_dracut_args; echo $?
+ 1
+
+ >>> _parse_dracut_args --stdlog 3; echo $?
+
+ >>> _parse_dracut_args --stdlog 4; echo $?
+ >>> logging.get_commands_level
+ >>> logging.get_level
+ 0
+ debug
+ debug
+
+ >>> logging.get_level
+ critical
+ >>> _parse_dracut_args --stdlog 4 --verbose
+ >>> logging.get_level
+ debug
+
+ >>> _parse_dracut_args --stdlog 4 --unknown-dracut-option; echo $?
+ 0
+ '
+ local verbose=false
+ local debug=false
+ while true; do
+ case "$1" in
+ --stdlog)
+ shift
+ local level="$1"
+ shift
+ [[ "$level" -ge 4 ]] && debug=true
+ ;;
+ --verbose)
+ shift
+ verbose=true
+ ;;
+ '')
+ break
+ ;;
+ *)
+ shift
+ ;;
+ esac
+ local level
+ $verbose && level=info
+ $debug && level=debug
+ #logging.set_level "$level"
+ #logging.set_commands_level debug
+ done
+ $debug
+ return $?
+}
+# WTF does this actually do aside from taking space!
+_debug=0
+_parse_dracut_args ${dracut_args[*]} || _debug=$?
+# endregion
+
+clean() {
+# Sourcing some helper functions
+ . "$(dirname "${BASH_SOURCE[0]}")/helper/build.inc"
+ clean_components
+}
+# region dracut plugin api
+check() {
+# Sourcing some helper functions
+ . "$(dirname "${BASH_SOURCE[0]}")/helper/build.inc"
+ if ! build_initialize_components; then
+ echo "Failed to initialize components."
+ return 1
+ fi
+ # NOTE: xmount must be compiled before qemu_xmount
+ local xmount_is_built=true
+ if [[ ! -f "$moddir/binaries/xmount/trunk/build/src/xmount" ]] ||
+ [[ ! -f "$moddir/binaries/qemu-xmount/libxmount_input_qemu.so" ]]; then
+ xmount_is_built=false
+ fi
+ # non-critical if failed
+ $xmount_is_built || warn "Compiling 'xmount'/'libxmount_input_qemu' failed."
+
+ if [[ ! -f "$moddir/binaries/dnbd3/build/dnbd3.ko" ]] || \
+ [[ ! -f "$moddir/binaries/dnbd3/build/dnbd3-client" ]]; then
+ CMAKE_FLAGS="-DKERNEL_VERSION=${kernel}" \
+ build_compile_dnbd3 "$moddir/binaries/dnbd3/"
+ [[ $? != 0 ]] && return 1
+ fi
+ if [[ ! -f "$moddir/binaries/systemd-preserve-process-marker/systemd-preserve-process-marker" ]]; then
+ build_compile_systemd_preserve_process_marker \
+ "$moddir/binaries/systemd-preserve-process-marker/"
+ [[ $? != 0 ]] && return 1
+ fi
+ # TODO do we still need this ?
+ # NOTE: This are workarounds for:
+ # - distributions where "systemd-udevd" doesn't lives in "/usr/lib" but in
+ # "/lib".
+ local alternate_systemd_udevd_location='/lib/systemd/systemd-udevd'
+ if [[ ! -f "${systemdutildir}/systemd-udevd" ]] && \
+ [[ -f "$alternate_systemd_udevd_location" ]]; then
+ mkdir --parents "${initdir}${systemdutildir}"
+ ln --symbolic --force "$alternate_systemd_udevd_location" \
+ "${initdir}${systemdutildir}/systemd-udevd"
+ fi
+ # WTF?
+ # - "/usr/bin/sh" isn't available but "/bin/sh".
+ if [[ ! -f /usr/bin/sh ]] && [[ -f /bin/sh ]]; then
+ ln --symbolic --force /bin/sh /usr/bin/sh
+ fi
+ return 255
+}
+depends() {
+ echo base bash kernel-modules shutdown slx-dmsetup slx-network
+}
+installkernel() {
+ local block_kmod_dir="/lib/modules/${kernel}/kernel/drivers/block"
+
+ # dnbd3
+ mkdir -p "${initdir}/${block_kmod_dir}"
+ inst "${moddir}/binaries/dnbd3/build/dnbd3.ko" "${block_kmod_dir}/dnbd3.ko"
+
+ # kqcow2 kernel
+ local kqcow_loop_kmod_dir="${moddir}/binaries/kernel-qcow2-linux/drivers/block/loop"
+ if [ -e "${kqcow_loop_kmod_dir}/loop.ko" ] && \
+ [ -e "${kqcow_loop_kmod_dir}/loop_file_fmt_raw.ko" ] && \
+ [ -e "${kqcow_loop_kmod_dir}/loop_file_fmt_qcow.ko" ]; then
+ mkdir -p "${initdir}/${block_kmod_dir}/loop"
+ for kmod in "${kqcow_loop_kmod_dir}/"*.ko ; do
+ inst "$kmod" "${block_kmod_dir}/loop/$(basename $kmod)"
+ done
+ fi
+}
+install() {
+ # region binaries
+ inst "$moddir/binaries/dnbd3/build/dnbd3-client" /usr/local/bin/dnbd3-client
+ inst "$moddir/binaries/systemd-preserve-process-marker/systemd-preserve-process-marker" \
+ /usr/local/bin/systemd-preserve-process-marker
+ # xmount
+ local \
+ xmount_installation="$moddir/binaries/xmount/trunk/build/release_build"
+ if [[ -f "${xmount_installation}/usr/bin/xmount" ]]; then
+ inst "${xmount_installation}/usr/bin/xmount" /usr/bin/xmount
+ for file in ${xmount_installation}/usr/lib/xmount/*; do
+ inst "$file" /usr/lib/xmount/"$(basename "$file")"
+ done
+ inst "$moddir/binaries/qemu-xmount/libxmount_input_qemu.so" \
+ /usr/lib/xmount/libxmount_input_qemu.so
+ # HACK fix missing libraries for some xmount input libs
+ # TODO copy the dependencies using dracut functions...
+ inst_libdir_file 'libafflib.so*'
+ inst_libdir_file 'libewf.so*'
+ fi
+ # kqcow2 losetup
+ local losetup_qcow2_dir="$moddir/binaries/kernel-qcow2-util-linux"
+ if [[ -f "${losetup_qcow2_dir}/.libs/losetup" ]]; then
+ inst "${losetup_qcow2_dir}/.libs/losetup" /usr/local/bin/losetup
+ mkdir -p "${initdir}/usr/local/lib"
+ cp -a "${losetup_qcow2_dir}/.libs/"*.so* "${initdir}/usr/local/lib"
+ fi
+ # endregion
+ # region hooks
+ inst_hook cmdline 00 "$moddir/hooks/enable-sysrq.sh"
+ # NOTE: Can be used to support old style ip append syntax and have an
+ # exclusive interface name - required when using dracut's regular
+ # 'network' module
+ dracut_module_included "network" && inst_hook cmdline 10 \
+ "$moddir/hooks/prepare-kernel-command-line-parameter.sh"
+ inst_hook cmdline 90 "$moddir/hooks/set-dracut-environment-variables.sh"
+ inst_hook pre-udev 00 "$moddir/hooks/load-custom-kernel-modules.sh"
+ # Get the openslx config from the servers configured in the kernel command
+ # line (${SLX_SERVER}/${SLX_SERVER_BASE}/config).
+ inst_hook pre-mount 10 "$moddir/hooks/fetch-config.sh"
+ # make the final blockdevice for the root system (dnbd3 -> xmount ->
+ # device-mapper)
+ if dracut_module_included "systemd-initrd"; then
+ inst "$moddir/hooks/prepare-root-partition.sh" \
+ /usr/local/bin/dnbd3root
+ inst_simple "${moddir}/services/dnbd3root.service" \
+ "${systemdsystemunitdir}/dnbd3root.service"
+ mkdir --parents \
+ "${initdir}/${systemdsystemunitdir}/dracut-mount.service.requires"
+ ln_r "${systemdsystemunitdir}/dnbd3root.service" \
+ "${systemdsystemunitdir}/dracut-mount.service.requires/dnbd3root.service"
+ mkdir --parents \
+ "${initdir}/${systemdsystemunitdir}/initrd.target.requires"
+ ln_r "${systemdsystemunitdir}/dnbd3root.service" \
+ "${systemdsystemunitdir}/initrd.target.requires/dnbd3root.service"
+ # Copy systemd services to new root (so they don't get killed after
+ # switch_root)
+ inst_hook pre-pivot 00 \
+ "$moddir/hooks/copy-dnbd3-service-into-newroot.sh"
+ inst_hook pre-pivot 00 \
+ "$moddir/hooks/copy-dracut-systemd-files-into-newroot.sh"
+ inst_hook pre-shutdown 00 "$moddir/hooks/shutdown-umount.sh"
+ else
+ inst_hook pre-mount 10 "$moddir/hooks/prepare-root-partition.sh"
+ fi
+ inst_hook mount 10 "$moddir/hooks/mount-root-device.sh"
+ inst_hook pre-pivot 00 \
+ "$moddir/hooks/copy-openslx-configuration-into-newroot.sh"
+ # endregion
+ # region scripts
+ # endregion
+ # region configuration files
+ # Use terminal readline settings from the template system.
+ inst /etc/inputrc /etc/inputrc
+ # Set some aliases for the initramfs context.
+ if [[ "$_debug" == 0 ]]; then
+ inst "$moddir/configuration/bash" '/etc/bash.bashrc'
+ inst "$moddir/configuration/bash" '/etc/profile.d/aliases'
+ fi
+ # endregion
+ inst_multiple \
+ awk \
+ basename bash blockdev \
+ cat cut curl \
+ dd diff dirname dmsetup \
+ find \
+ grep \
+ insmod \
+ lsblk \
+ mkfifo mktemp mount mountpoint \
+ sed sleep sort \
+ tee touch tr
+}
diff --git a/modules.d/dnbd3-rootfs/services/dnbd3root.service b/modules.d/dnbd3-rootfs/services/dnbd3root.service
new file mode 100644
index 00000000..df079576
--- /dev/null
+++ b/modules.d/dnbd3-rootfs/services/dnbd3root.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=root fs on dnbd3 (distributed network block device)
+After=dracut-pre-mount.service network.target
+Before=dracut-mount.service
+DefaultDependencies=no
+IgnoreOnIsolate=true
+
+[Service]
+Type=oneshot
+RemainAfterExit=true
+KillMode=none
+ExecStart=/usr/local/bin/dnbd3root
diff --git a/modules.d/dns/module-setup.sh b/modules.d/dns/module-setup.sh
new file mode 100755
index 00000000..3bad6548
--- /dev/null
+++ b/modules.d/dns/module-setup.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+check() {
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ return 255
+}
+depends() {
+ echo base
+}
+install() {
+ inst_hook pre-mount 50 "$moddir/scripts/gen-resolv-conf.sh"
+}
diff --git a/modules.d/dns/scripts/gen-resolv-conf.sh b/modules.d/dns/scripts/gen-resolv-conf.sh
new file mode 100755
index 00000000..1601bb12
--- /dev/null
+++ b/modules.d/dns/scripts/gen-resolv-conf.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+CONFFILE="/etc/resolv.conf"
+
+DNS=$(getargs dns=)
+HOSTNAME=$(getargs hostname=)
+
+[ -n "$DNS" ] && echo "nameserver $DNS" >> "$CONFFILE"
+[ -n "$HOSTNAME" ] && echo "$HOSTNAME" >> /etc/hostname
diff --git a/modules.d/haveged/module-setup.sh b/modules.d/haveged/module-setup.sh
new file mode 100644
index 00000000..d3183dbe
--- /dev/null
+++ b/modules.d/haveged/module-setup.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+check() {
+ if ! hash haveged 2>/dev/null; then
+ warn "Could not find haveged in $PATH. Check if its installed."
+ return 1
+ fi
+ return 0
+}
+# called by dracut
+install() {
+ # see where haveged is installed
+ local haveged_bin="$(command -v haveged)"
+ if [ -z "$haveged_bin" ]; then
+ warn "Could not find havaged in $PATH. Check if its installed."
+ return 1
+ fi
+ # TODO SysVInit support, if that even a thing anymore :)
+ local haveged_service="$systemdsystemunitdir/haveged.service"
+ if [ ! -f "$haveged_service" ]; then
+ # query systemd directly
+ haveged_service="$(systemctl show -p FragmentPath haveged | cut -c 14-)"
+ if [ -z "$haveged_service" ]; then
+ warn "Could not find haveged service in '$systemdsystemunitdir' or by querying systemd."
+ warn "Check if it is installed properly."
+ return 1
+ fi
+ fi
+ inst_multiple -o \
+ "$haveged_bin" \
+ "$haveged_service"
+
+ # In Ubuntu, the service sources an EnvironmentFile for default options
+ local haveged_env_file="$(grep -oP '^EnvironmentFile=-?\K.*' $haveged_service)"
+ if [ -n "$haveged_env_file" ]; then
+ mkdir -p "$initdir/${haveged_env_file%/*}" 2>/dev/null
+ cp "$haveged_env_file" "$initdir/$haveged_env_file"
+ fi
+ mkdir "$initdir/$systemdsystemunitdir/sysinit.target.wants" 2>/dev/null
+ ln_r "$systemdsystemunitdir/haveged.service" "$systemdsystemunitdir/sysinit.target.wants/haveged.service"
+}
diff --git a/modules.d/ib-conf/module-setup.sh b/modules.d/ib-conf/module-setup.sh
new file mode 100755
index 00000000..0a80d89e
--- /dev/null
+++ b/modules.d/ib-conf/module-setup.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+check() {
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ return 255
+}
+depends() {
+ echo dnbd3-rootfs
+}
+install() {
+ inst_hook pre-pivot 50 "$moddir/scripts/gen-ib-conf.sh"
+}
diff --git a/modules.d/ib-conf/scripts/gen-ib-conf.sh b/modules.d/ib-conf/scripts/gen-ib-conf.sh
new file mode 100755
index 00000000..430dc887
--- /dev/null
+++ b/modules.d/ib-conf/scripts/gen-ib-conf.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+type emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+. "/run/openslx/network.conf"
+
+# get the IP from the VLAN device if a VLAN is configured
+[ -n "${SLX_VLAN_ID}" ] && SLX_PXE_NETIF="${SLX_PXE_NETIF}.${SLX_VLAN_ID}"
+
+IPSUFFIX=$(
+ ip -4 -o addr show dev "${SLX_PXE_NETIF}" | \
+ awk '{split($4,a,"/");split(a[1],b,".");print b[3]"."b[4]}'
+)
+
+cat << EOF >> "${NEWROOT}/etc/sysconfig/network-scripts/ifcfg-ib0"
+DEVICE=ib0
+NAME=ib0
+TYPE=Infiniband
+BOOTPROTO=static
+IPADDR=10.12.${IPSUFFIX}
+BROADCAST=10.12.255.255
+NETWORK=10.12.0.0
+NETMASK=255.255.0.0
+ONBOOT=yes
+NM_CONTROLLED=yes
+CONNECTED_MODE=yes
+MTU=65520
+EOF
+
diff --git a/modules.d/kexec-reboot/module-setup.sh b/modules.d/kexec-reboot/module-setup.sh
new file mode 100755
index 00000000..1cda92a0
--- /dev/null
+++ b/modules.d/kexec-reboot/module-setup.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+check() {
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ if ! hash kexec; then
+ derror "Failed to find kexec, please install it when using this module."
+ return 1
+ fi
+ return 255
+}
+depends() {
+ echo dnbd3-rootfs slx-tools
+}
+install() {
+ inst_simple "$moddir/scripts/kexec-reboot.sh" "/bin/kexec-reboot"
+ inst_multiple kexec
+}
diff --git a/modules.d/kexec-reboot/scripts/kexec-reboot.sh b/modules.d/kexec-reboot/scripts/kexec-reboot.sh
new file mode 100755
index 00000000..68fa73b9
--- /dev/null
+++ b/modules.d/kexec-reboot/scripts/kexec-reboot.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+kexec_load() {
+ . /lib/dracut-lib.sh
+
+ local SLXSRV="$(getarg slxsrv)"
+ local SLXBASE="$(getarg slxbase)"
+ local DIR="$(mktemp -d)"
+
+ if [ -z "$SLXSRV" -o -z "$SLXBASE" -o -z "$DIR" ]; then
+ echo "Failed to construct download URL..."
+ return 1
+ fi
+ for FILE in kernel initramfs-stage31; do
+ if ! slx-tools download_retry "http://${SLXSRV}/${SLXBASE}/${FILE}" > "${DIR}/${FILE}" ; then
+ echo "Failed to download ${FILE}."
+ return 1
+ fi
+ done
+
+ if ! kexec --load "${DIR}/kernel" \
+ --initrd "${DIR}/initramfs-stage31" \
+ --reuse-cmdline "${1:+--append "$@"}"; then
+ echo "Failed to load kernel/initrd from ${DIR}"
+ return 1
+ fi
+ return 0
+}
+
+if ! hash kexec; then
+ echo "kexec binary not found, aborting..."
+ exit 1
+fi
+if kexec_load $@; then
+ kexec -e
+else
+ echo "Failed to execute kexec --load"
+ exit 1
+fi
diff --git a/modules.d/slx-addons/module-setup.sh b/modules.d/slx-addons/module-setup.sh
new file mode 100755
index 00000000..296b3fe4
--- /dev/null
+++ b/modules.d/slx-addons/module-setup.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+check() {
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ return 255
+}
+depends() {
+ echo dnbd3-rootfs
+}
+install() {
+ inst_hook pre-pivot 30 "$moddir/scripts/setup-addons.sh"
+}
diff --git a/modules.d/slx-addons/scripts/setup-addons.sh b/modules.d/slx-addons/scripts/setup-addons.sh
new file mode 100644
index 00000000..94c2c444
--- /dev/null
+++ b/modules.d/slx-addons/scripts/setup-addons.sh
@@ -0,0 +1,105 @@
+#!/usr/bin/env bash
+#
+# Stage4 addons setup script
+#
+###############################################################################
+# Support stage4 addons residing under '/opt/openslx/addons'.
+# This script will loop over all addons found, in the form of
+# directories containing directory structures relative to '/'
+#
+# Additionally addons are expected to provide:
+# * <addon_dir>/addon-required -> script to check whether the
+# addon should be installed (exit 0) or not (exit 1).
+#
+# * <addon_dir>/opt/openslx/etc/<addon_name>.whiteout -> list of files
+# that were removed during the addon installation and thus need to be
+# removed after the addon was installed.
+#
+# * <addon_dir>/opt/openslx/etc/<addon_name> ld.so.cache -> ld cache containing
+# the newly installed libraries. CAVE: multiple addons -> ld cache combination
+#
+### CURRENTLY NOT EXECUTED
+# * <addon_dir>/addon-init -> script that will be automatically
+# be executed after the addon was installed.
+# NOTE: question remains if this should be done within stage3
+# or by chroot'ing into the stage4 before executing it.
+### CURRENTLY NOT EXECUTED: Since whiteouts could be handled for _all_addons
+
+type emergency_shell >/dev/null 2>&1 || . /lib/dracut-lib.sh
+
+# Check if we even have any addons to process
+if [ ! -d "$NEWROOT/opt/openslx/addons" ]; then
+ info "No stage4 addons found."
+ return 0
+fi
+
+setup_addons() {
+ local ADDONS_DIR="$NEWROOT/opt/openslx/addons/"
+ cd "$ADDONS_DIR" || return 1
+ for ADDON in *; do
+ if ! setup_addon "$ADDON"; then
+ info "Failed to setup $ADDON"
+ fi
+ done
+}
+
+setup_addon() {
+ [ -z "$1" -o ! -d "$ADDONS_DIR/$1" ] && return 1
+ local ADDON="$1"
+ cd "$ADDONS_DIR/$ADDON" || return 1
+
+ if ! bash addon-required 2>&1 ; then
+ info "'$ADDONS_DIR/$ADDON/addon-required' missing or returned non-zero, skipping..."
+ return 1
+ fi
+
+ for entry in $(find * -not -wholename "addon-*" 2>/dev/null); do
+ if [ -d "$entry" ]; then
+ [ -d "/$entry" ] || mkdir -p "/${entry}"
+ continue
+ fi
+ local dir=${entry%/*}
+ [ -d "$NEWROOT/$dir" ] || mkdir -p "$NEWROOT/$dir"
+ if [ -f "$entry" -a ! -L "$entry" ]; then
+ if [ ! -e "$NEWROOT/${entry}" ] || ! diff -q "$entry" "$NEWROOT/${entry}"; then
+ mv -f -- "$entry" "$NEWROOT/${entry}"
+ fi
+ else
+ # either block dev, char dev or a symlink, just overwrite them "blindly"
+ mv -f -- "$entry" "$NEWROOT/${entry}"
+ fi
+ done
+
+ # post merge: remove whiteouts from filesystem
+ for WHITEOUT in "$NEWROOT/opt/openslx/etc/"*.whiteout; do
+ [ -e "$WHITEOUT" ] || continue
+ while read line; do
+ rm -f "${NEWROOT}/${line}"
+ done < "$WHITEOUT"
+ done
+
+ # finally update ld.so.cache expected to be under /opt/openslx/etc/<addon_name>.ld.so.cache
+ # NOTE: if we have more than one addon in the future, we need to be extra
+ # careful with prebuilt ld.caches since they need to match *ALL* addons
+ local ADDON_LD_CACHE="$NEWROOT/opt/openslx/etc/$ADDON.ld.so.cache"
+ if [ ! -e "$ADDON_LD_CACHE" ] || ! mv -f -- "$ADDON_LD_CACHE" "$NEWROOT/etc/ld.so.cache" ; then
+ # Using prebuilt ld cache failed, try hard to find a ldconfig...
+ for LDCONFIG in "$(type -p ldconfig 2>/dev/null)" "${NEWROOT}/sbin/ldconfig.real"; do
+ if [ -x "$LDCONFIG" ] && "$LDCONFIG" -r "$NEWROOT"; then
+ return 0
+ fi
+ done
+ # try with chroot if we have it
+ local CHROOT_PATH="$(type -p chroot 2>/dev/null)"
+ if [ -x "$CHROOT_PATH" ] && "$CHROOT_PATH" "$NEWROOT" ldconfig; then
+ return 0
+ fi
+ # very bad indeed, libraries won't be registered in the cache ...
+ warn "Failed to find 'ldconfig' to rebuild the addon's missing ld.so.cache..."
+ return 1
+ fi
+}
+
+if ! setup_addons; then
+ warn "Failed to fully setup some addons! They will likely malfunction..."
+fi
diff --git a/modules.d/slx-clock/module-setup.sh b/modules.d/slx-clock/module-setup.sh
new file mode 100755
index 00000000..0c21b032
--- /dev/null
+++ b/modules.d/slx-clock/module-setup.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+check() {
+ if ! hash ntpdate; then
+ derror "Missing 'ntpdate'. Please install it."
+ return 1
+ fi
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ return 255
+}
+depends() {
+ echo dnbd3-rootfs busybox
+}
+install() {
+ # wait til we have the openslx config for ntp servers
+ # which happens in pre-mount/10
+ inst_multiple ntpdate /etc/services /usr/share/zoneinfo/Europe/Berlin
+ inst /usr/share/zoneinfo/Europe/Berlin /etc/localtime
+ inst_hook pre-mount 15 "$moddir/scripts/ntp-sync.sh"
+}
diff --git a/modules.d/slx-clock/scripts/ntp-sync.sh b/modules.d/slx-clock/scripts/ntp-sync.sh
new file mode 100755
index 00000000..887d5b13
--- /dev/null
+++ b/modules.d/slx-clock/scripts/ntp-sync.sh
@@ -0,0 +1,55 @@
+#!/bin/ash
+# Sync time via network
+
+. /etc/openslx
+
+ntp_sync() {
+ # Try to merge with servers from DHCP. Prefer DHCP, skip duplicates
+ for SERVER in $SLX_NTP_SERVER; do
+ if ! echo "$SLX_DHCP_NTP" | grep -wq "$SERVER"; then
+ SLX_DHCP_NTP="$SLX_DHCP_NTP $SERVER"
+ fi
+ done
+ local SUCCESS=
+ for SERVER in $SLX_DHCP_NTP; do
+ if ntpdate -u -p 2 "$SERVER"; then
+ echo "Successfully queried $SERVER for time."
+ if [ "x$SLX_BIOS_CLOCK" = "xlocal" ]; then
+ usleep 100000
+ hwclock -l -w || echo "... but could not set BIOS clock to localtime"
+ elif [ "x$SLX_BIOS_CLOCK" = "xutc" ]; then
+ usleep 100000
+ hwclock -u -w || echo "... but could not set BIOS clock to UTC"
+ fi
+ SUCCESS=1
+ break
+ fi
+ echo "Error querying $SERVER for current time."
+ done
+ if [ -z "$SUCCESS" ]; then
+ echo "No NTP server reachable"
+ # See if we have a timestamp in our server-config - should only be a few seconds off by now
+ if [ -n "$SLX_NOW" ] && [ "$SLX_NOW" -gt 1234567890 ]; then
+ TTS="$SLX_NOW"
+ if [ -n "$CONFIG_DOWNLOAD_TIME" ]; then
+ NOW_TIME=$(sed -r 's/^([0-9]+)\.([0-9]+).*$/\1\2/' /proc/uptime)
+ if [ "$CONFIG_DOWNLOAD_TIME" -gt 0 ] && [ "$NOW_TIME" -gt 0 ]; then
+ TTS=$(( TTS + ( NOW_TIME - CONFIG_DOWNLOAD_TIME ) / 100 ))
+ fi
+ fi
+ echo "Setting time to SLX_NOW ($SLX_NOW, corrected $TTS)"
+ date -s "@$TTS"
+ else
+ echo "No fallback option for timesync available, relying on correct RTC setup"
+ if [ "x$SLX_BIOS_CLOCK" = "xlocal" ]; then
+ # Linux defaults to RTC = UTC, so read again in this case
+ hwclock -l -s
+ fi
+ fi
+ fi
+}
+
+ntp_sync &
+
+true
+
diff --git a/modules.d/slx-dmsetup/module-setup.sh b/modules.d/slx-dmsetup/module-setup.sh
new file mode 100755
index 00000000..68e9b7b4
--- /dev/null
+++ b/modules.d/slx-dmsetup/module-setup.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+check() {
+ return 255
+}
+depends() {
+ echo "slx-tools"
+}
+install() {
+ inst "$moddir/scripts/dmsetup-slx-device" "/usr/local/bin/dmsetup-slx-device"
+
+ inst_hook pre-pivot 10 "$moddir/scripts/generate-fstab-swap.sh"
+ inst_hook pre-pivot 00 "$moddir/scripts/grow-rootfs.sh"
+ # deliberatly left ext helpers out for now, since we don't really use it.
+ inst_multiple blockdev xxd \
+ mkfs.ext4 resize2fs \
+ xfs_repair xfs_growfs
+}
+installkernel() {
+ # install those modules in case the used kernel does not have them builtin
+ instmods \
+ dm-thin-pool dm-snapshot \
+ dm-crypt crc32c xts \
+ xfs ext4
+}
diff --git a/modules.d/slx-dmsetup/scripts/dmsetup-slx-device b/modules.d/slx-dmsetup/scripts/dmsetup-slx-device
new file mode 100755
index 00000000..1756865e
--- /dev/null
+++ b/modules.d/slx-dmsetup/scripts/dmsetup-slx-device
@@ -0,0 +1,446 @@
+#!/usr/bin/env bash
+#
+# Script to back given read-only device using the block device
+# specified by SLX_WRITABLE_DEVICE_IDENTIFIER in the SLX config.
+# If SLX_WRITABLE_DEVICE_PARTITION_TABLE is sepcified, it will
+# further create device mapper devices accordingly.
+#
+# Example partition config:
+# <type> <name> <size> <crypt>
+# thin-snapshot root 10G 1
+# thin-volume tmp 20G 0
+# linear data0 5-10G 1
+# linear data1 1-50% 1
+#
+# NOTE: Encrypting thin-snapshot will actually encrypt the
+# entire pool data device used for the pool.
+# TODO: Support external keys
+
+type -p emergency_shell || . /lib/dracut-lib.sh
+
+# for debugging purposes
+set -x
+exec &> /run/openslx/dmsetup.log
+
+# read-only device to prepare for CoW
+[ -z "$1" ] && emergency_shell "Read-only device was not given!"
+declare -rg read_only_device="$1"
+declare -rg read_only_device_size="$(blockdev --getsz $1)"
+
+# global array variables storing the configuration of the partitions
+declare -ag linear snapshot thin_snapshot thin_volume
+parse_config() {
+ [ -z "$1" ] && return 1
+ while IFS= read -r line; do
+ [ -z "$line" ] && continue
+ read -r type name range crypt ignore <<< "$line"
+ type=${type//-/_} # to use the type as variable in eval
+ if ! [[ "$type" =~ \
+ ^(linear|snapshot|thin_snapshot|thin_volume)$ ]]; then
+ echo "$0: Ignoring invalid type: $line"
+ continue
+ fi
+ if [[ -z "$name" ]]; then
+ echo "$0: Ignoring nameless entry: $line"
+ continue
+ fi
+ unset unit min max
+ # ranges can be like: 40G, 40-80G, 10-20%
+ if ! [[ $range =~ ^([0-9]+-)*([0-9])+[GgMmKkBb%]$ ]]; then
+ echo "$0: Ignoring invalid range: $line"
+ continue
+ fi
+ # process ranges: convert percentages (of read_only_device!)
+ # to actual sizes (in sectors!) before saving them
+ local unit=${range: -1}
+ local min="$(cut -d'-' -f1 <<< "${range%?}" )"
+ local max="$(cut -d'-' -f2 <<< "${range%?}" )"
+ if [ "$min" -gt "$max" ]; then
+ echo "$0: Ignoring invalid range: $line"
+ continue
+ fi
+ # default for bytes
+ local -i potency=0
+ case "$unit" in
+ [%])
+ if [ "$max" -gt 100 ]; then
+ echo "Ignoring invalid percentages: $min/$max"
+ continue
+ fi
+ min=$(( $writable_device_size * $min / 100 ))
+ max=$(( $writable_device_size * $max / 100 ))
+ ;;
+ [Kk]) potency=1 ;;&
+ [Mm]) potency=2 ;;&
+ [Gg]) potency=3 ;;&
+ *)
+ # => 1024 ** potency for G, M, K, etc results in bytes
+ # => bytes / 512 = sectors
+ min=$(( $min * ( 1024 ** $potency) / 512 ))
+ max=$(( $max * ( 1024 ** $potency) / 512 ))
+ ;;
+ esac
+ if ! [[ "$crypt" =~ ^[01]$ ]]; then
+ echo "$0: Disabling encryption due to invalid crypt argument: $line"
+ crypt=0
+ fi
+ # finally save it to the global array for this type
+ eval "${type}"'+=("'${name} ${crypt} ${min} ${max}'")'
+ done <<< "$1"
+}
+
+# Helper to call 'dmsetup setup' without syncing with udev
+# and then actively create the devices with the mknodes command.
+# dmsetup_create_noudevsync <name> <table>
+dmsetup_create_noudevsync() {
+ (
+ set -o errexit
+ dmsetup create "$1" --noudevsync --table "$2"
+ dmsetup mknodes --noudevsync "$1"
+ )
+ local ret=$?
+ [ $ret -ne 0 ] && dmsetup remove --noudevsync "$1"
+ return $ret
+}
+
+# encrypt_device <dev_path> <encrypted_name> [<size>]
+encrypt_device() {
+ modprobe dm-crypt || echo "$0: dm-crypt loading failed, maybe builtin?"
+ [ -b "$1" ] || return 1
+ [ -n "$2" ] || return 1
+ [ -z "$3" ] && local size="$(blockdev --getsz $1)"
+ local key="$(head -c32 /dev/random | xxd -p | tr -d '\n')"
+ if ! dmsetup_create_noudevsync "$2" \
+ "0 ${3:-${size}} crypt aes-xts-plain64 $key 0 $1 0 1 allow_discards"; then
+ echo "$0: Failed to encrypt $1."
+ return 1
+ fi
+ return 0
+}
+# create_snapshot "<name> <persist>"
+create_snapshot() {
+ modprobe dm-snapshot || echo "$0: dm-snapshot loading failed, maybe builtin?"
+ read -r name persist ignore <<< "$1"
+ if ! dmsetup_create_noudevsync "$name" \
+ "0 $read_only_device_size snapshot $read_only_device $writable_device ${persist:-N} 8"; then
+ echo "$0: Failed to create snapshot on '$writable_device' for '$read_only_device'."
+ return 1
+ fi
+ return 0
+}
+
+# Call this to fallback to a RAMdisk stored under /run/openslx
+# This will call terminate the whole script by calling finish_setup, if successful
+ramdisk_fallback() {
+ echo "$0: Falling back to regular dm-snapshot on a RAMdisk."
+ local file="$(mktemp -u -p /run/openslx dnbd_cow.XXX)"
+ local size="$SLX_RAMDISK_SIZE_IN_MB"
+ [ -z "$size" ] && size="$(awk '/MemTotal/ {printf("%d\n", $2 / 2 / 1024 )}' /proc/meminfo)"
+ dd of="$file" seek="$size" bs=1M count=0 &> /dev/null
+ writable_device="$(losetup --show --find "$file")"
+ cow_device_candidate="root"
+ while [ -b "/dev/mapper/$cow_device_candidate" ]; do
+ cow_device_candidate="root.$RANDOM"
+ done
+ if [ -z "$writable_device" ] || ! create_snapshot "$cow_device_candidate N"; then
+ emergency_shell "CRITICAL: failed to setup RAMdisk fallback."
+ exit 1
+ fi
+ finish_setup "$cow_device_candidate" "0" "$size"
+}
+
+# finish_setup <device> <type> [<size>]
+# <device> is the device name only, /dev/mapper will be prepended automatically.
+# <type> denotes if the created device lies in a RAMdisk (0) or is backed by a disk (1).
+# <size> is given in sectors.
+finish_setup() {
+ if [ -z "$1" ] || [ ! -b "/dev/mapper/$1" ]; then
+ emergency_shell "'/dev/mapper/$1' not a block device. Failed to setup CoW layer."
+ exit 1
+ fi
+ if ! [[ "$2" =~ ^[0-9]$ ]]; then
+ emergency_shell "'$2' not a valid type, 0 or 1 expected."
+ fi
+ # <size> optional?
+ (
+ echo "# Generated by '$0'."
+ echo "SLX_DNBD3_DEVICE_COW=/dev/mapper/$1"
+ ) >> /etc/openslx
+ save_partition_info "$1" "/" "$2" "$3"
+ exit 0
+}
+
+# path to save the achieved setup to
+declare -rg partitions_config="/run/openslx/dmsetup.state"
+cat <<-EOF > "$partitions_config"
+# Generated by '$0'.
+# Format: <device_mapper_dev> <mount_point> <options>
+# Options can be:
+# * type -> CoW layer type: 0 is RAMdisk, 1 is disk, 2 is network
+# * size -> in 512 byte sectors
+EOF
+
+# save_partition_info <dm_dev> <mount_point> <type> [<size>]
+save_partition_info() {
+ [ -b "/dev/mapper/$1" ] || return 1
+ [ -n "$2" ] || return 1
+ [[ "$3" =~ ^[0-9]$ ]] || return 1
+ local opts="type=$3"
+ # plain size given
+ [[ "$4" =~ ^[0-9]+$ ]] && opts="$opts,physical_size=$4"
+ # <physical_backing_dev_size>-<virtual_size>
+ [[ "$4" =~ ^[0-9]+-[0-9]+$ ]] && opts="$opts,shared_physical_size=${4%-*},virtual_size=${4#*-}"
+ echo "/dev/mapper/$1 $2 ${opts}" >> "$partitions_config"
+}
+
+###
+## MAIN
+###
+
+. /etc/openslx
+# This is the main variable driving this script
+declare -g writable_device=
+if [ -n "$SLX_WRITABLE_DEVICE_IDENTIFIER" ]; then
+ # only first one for now TODO create linear devices of all ID44s
+ writable_device="$(slx-tools dev_find_partitions "$SLX_WRITABLE_DEVICE_IDENTIFIER" | head -n 1)"
+fi
+if [ -z "$writable_device" ]; then
+ echo "$0: Could not find writable device with id '$SLX_WRITABLE_DEVICE_IDENTIFIER'."
+ ramdisk_fallback
+fi
+
+# NOTE: from here on out, every value related to size is in 512 bytes sectors!
+declare -g writable_device_size="$(blockdev --getsz $writable_device)"
+
+# If SLX_WRITABLE_DEVICE_PARTITION_TABLE is not set, just do
+# regular thin-snapshot for the CoW layer, else parse it.
+if [ -n "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" ]; then
+ parse_config "$SLX_WRITABLE_DEVICE_PARTITION_TABLE"
+fi
+# Default to thin-snapshot, if none were configured
+if [ -z "$snapshot" ] && [ -z "$thin_snapshot" ]; then
+ parse_config "thin-snapshot root 100% 0"
+fi
+
+# Sanity checks for weird configurations
+if [ "${#snapshot[@]}" -gt 1 ]; then
+ echo "Multiple snapshots specified, using first one: ${snapshot[0]}"
+ snapshot="${snapshot[0]}"
+fi
+if [ "${#thin_snapshot[@]}" -gt 1 ]; then
+ echo "Multiple thin-snapshots specified, using first one: ${thin_snapshot[0]}"
+ thin_snapshot="${thin_snapshot[0]}"
+fi
+if [ -n "$snapshot" ] && [ -n "$thin_snapshot" ]; then
+ echo "$0: Both snapshot and thin-snapshot specified, prefering thin-snapshot."
+ snapshot=
+fi
+
+###
+## LINEAR SLICES
+###
+
+# start allocating spaces to the configured devices
+declare -g writable_device_allocated=0
+# reserve the space for the snapshot (of either type)...
+read -r name crypt min max ignore <<< "${thin_snapshot:-${snapshot}}"
+
+declare -g scratch_device_size=0
+if (( $min <= $writable_device_size )); then
+ scratch_device_size=$max
+ while (( $scratch_device_size >= 0 )) && (( $scratch_device_size > $writable_device_size )); do
+ (( scratch_device_size -= 2097152 )) # 1G steps => 2097152 sectors
+ done
+ (( $scratch_device_size < $min )) && scratch_device_size="$min"
+else
+ # minimum snapshot size is bigger than physical device size
+ echo "$0: Minimum snapshot size is too big for the scratch partition."
+ echo "$0: You probably need to use a more conservative value."
+ echo "$0: Using this client maximum scratch space ($writable_device_size sectors)."
+ scratch_device_size="$writable_device_size"
+fi
+
+# ... and slice it from the start of the writable device (for performance).
+declare -g scratch_device="/dev/mapper/scratch"
+if ! dmsetup_create_noudevsync "${scratch_device##*/}" \
+ "0 $scratch_device_size linear $writable_device $writable_device_allocated"; then
+ echo "$0: Failed to create scratch space for the CoW layer."
+ # TODO do not bail directly, but try to to create the linear devices at least?
+ ramdisk_fallback
+fi
+save_partition_info "${scratch_device##*/}" "*" "1" "$scratch_device_size"
+
+# encrypt the scratch device, if configured
+if [ "$crypt" -ne 0 ] && encrypt_device \
+ "$scratch_device" "${scratch_device##*/}-crypt" "$scratch_device_size"; then
+ scratch_device="${scratch_device}-crypt"
+fi
+
+writable_device_allocated="$scratch_device_size"
+
+# first setup linear slices of the writable device
+for i in ${!linear[@]}; do
+ [ -z "${linear[$i]}" ] && continue
+ read -r name crypt min max ignore <<< "${linear[$i]}"
+ free_space=$(( $writable_device_size - $writable_device_allocated ))
+ if [ "$min" -gt "$free_space" ]; then
+ echo "$0: Not enough space left for linear devices: ${linear[$i]}"
+ break
+ fi
+ # allocate its max if it fits within the free space, otherwise use the space left.
+ to_allocate="$max"
+ [ "$to_allocate" -gt "$free_space" ] && to_allocate="$free_space"
+
+ if ! dmsetup_create_noudevsync "$name" "0 $to_allocate linear $writable_device $writable_device_allocated"; then
+ echo "$0: Failed to create linear device: ${linear[$i]}"
+ continue
+ fi
+ # TODO sane?
+ save_partition_info "$name" "*" "1" "$to_allocate"
+ if [ "$crypt" -ne 0 ] && \
+ ! encrypt_device "/dev/mapper/$name" "${name}-crypt" "$to_allocate"; then
+ echo "$0: Failed to encrypt '$name'."
+ fi
+ writable_device_allocated=$(( $to_allocate + $writable_device_allocated ))
+done
+
+# we are done with the physical device, use the scratch space from now on
+writable_device="$scratch_device"
+writable_device_size="$scratch_device_size"
+
+###
+## THIN-PROVISIONING
+###
+declare -rg pool_metadata_dev="/dev/mapper/pool-metadata"
+declare -rg pool_data_dev="/dev/mapper/pool-data"
+declare -rg pool_dev="/dev/mapper/pool"
+create_pool() {
+ # create external snapshot for read-only device
+ # create remaining thin volumes
+ modprobe dm-thin-pool || echo "$0: dm-thin-pool load failed, maybe builtin?"
+ # create temporary metadata device
+ data_block_size=255
+ # calculate number of sectors needed and check boundaries:
+ metadata_dev_size="$(( 48 * $writable_device_size / $data_block_size / 512 ))"
+ # Min 2MB -> 4096 sectors, max 16GB -> 33554432 sectors
+ [ "$metadata_dev_size" -lt 4096 ] && metadata_dev_size="4096"
+ # TODO handle the exotic case of a too large metadata device to fit within RAM.
+ [ "$metadata_dev_size" -gt 33554432 ] && metadata_dev_size="33554432"
+ # TODO handle persistent metadata device on disk
+ # create RAMdisk in /run for metadata device
+ metadata_dev="$(mktemp -p /run/openslx .pool-metadata.XXX)"
+ dd of="$metadata_dev" bs=512 seek="$metadata_dev_size" &> /dev/null
+ metadata_dev="$(losetup --show --find $metadata_dev)"
+ if ! dmsetup_create_noudevsync "${pool_metadata_dev##*/}" \
+ "0 $metadata_dev_size linear $metadata_dev 0"; then
+ echo "$0: Failed to create pool metadata device on '$writable_device'."
+ return 1
+ fi
+ # For persistent metadata device we will need to cut that space off first:
+ # writable_device_size=$(( $writable_device_size - $metadata_dev_size ))
+
+ if ! dmsetup_create_noudevsync "${pool_data_dev##*/}" \
+ "0 $writable_device_size linear $writable_device 0"; then
+ echo "$0: Failed to create pool data device on '$writable_device'."
+ return 1
+ fi
+ low_water_mark=32
+ if ! dmsetup_create_noudevsync "${pool_dev##*/}" \
+ "0 $writable_device_size thin-pool $pool_metadata_dev $pool_data_dev $data_block_size $low_water_mark"; then
+ echo "$0: Failed to create thin-pool device on '$writable_device'."
+ return 1
+ fi
+ return 0
+}
+
+# create_volume "<name> <id> <size> <backing_dev>"
+create_volume() {
+ if [ -z "$pool_dev" -o ! -b "$pool_dev" ]; then
+ echo "$0: Global pool device not set or present."
+ return 1
+ fi
+ if [ $# -ne 1 -o -z "$1" ]; then
+ echo "$0: create_volume requires one non-empty argument."
+ return 1
+ fi
+ local name id size backing_dev ignore
+ read -r name id size backing_dev ignore <<< "$1"
+
+ if ! dmsetup message "$pool_dev" 0 "create_thin $id"; then
+ echo "$0: Failed to create thin volume with id '$id' in pool '$pool_dev'."
+ echo "$0: It might already exists, trying anyway..."
+ fi
+ if ! dmsetup_create_noudevsync "$name" "0 $size thin $pool_dev $id $backing_dev"; then
+ echo "$0: Failed to create external snapshot named '$name':"
+ echo " Size: $size"
+ echo " Backing device: $backing_dev"
+ echo " Thin volume id: $id"
+ return 1
+ fi
+ return 0
+}
+if [ -n "$thin_snapshot" ] || [ -n "$thin_volume" ]; then
+ if ! create_pool ; then
+ echo "Failed to create thin pool. Will ignore:"
+ echo -e "\tThin snapshot: $(declare -p thin_snapshot)"
+ echo -e "\tThin volumes: $(declare -p thin_volume)"
+ ramdisk_fallback
+ fi
+ # the order in which pool devices are created does not matter
+ # so start with thin volumes starting with id 2 and end with
+ # the thin-snapshot with id 1 which needs to call finish_setup.
+ volume_id=2
+ # go over thin-volumes
+ for i in ${!thin_volume[@]}; do
+ [ -z "${thin_volume[$i]}" ] && continue
+ read -r name crypt min max ignore <<< "${thin_volume[$i]}"
+ # thin-volume can be safely created with max size,
+ # since they are overprovisioned anyway.
+ if ! create_volume "$name $(( volume_id++ )) $max"; then
+ echo "Failed to create thin volume '$name'."
+ fi
+ save_partition_info "$name" "*" "1" "${writable_device_size}-${max}"
+ if [ "$crypt" -ne 0 ] && ! encrypt_device \
+ "/dev/mapper/$name" "$name-crypt" "$max"; then
+ echo "Failed to encrypt thin volume '$name'."
+ fi
+ done
+
+ if [ -n "$thin_snapshot" ]; then
+ # create thin-snapshot, use first one
+ read -r name crypt min max ignore <<< "$thin_snapshot"
+ # min/max was used for the pool data device, ignore it here!
+ # NOTE: the filesystem will most likely malfunction if the size of the
+ # thin-snapshot is smaller than what it was upon creation.
+ # As such, the size of the thin-snapshot can only be $writable_device_size
+ # if it is larger than $read_only_device_size, otherwise we should only
+ # use $read_only_device_size. While live-shrinking the filesystem might be
+ # an option, it is not supported throughout all fileystems (xfs can't).
+ if (( writable_device_size >= read_only_device_size )); then
+ thin_snapshot_size="$writable_device_size"
+ else
+ thin_snapshot_size="$read_only_device_size"
+ fi
+ if ! create_volume "$name 1 $thin_snapshot_size $read_only_device"; then
+ echo "Failed to create external snapshot for '$read_only_device'."
+ ramdisk_fallback
+ fi
+ finish_setup "$name" "1" "$thin_snapshot_size"
+ fi
+fi
+
+###
+## SNAPSHOT (OLD FUNCTIONALITY)
+###
+if [ -n "$snapshot" ]; then
+ read -r name crypt min max ignore <<< "$snapshot"
+ if ! create_snapshot "$name $persist"; then
+ echo "Failed to create regular snapshot for '$read_only_device' on '$writable_device'."
+ ramdisk_fallback
+ fi
+ finish_setup "$name" "1" "$writable_device_size"
+fi
+
+# ultimate fallback
+ramdisk_fallback
+exit 1
diff --git a/modules.d/slx-dmsetup/scripts/gen-fstab-persistent b/modules.d/slx-dmsetup/scripts/gen-fstab-persistent
new file mode 100644
index 00000000..ed00b5de
--- /dev/null
+++ b/modules.d/slx-dmsetup/scripts/gen-fstab-persistent
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+#
+# Hook to generate stage4's fstab entries for persistent partitions
+#
+# Persistent identifiers (MBR types, GPT partition labels)
+# are expected to be specified in the OpenSLX config
+# as 'SLX_PERSISTENT_DEVICE_IDENTIFIER' and their filesystem
+# as 'SLX_PERSISTENT_DEVICE_FILESYSTEM', e.g ext4 or xfs.
+# If not specified, will default to 'auto' but will not
+# active systemd's features 'x-systemd.makefs' and 'x-systemd.growfs'
+
+. /etc/openslx
+
+type -p emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+# NOTE: systemd makes the mount point path automatically.
+# if multiple exists, take the biggest one (first in the list)
+if [ -n "$SLX_PERSISTENT_DEVICE_IDENTIFIER" ]; then
+ declare -a persistent_dev_list
+ for persistent_dev in \
+ $(get_partitions_by_id ${SLX_PERSISTENT_DEVICE_IDENTIFIER//,/ /}); do
+ [ -z "$persistent_dev" ] && continue
+ persistent_dev_list+=("$persistent_dev")
+ done
+ if [ "${#persistent_dev[@]}" -gt 0 ]; then
+ if [ "${#persistent_dev[@]}" -gt 1 ]; then
+ warn "$0: More than one persistent device found."
+ warn "$0: Will use the biggest one: ${persistent_dev[0]}"
+ fi
+ persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})"
+ persistent_mount_opts="nofail"
+ if [ -n "$SLX_PERSISTENT_DEVICE_FILESYSTEM" ]; then
+ #persistent_mount_opts+=",x-systemd.requires=ensure-fs@${persistent_dev_systemd_name}"
+ persistent_mount_opts+=",x-systemd.after=ensure-fs@${persistent_dev_systemd_name}"
+ fi
+ (
+ echo -ne "${persistent_dev[0]}\t"
+ echo -ne "${SLX_PERSISTENT_DEVICE_MOUNT_POINT:-/opt/openslx/persistent}\t"
+ echo -ne "${SLX_PERSISTENT_DEVICE_FILESYSTEM:-auto}\t"
+ echo -ne "${persistent_mount_opts}\t0\t2"
+ ) >> "$NEWROOT/etc/fstab"
+
+ # drop-in to create filesystem if needed and
+ #persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})"
+ #mkdir -p "$NEWROOT/etc/systemd/system/${persistent_dev_systemd_name}"
+ #cat <<- EOF > "$NEWROOT"
+ #EOF
+ else
+ warn "$0: No device with ID '$SLX_PERSISTENT_DEVICE_IDENTIFIER' found."
+ fi
+fi
+true
diff --git a/modules.d/slx-dmsetup/scripts/generate-fstab-persistent.sh b/modules.d/slx-dmsetup/scripts/generate-fstab-persistent.sh
new file mode 100644
index 00000000..5c6f2b82
--- /dev/null
+++ b/modules.d/slx-dmsetup/scripts/generate-fstab-persistent.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+#
+# Hook to generate stage4's fstab entries for persistent partitions
+#
+# Persistent identifiers (MBR types, GPT partition labels)
+# are expected to be specified in the OpenSLX config
+# as 'SLX_PERSISTENT_DEVICE_IDENTIFIER' and their filesystem
+# as 'SLX_PERSISTENT_DEVICE_FILESYSTEM', e.g ext4 or xfs.
+# If not specified, will default to 'auto' but will not
+# active systemd's features 'x-systemd.makefs' and 'x-systemd.growfs'
+
+. /etc/openslx
+
+type -p emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh
+
+# NOTE: systemd makes the mount point path automatically.
+# if multiple exists, take the biggest one (first in the list)
+if [ -n "$SLX_PERSISTENT_DEVICE_IDENTIFIER" ]; then
+ declare -a persistent_dev_list
+ for persistent_dev in \
+ $(get-partitions-by-id ${SLX_PERSISTENT_DEVICE_IDENTIFIER//,/ /}); do
+ [ -z "$persistent_dev" ] && continue
+ persistent_dev_list+=("$persistent_dev")
+ done
+ if [ "${#persistent_dev[@]}" -gt 0 ]; then
+ if [ "${#persistent_dev[@]}" -gt 1 ]; then
+ warn "$0: More than one persistent device found."
+ warn "$0: Will use the biggest one: ${persistent_dev[0]}"
+ fi
+ persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})"
+ persistent_mount_opts="nofail"
+ if [ -n "$SLX_PERSISTENT_DEVICE_FILESYSTEM" ]; then
+ #persistent_mount_opts+=",x-systemd.requires=ensure-fs@${persistent_dev_systemd_name}"
+ persistent_mount_opts+=",x-systemd.after=ensure-fs@${persistent_dev_systemd_name}"
+ fi
+ (
+ echo -ne "${persistent_dev[0]}\t"
+ echo -ne "${SLX_PERSISTENT_DEVICE_MOUNT_POINT:-/opt/openslx/persistent}\t"
+ echo -ne "${SLX_PERSISTENT_DEVICE_FILESYSTEM:-auto}\t"
+ echo -ne "${persistent_mount_opts}\t0\t2"
+ ) >> "$NEWROOT/etc/fstab"
+
+ # drop-in to create filesystem if needed and
+ #persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})"
+ #mkdir -p "$NEWROOT/etc/systemd/system/${persistent_dev_systemd_name}"
+ #cat <<- EOF > "$NEWROOT"
+ #EOF
+ else
+ warn "$0: No device with ID '$SLX_PERSISTENT_DEVICE_IDENTIFIER' found."
+ fi
+fi
+true
diff --git a/modules.d/slx-dmsetup/scripts/generate-fstab-swap.sh b/modules.d/slx-dmsetup/scripts/generate-fstab-swap.sh
new file mode 100644
index 00000000..bb37d6cf
--- /dev/null
+++ b/modules.d/slx-dmsetup/scripts/generate-fstab-swap.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+#
+# Script to create stage4's fstab entry for swap devices
+#
+# Will use swap partitions of MBR's type '82' or
+# GPT UUID '0657fd6d-a4ab-43c4-84e5-0933c84b4f4f'
+#
+. /etc/openslx
+
+for swap_dev in \
+ $(slx-tools dev_find_partitions "82" "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f"); do
+
+ [ -z "$swap_dev" ] && continue
+
+ # Generate swap fstab entry for NEWROOT. Use priority 10 to prefer zram
+ echo -e "$swap_dev\tswap\t\tswap\t\tx-systemd.makefs,pri=10\t0\t0" \
+ >> "$NEWROOT/etc/fstab"
+
+ # check if configured not to wipe any existing filesystem
+ [ "$SLX_WIPE_SWAP_DEVICE" = "yes" ] || continue
+
+ # create a drop-in to wipe the device's filesystem
+ swap_dev_systemd_escaped="$(tr '/' '-' <<< ${swap_dev:1})"
+ base_dir="$NEWROOT/etc/systemd/system"
+ dropin_dir="$base_dir/systemd-mkswap@${swap_dev_systemd_escaped}.service.d"
+ mkdir -p "$dropin_dir"
+ cat <<- EOF > "$dropin_dir/wipefs.conf"
+ [Service]
+ ExecStartPre=/sbin/wipefs -a %f
+ EOF
+done
+
+true
diff --git a/modules.d/slx-dmsetup/scripts/get-partitions-by-id b/modules.d/slx-dmsetup/scripts/get-partitions-by-id
new file mode 100755
index 00000000..2fe5ce7a
--- /dev/null
+++ b/modules.d/slx-dmsetup/scripts/get-partitions-by-id
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+#
+# Get all partitions with given ids (list of /dev/sdXX)
+# Examples of supported ID types:
+# * MBR's type: 44
+# * GPT's UUID: 0657fd6d-a4ab-43c4-84e5-0933c84b4f4f (swap)
+# * GPT's Name: OpenSLX-ID44
+#
+# First argument can be a block device to limit the search to
+# partitions thereof, e.g. for /dev/loop0 to look for /dev/loop0pX
+#
+# NOTE: for compatibility reasons, MBR's type will also
+# be matched against part name 'OpenSLX-ID<id>'.
+# The output will be a list of matching devices,
+# sorted from largest to smallest.
+get_partitions_by_id () {
+ local ID dev exp target
+ exp=
+ # target for the scan, defaults to /dev to check everything
+ target=/dev
+ if [ -b "$1" ]; then
+ target="$1"'*'
+ shift
+ fi
+ # support commas and pipes to separate identifiers
+ local args=$@
+ set -- ${args//[,|]/ }
+ while [ $# -gt 0 ]; do
+ ID=$1
+ shift
+ [ -z "$ID" ] && continue
+ # if single digit, e.g. 7, look for 0x7 and 0x07
+ [[ $ID =~ ^[0-9]$ ]] && ID="0?$ID"
+ if [[ $ID =~ ^[0-9]{2}$ ]]; then
+ # if double digit look for MBR types and OpenSLX-ID$ID GPT labels
+ exp="$exp|ID_PART_ENTRY_(NAME=OpenSLX-ID|TYPE=0x)$ID"
+ elif [[ $ID =~ ^(0x[0-9]{2}|[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})$ ]]; then
+ # if full MBR type (e.g. 0x44) or UUID look for TYPE
+ exp="$exp|ID_PART_ENTRY_TYPE=$ID"
+ else
+ # something else, look for names of partitions / filesystems
+ exp="$exp|ID_(PART_ENTRY_NAME|FS_LABEL)=$ID"
+ fi
+ done
+ exp=${exp:1}
+ #echo "Partition find is '$exp'" >&2
+ for dev in $(find $target -type b); do
+ udevadm info --name="$dev" | grep -iqE "($exp)\$" \
+ && echo "$(blockdev --getsize64 "$dev") $dev"
+ done | sort -n -k1 -r | cut -d' ' -f2
+}
+
+## MAIN
+if [ $# -eq 0 ]; then
+ echo "$0 needs at least one argument."
+ exit 1
+fi
+
+get_partitions_by_id $@
+
diff --git a/modules.d/slx-dmsetup/scripts/grow-rootfs.sh b/modules.d/slx-dmsetup/scripts/grow-rootfs.sh
new file mode 100644
index 00000000..e2603835
--- /dev/null
+++ b/modules.d/slx-dmsetup/scripts/grow-rootfs.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# This tried to call growfs helpers (xfs_growfs, resize2fs, ...) to resize
+# the root filesystem mounted on $NEWROOT to the maximum size of the backing
+# disk partition (done by dmsetup-slx-device).
+
+. /etc/openslx
+
+declare -Ag growfs_helpers growfs_targets growfs_opts
+# xfs
+growfs_helpers[xfs]="xfs_growfs"
+growfs_targets[xfs]="$NEWROOT"
+growfs_opts[xfs]="-d"
+# ext4
+growfs_helpers[ext4]="resize2fs"
+growfs_targets[ext4]="$SLX_DNBD3_DEVICE_COW"
+growfs_opts[ext4]=""
+
+resize_rootfs() {
+ # First let's check what filesystem it is
+ local fstype="$(blkid "$SLX_DNBD3_DEVICE_COW" | grep -oE 'TYPE=\S+')"
+ if [ -z "$fstype" ]; then
+ echo "Failed to detect filesystem on '$SLX_DNBD3_DEVICE_COW' - ignoring."
+ return 1
+ fi
+ fstype="${fstype#TYPE=}"
+ fstype="${fstype//\"/}"
+ if [ ! "${growfs_helpers[${fstype}]+set}" ]; then
+ echo "'$fstype' not supported - ignoring."
+ return 1
+ fi
+ if ! hash "${growfs_helpers[${fstype}]}" &> /dev/null; then
+ echo "'$fstype' is supported, but cannot find helper binary - ignoring."
+ return 1
+ fi
+ if ! "${growfs_helpers[${fstype}]}" ${growfs_opts[$fstype]} "${growfs_targets[$fstype]}"; then
+ echo "Failed to run '${growfs_helpers[${fstype}]}' on '${growfs_targets[$fstype]}'."
+ return 1
+ fi
+ return 0
+} &> /run/openslx/rootfs-grow.log
+
+[ -b "$SLX_DNBD3_DEVICE_COW" ] && resize_rootfs
+# non-critical, so always fake success
+true
diff --git a/modules.d/slx-drm/hooks/activate-nvidia-drivers.sh b/modules.d/slx-drm/hooks/activate-nvidia-drivers.sh
new file mode 100644
index 00000000..5c9310e8
--- /dev/null
+++ b/modules.d/slx-drm/hooks/activate-nvidia-drivers.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+type emergency_shell >/dev/null 2>&1 || . /lib/dracut-lib.sh
+
+detect_nvidia_cards() {
+ # hard check on nvidia graphic cards
+ local cards="$(lspci | grep 'Class 0300: 10de:' | awk '{print $4}')"
+ if ! [ -d "/drm.cfg.d" ] && [ -n $cards ]; then
+ warn "Failed to find '/drm.cfg.d' or nvidia cards."
+ return 1
+ fi
+ for card in $cards; do
+ local driver="$(awk '$1 = /'"$card"'/ {print $2}' /drm.cfg.d/*)"
+ [ -z "$driver" ] && continue
+ driver="${driver//@/}"
+ driver="${driver//-/\/}"
+ local driver_dir="/lib/modules/${driver}"
+ [ -d "$driver_dir" ] || continue
+ local driver_target="/lib/modules/$(uname -r)/kernel/drivers/gpu/drm/nvidia"
+ if [ -d "$driver_target" ]; then
+ warn "'$driver_target' exists, will not overwrite!"
+ return 1
+ fi
+ # all good, move it over
+ if ! mv "$driver_dir" "$driver_target" 2>&1; then
+ warn "Failed to move '$driver_dir' to '$driver_target'."
+ return 1
+ fi
+ # finally run depmod to make it visible to udev
+ if ! depmod -a 2>&1 ; then
+ warn "Failed to run depmod, udev won't see the nvidia modules."
+ return 1
+ fi
+ # blacklist nouveau
+ echo 'blacklist nouveau' > "/lib/modprobe.d/disable-nouveau.conf"
+ info "Initialized nvidia drivers."
+ return 0
+ done
+}
+
+detect_nvidia_cards
+:
diff --git a/modules.d/slx-drm/hooks/copy-nvidia-drivers.sh b/modules.d/slx-drm/hooks/copy-nvidia-drivers.sh
new file mode 100644
index 00000000..323af6d2
--- /dev/null
+++ b/modules.d/slx-drm/hooks/copy-nvidia-drivers.sh
@@ -0,0 +1,28 @@
+#!/bin/ash
+#
+# This script checks whether the nvidia kernel module was loaded by udev
+# and copies the kernel modules over to stage4 and disables nouveau
+
+type emergency_shell >/dev/null 2>&1 || . /lib/dracut-lib.sh
+
+copy_nvidia_modules() {
+ local nvidia_moddir="/lib/modules/$(uname -r)/kernel/drivers/gpu/drm/nvidia"
+ if [ -d "${NEWROOT}/${nvidia_moddir}" ]; then
+ warn "Stage4 contains nvidia driver which would be overwritten - skipping."
+ return 1
+ fi
+ if ! ( cp -r "$nvidia_moddir" "${NEWROOT}/${nvidia_moddir}" \
+ && depmod -a -b "$NEWROOT" ); then
+ warn "Failed to copy/depmod nvidia modules to stage4."
+ return 1
+ fi
+ # nouveau driver would needlessly load, prevent that
+ mkdir -p "${NEWROOT}/etc/modprobe.d" # cause why not
+ echo "blacklist nouveau" > "${NEWROOT}/etc/modprobe.d/disable-nouveau.conf"
+ return 0
+}
+
+if lsmod | grep -q nvidia; then
+ copy_nvidia_modules
+fi
+: # fake success
diff --git a/modules.d/slx-drm/module-setup.sh b/modules.d/slx-drm/module-setup.sh
new file mode 100755
index 00000000..4baa5b2a
--- /dev/null
+++ b/modules.d/slx-drm/module-setup.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+check() {
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ return 255
+}
+depends() {
+ echo drm
+}
+installkernel() {
+ instmods acpi_ipmi
+}
+install() {
+ # grab what mltk produced, to externalize this part!
+ for dir in "/drm.cfg.d" "/lib/modules/nvidia"; do
+ [ -d "$dir" ] || continue
+ mkdir -p "${initdir}/${dir%/*}"
+ cp -ar "$dir" "${initdir}/${dir%/*}"
+ done
+ inst_hook pre-udev 10 "${moddir}/hooks/activate-nvidia-drivers.sh"
+ inst_hook pre-pivot 50 "${moddir}/hooks/copy-nvidia-drivers.sh"
+}
diff --git a/modules.d/slx-network/TODO b/modules.d/slx-network/TODO
new file mode 100644
index 00000000..bd119512
--- /dev/null
+++ b/modules.d/slx-network/TODO
@@ -0,0 +1 @@
+# autostart dhcp in stage4
diff --git a/modules.d/slx-network/hooks/activate-bootif-dhcp.sh b/modules.d/slx-network/hooks/activate-bootif-dhcp.sh
new file mode 100644
index 00000000..f5345c61
--- /dev/null
+++ b/modules.d/slx-network/hooks/activate-bootif-dhcp.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# This script configures the udhcpc-based DHCP service for
+# within stage4, unless specifically disabled by SLX_STAGE4_DHCP
+
+. /etc/openslx
+[ -n "$SLX_STAGE4_DHCP" ] || exit 0
+
+for script in setup-bootif-network udhcpc-trigger; do
+ if [ -e "${NEWROOT}/opt/openslx/scripts/${script}" ]; then
+ mv "${NEWROOT}/opt/openslx/scripts/${script}"{,.stage4}
+ fi
+ cp -f "/opt/openslx/scripts/${script}.stage4" \
+ "${NEWROOT}/opt/openslx/scripts/${script}"
+done
+
+# copy udhcpc@ systemd service, backup existing ones for debugging
+mkdir -p "${NEWROOT}/etc/systemd/system"
+cp -f "/opt/openslx/services/udhcpc-bootif.service" "${NEWROOT}/etc/systemd/system"
+
+# it requires /run/network
+echo 'd /run/network 0755 root root' > "${NEWROOT}/etc/tmpfiles.d/network.conf"
+
+# activate it for the bridge or the physical interface if not bridged
+systemctl --quiet --root "$NEWROOT" enable "udhcpc-bootif"
+
diff --git a/modules.d/slx-network/hooks/copy-network-files.sh b/modules.d/slx-network/hooks/copy-network-files.sh
new file mode 100644
index 00000000..d1dd48d1
--- /dev/null
+++ b/modules.d/slx-network/hooks/copy-network-files.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+type -p warn &> /dev/null || . /lib/dracut-lib.sh
+
+if [ -n "$NEWROOT" ]; then
+ # backup network configuration files found in stage4
+ for file in /etc/{hostname,hosts,resolv.conf}; do
+ if [ ! -e "$file" ]; then
+ warn "Missing '$file' - won't move it to stage4. "
+ continue
+ fi
+ if [ -e "${NEWROOT}/${file}" ] || [ -h "${NEWROOT}/${file}" ]; then
+ mv "${NEWROOT}/${file}" "${NEWROOT}/${file}.stage4"
+ fi
+ cp -af "$file" "${NEWROOT}/etc"
+ done
+ # special handling for resolv.conf:
+ # move it to /opt/openslx to detect we are managing it
+ mkdir -p "${NEWROOT}/opt/openslx"
+ mv "${NEWROOT}/etc/resolv.conf" "${NEWROOT}/opt/openslx/resolv.conf"
+ ln -s "/opt/openslx/resolv.conf" "${NEWROOT}/etc/resolv.conf"
+
+ # HACK: finally make sure we have rdns helper
+ # This should be done more elegantly one day...
+ rdns="$(type -p rdns)"
+ if [ -n "$rdns" ]; then
+ mkdir -p "${NEWROOT}/opt/openslx/bin"
+ cp -f "$rdns" "${NEWROOT}/opt/openslx/bin"
+ fi
+fi
+true
diff --git a/modules.d/slx-network/hooks/parse-ipxe-network-kcl.sh b/modules.d/slx-network/hooks/parse-ipxe-network-kcl.sh
new file mode 100644
index 00000000..56abb680
--- /dev/null
+++ b/modules.d/slx-network/hooks/parse-ipxe-network-kcl.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+#
+# TODO VLAN support
+
+command -v getarg >/dev/null || . /lib/dracut-lib.sh
+
+# static names for the boot interface and its bridge
+declare -rg BOOTIF_NAME="boot0"
+declare -rg BRIDGE_NAME="br0"
+declare -rg RUNTIME_CONF="/run/openslx/network.conf"
+mkdir -p "${RUNTIME_CONF%/*}"
+# Get all the ip-related arguments from the KCL
+parse_kernel_command_line() {
+ ## KCL "BOOTIF": MAC address of the interface that DHCP'ed during PXE
+ declare -g BOOTIF="$(getarg BOOTIF=)"
+ # Remove the hardware type prefix of BOOTIF if it has 20 chars to get
+ # the plain MAC address. The hardware type prefix has length 3, e.g. "01-".
+ if [ -n "${BOOTIF}" ] && [ ${#BOOTIF} -eq 20 ]; then
+ BOOTIF="${BOOTIF#???}"
+ BOOTIF="${BOOTIF//-/:}"
+ fi
+ readonly BOOTIF
+
+ ## KCL "ip": is expected in following format (syslinux IPAPPEND3):
+ declare -rg IPCONF="$(getarg ip=)"
+ # <CLIENT_IP>:<PXE_SERVER_IP>:<GATEWAY_IP>:<NETMASK>
+ declare -g CLIENT_IP=
+ declare -g SERVER_IP=
+ declare -g GATEWAY_IP=
+ declare -g NETMASK=
+ read -r CLIENT_IP SERVER_IP GATEWAY_IP NETMASK \
+ <<< $( awk -F: '{print $1" "$2" "$3" "$4}' <<< "${IPCONF}" )
+ readonly CLIENT_IP SERVER_IP GATEWAY_IP NETMASK
+
+ # Calculate routing prefix from netmask
+ declare -rg ROUTING_PREFIX="$(ipcalc -s -p "$CLIENT_IP" "$NETMASK")"
+
+ # KCL "hostname"
+ declare -rg HOSTNAME="$(getarg hostname=)"
+ [ -n "$HOSTNAME" ] && echo "$HOSTNAME" > /proc/sys/kernel/hostname
+
+ # KCL "dns"
+ declare -rg DNS="$(getarg dns=)"
+
+ # KCL "domain"
+ declare -rg DOMAIN="$(getarg domain=)"
+
+ # VLAN tag
+ declare -rg VLAN="$(getarg vlan=)"
+ if [ -n "$VLAN" ]; then
+ modprobe 8021q || warn "VLAN mode detected but failed to load 8021q!"
+ fi
+
+ # Bridged mode?
+ grep -wqE 'bridged' /proc/cmdline && declare -rg BRIDGED="y"
+}
+
+save_network_config() {
+ cat <<-EOF > "${RUNTIME_CONF}"
+ SLX_PXE_CLIENT_IP='${CLIENT_IP}'
+ SLX_PXE_SERVER_IP='${SERVER_IP}'
+ SLX_PXE_GATEWAY='${GATEWAY_IP}'
+ SLX_PXE_NETMASK='${NETMASK}'
+ SLX_PXE_MAC='${BOOTIF}'
+ SLX_PXE_NETIF='${BOOTIF_NAME}'
+ SLX_PXE_DNS='${DNS}'
+ SLX_PXE_HOSTNAME='${HOSTNAME}'
+ SLX_PXE_DOMAIN='${DOMAIN}'
+ SLX_BRIDGE='${BRIDGED:+${BRIDGE_NAME}}'
+ SLX_VLAN_ID='${VLAN}'
+ EOF
+}
+
+# Create udev rule to rename the PXE boot interface to BOOTIF_NAME
+create_udev_bootif_name_rule() {
+ if [ -z "${BOOTIF}" ]; then
+ echo "No BOOTIF set, was it present in the kernel command line?"
+ return 1
+ fi
+ # priority 70 < 80-net-name-slot.rules.
+ echo 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="'${BOOTIF}'", NAME="'${BOOTIF_NAME}'"' > /etc/udev/rules.d/70-pxe-boot-interface.rules
+}
+
+## MAIN ##
+# Get IP config from KCL
+parse_kernel_command_line
+
+# Save network config for later use
+save_network_config &
+
+# Create the udev rule to rename the boot interface to the declared BOOTIF_NAME
+create_udev_bootif_name_rule &
+
+/sbin/initqueue --settled /usr/local/bin/setup-bootif-network
+/sbin/initqueue --finished [ -e "/.network" ]
diff --git a/modules.d/slx-network/module-setup.sh b/modules.d/slx-network/module-setup.sh
new file mode 100755
index 00000000..df95bfee
--- /dev/null
+++ b/modules.d/slx-network/module-setup.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+check() {
+ [[ $mount_needs ]] && return 1
+
+ if dracut_module_included "network" || dracut_module_included "systemd-networkd" ; then
+ derror "This module conflicts with 'network' and 'systemd-networkd'!"
+ return 1
+ fi
+ return 255
+}
+
+# called by dracut
+depends() {
+ echo "busybox kernel-network-modules"
+}
+
+# called by dracut
+install() {
+ # need initqueue to get a clean network start
+ dracut_need_initqueue
+
+ # install basic dns libs
+ _arch=$(uname -m)
+ inst_libdir_file {"tls/$_arch/",tls/,"$_arch/",}"libnss_dns.so.*"
+
+ # stage3 network scripts
+ inst "${moddir}/scripts/setup-bootif-network.stage3" "/usr/local/bin/setup-bootif-network"
+ inst "${moddir}/scripts/udhcpc-trigger.stage3" "/usr/local/bin/udhcpc-trigger"
+
+ # files for stage4, park them in /opt/openslx
+ gcc -o "${initdir}/usr/local/bin/rdns" "${moddir}/rdns.c"
+ inst "${moddir}/scripts/setup-bootif-network.stage4" "/opt/openslx/scripts/setup-bootif-network.stage4"
+ inst "${moddir}/scripts/udhcpc-trigger.stage4" "/opt/openslx/scripts/udhcpc-trigger.stage4"
+ inst "${moddir}/services/udhcpc-bootif.service" "/opt/openslx/services/udhcpc-bootif.service"
+
+ # hooks
+ inst_hook cmdline 10 "${moddir}/hooks/parse-ipxe-network-kcl.sh"
+ inst_hook pre-pivot 50 "${moddir}/hooks/copy-network-files.sh"
+ inst_hook pre-pivot 60 "${moddir}/hooks/activate-bootif-dhcp.sh"
+}
diff --git a/modules.d/slx-network/rdns.c b/modules.d/slx-network/rdns.c
new file mode 100644
index 00000000..218f7400
--- /dev/null
+++ b/modules.d/slx-network/rdns.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ fprintf(stderr,"usage: %s <IPADDRESS>\n", argv[0]);
+ return 1;
+ }
+
+ struct hostent *he;
+ struct in_addr ipv4addr;
+ struct in6_addr ipv6addr;
+
+ inet_pton(AF_INET, argv[1], &ipv4addr);
+ he = gethostbyaddr(&ipv4addr, sizeof ipv4addr, AF_INET);
+ if (he == NULL) return 2;
+ if (he->h_name == NULL) return 3;
+ printf("%s\n", he->h_name);
+
+ return 0;
+}
+
diff --git a/modules.d/slx-network/scripts/setup-bootif-network.stage3 b/modules.d/slx-network/scripts/setup-bootif-network.stage3
new file mode 100755
index 00000000..53ad8de9
--- /dev/null
+++ b/modules.d/slx-network/scripts/setup-bootif-network.stage3
@@ -0,0 +1,112 @@
+#!/bin/bash
+#
+# This script sets up the main network interface we booted from,
+# as designated by SLX_PXE_NETIF (parsed from the PXE KCL in the
+# cmdline dracut hook).
+# It is run inside dracut's initqueue, on settles to detect the
+# physical network interface as fast as possible.
+
+type emergency_shell >/dev/null 2>&1 || . /lib/dracut-lib.sh
+
+. /run/openslx/network.conf
+
+# guard to not run until the phsyical interface is not ready yet
+if [ ! -e "/sys/class/net/${SLX_PXE_NETIF}/device" ]; then
+ exit 1
+fi
+
+wait_for_iface() {
+ local _iface="$1"
+ local _timeout="${2:-50}"
+ while [ "$_timeout" -ne 0 ]; do
+ [ "$(cat /sys/class/net/${_iface}/operstate)" = "up" ] && break
+ (( _timeout -- ))
+ usleep 100000
+ done
+ [ "$_timeout" -ne 0 ]
+}
+
+# For debugging...
+{
+set -x
+
+ip link set dev "$SLX_PXE_NETIF" up
+if ! wait_for_iface "$SLX_PXE_NETIF" 300; then
+ warn "'$SLX_PXE_NETIF' still not up after 30sec ... trying anyway."
+ # TODO handle case where we waited for 30sec and it is still not up
+fi
+
+# now determine whether we are in bridged/vlan/plain mode
+MAIN_NETIF="$SLX_PXE_NETIF"
+if [ -n "$SLX_VLAN_ID" ]; then
+ # create VLAN interface
+ modprobe 8021q || warn "Loading '8021q' failed - missing module?"
+ ip link add link "$SLX_PXE_NETIF" name "${SLX_PXE_NETIF}.${SLX_VLAN_ID}" \
+ type vlan id "$SLX_VLAN_ID"
+ ip link set dev "${SLX_PXE_NETIF}.${SLX_VLAN_ID}" up
+ if wait_for_iface "${SLX_PXE_NETIF}.${SLX_VLAN_ID}"; then
+ MAIN_NETIF="${SLX_PXE_NETIF}.${SLX_VLAN_ID}"
+ else
+ warn "Setting up VLAN '$SLX_VLAN_ID' failed, trying plain..."
+ fi
+fi
+
+if [ -n "$SLX_BRIDGE" ]; then
+ for try in {1..10} ""; do
+ (
+ set -e
+ brctl addbr "$SLX_BRIDGE"
+ brctl stp "$SLX_BRIDGE" 0
+ brctl setfd "$SLX_BRIDGE" 0.000000000001
+ ip link set addr "$SLX_PXE_MAC" "$SLX_BRIDGE"
+ brctl addif "$SLX_BRIDGE" "$MAIN_NETIF"
+ ip link set dev "$SLX_BRIDGE" up
+ wait_for_iface "$SLX_BRIDGE"
+ )
+ # success?
+ if [ "$?" -eq 0 ]; then
+ MAIN_NETIF="$SLX_BRIDGE"
+ break
+ fi
+
+ # nope, handle
+ if [ -z "$try" ]; then
+ emergency_shell "Failed to setup main network bridge, giving up!"
+ fi
+ warn "Failed to setup main network bridge on try $try. Retrying ..."
+ # delete bridge, inc try and sleep 100ms before trying again
+ [ -e "/sys/class/net/${SLX_BRIDGE}" ] && brctl delbr "$SLX_BRIDGE"
+ usleep 100000
+ done
+fi
+
+# finally add the IP address on the main NIC
+if [ -n "$SLX_PXE_CLIENT_IP" ]; then
+ ip addr add \
+ "${SLX_PXE_CLIENT_IP}/$(ipcalc -s -p "$SLX_PXE_CLIENT_IP" "$SLX_PXE_NETMASK" | sed "s/.*=//")" \
+ broadcast "$(ipcalc -s -b "$SLX_PXE_CLIENT_IP" "$SLX_PXE_NETMASK" | sed "s/.*=//")" \
+ dev "$MAIN_NETIF"
+fi
+
+if [ "$USE_DHCP_UUID" = "yes" ] && [ -s "/run/system-uuid" ]; then
+ UUID="$(cat /run/system-uuid)"
+fi
+
+# udhcpc
+for i in 1 1 1 fail; do
+ [ "$i" = "fail" ] && emergency_shell "DHCP failed 3 times... cannot continue."
+ udhcpc -t 4 -T 3 -f -n -q \
+ -i "${MAIN_NETIF}" \
+ "${SLX_PXE_CLIENT_IP:+-r $SLX_PXE_CLIENT_IP}" \
+ "${UUID:+-x 0x3d:$UUID}" \
+ -O ntpsrv -O domain -O wpad -O search -O nisdomain \
+ -s "/usr/local/bin/udhcpc-trigger"
+ # success?
+ [ "$?" -eq 0 ] && break
+ # nope, keep trying...
+ warn "DHCP failed, retrying in 1sec..."
+ sleep $i
+done
+
+set +x
+} &>> "/run/openslx/initramfs-network.log.$$"
diff --git a/modules.d/slx-network/scripts/setup-bootif-network.stage4 b/modules.d/slx-network/scripts/setup-bootif-network.stage4
new file mode 100755
index 00000000..61f925d0
--- /dev/null
+++ b/modules.d/slx-network/scripts/setup-bootif-network.stage4
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# This script sets up the main network interface we booted from,
+# as designated by SLX_PXE_NETIF in /opt/openslx/config
+# It will run on either the bridge (SLX_BRIDGE is set) or the
+# physical interface directly.
+
+export PATH=$PATH:/opt/openslx/sbin:/opt/openslx/bin
+
+. /opt/openslx/config
+
+if [ -z "$SLX_PXE_NETIF" ]; then
+ echo "Missing network information of the main boot interface."
+ exit 1
+fi
+
+MAIN_NETIF="$SLX_PXE_NETIF"
+[ -n "$SLX_VLAN_ID" ] && MAIN_NETIF="${SLX_PXE_NETIF}.${SLX_VLAN_ID}"
+[ -n "$SLX_BRIDGE" ] && MAIN_NETIF="${SLX_BRIDGE}"
+readonly MAIN_NETIF
+
+# set default options
+declare -a udhcpc_opts
+udhcpc_opts+=("-t" "8")
+udhcpc_opts+=("-O" "domain")
+udhcpc_opts+=("-O" "nissrv")
+udhcpc_opts+=("-O" "nisdomain")
+udhcpc_opts+=("-O" "wpad")
+udhcpc_opts+=("-O" "search")
+udhcpc_opts+=("-O" "wins")
+
+# send machine uuid during DHCP if configured
+if [ "$SLX_NET_DHCP_UUID" = "yes" ]; then
+ uid=$(dmidecode -s system-uuid | \
+ sed -r 's/^(..)(..)(..)(..)-(..)(..)-(..)(..)-(....)-/00\4\3\2\1\6\5\8\7\9/')
+ if [ "${#uid}" = 34 ]; then
+ echo "Using SMBIOS uid for DHCP"
+ udhcpc_opts+=( "-x" "0x3d:$uid" )
+ fi
+fi
+
+mkdir -p /run/udhcpc || echo "Could not create '/run/udhcpc'."
+
+udhcpc "${udhcpc_opts[@]}" \
+ -i "$MAIN_NETIF" \
+ -r "${SLX_PXE_CLIENT_IP}" \
+ -s /opt/openslx/scripts/udhcpc-trigger \
+ -p "/run/udhcpc/udhcpc.${MAIN_NETIF}.pid"
+ret=$?
+
+if [ "${ret}" != 0 ]; then
+ echo "udhcpc" "Could not run 'udhcpc ${udhcpc_opts[*]}' on ${MAIN_NETIF}."
+fi
+
+exit "${ret}"
+
diff --git a/modules.d/slx-network/scripts/udhcpc-trigger.stage3 b/modules.d/slx-network/scripts/udhcpc-trigger.stage3
new file mode 100755
index 00000000..d54939a8
--- /dev/null
+++ b/modules.d/slx-network/scripts/udhcpc-trigger.stage3
@@ -0,0 +1,140 @@
+#!/bin/bash
+#
+# This script is triggered by udhcpc in stage3 and handle the
+# DHCP information given as parameters
+
+{
+# for debugging
+set -x
+NETWORK_CONF="/run/openslx/network.conf"
+. "$NETWORK_CONF"
+
+MAIN_NETIF="$SLX_PXE_NETIF"
+[ -n "$SLX_VLAN_ID" ] && MAIN_NETIF="${SLX_PXE_NETIF}.${SLX_VLAN_ID}"
+[ -n "$SLX_BRIDGE" ] && MAIN_NETIF="$SLX_BRIDGE"
+readonly MAIN_NETIF
+
+if [ "x$1" != "xbound" -a "x$1" != "xrenew" ] \
+ || [ "x$interface" != "x${MAIN_NETIF}" ] \
+ || [ -z "$ip" ]; then
+ exit 0
+fi
+
+##
+## CORE NETWORK CONFIGURATION
+##
+## > IP, subnet, route
+
+# If we already got an IP from KCL, see if it differs, and remove first if so
+# We just try to prevent everything from breaking if the DHCP server doesn't
+# objey the renew request by the client and hands out a new address
+if [ -n "$SLX_PXE_CLIENT_IP" ]; then
+ #...some address is already configured...
+ if [ "x${SLX_PXE_CLIENT_IP}" != "x${ip}" ]; then
+ #...it's a different one, reconfigure...
+ echo "..reconfiguring ${SLX_PXE_CLIENT_IP} to ${ip}.."
+ # remove default route and let it be added again below, as it might get lost when changing the primary address on the interface
+ ip route del default 2>/dev/null
+ ip addr del "$SLX_PXE_CLIENT_IP" dev "${interface}" 2>/dev/null
+ ip addr add "${ip}/$(ipcalc -s -p "${ip}" "${subnet}" | sed s/.*=//)" dev "${interface}"
+ fi
+else
+ #...no address configured yet, just add...
+ echo "..adding ${ip}.."
+ ip addr add "${ip}/$(ipcalc -s -p "${ip}" "${subnet}" | sed s/.*=//)" dev "${interface}"
+fi
+echo "SLX_DHCP_CLIENT_IP='$ip'" >> "$NETWORK_CONF"
+
+# Same procedure for default gateway
+if [ -n "${router}" ]; then
+ if [ -s "$SLX_PXE_GATEWAY" ]; then
+ if [ "x${SLX_PXE_GATEWAY}" != "x${router}" ]; then
+ echo "..reconfiguring default gw from ${SLX_PXE_GATEWAY} to ${router}.."
+ ip route replace default via "$router"
+ fi
+ else
+ ip route add default via "$router"
+ fi
+ echo "SLX_DHCP_GATEWAY='$router'" >> "$NETWORK_CONF"
+fi
+
+##
+## ADDITIONAL NETWORK CONFIGURATION
+##
+## > DNS, domain, hostname
+
+rm -f -- "/etc/resolv.conf"
+
+# DNS/domain?
+if [ -n "$dns" ]; then
+ echo "..got DNS.."
+ echo "# From DHCP in stage 3.1" >> "$NETWORK_CONF"
+ echo "SLX_DNS='$dns'" >> "$NETWORK_CONF"
+fi
+for srv in $dns; do
+ echo "nameserver $srv" >> "/etc/resolv.conf"
+done
+if [ -z "$domain" ]; then
+ # try to get domain via reverse lookup if empty
+ echo "..trying to get domain via DNS, as DHCP didn't supply one.."
+ fqdn=$(timeout -t 3 nslookup "$ip" | grep -E "^Address +[0-9]+: +$ip " | head -n 1 | awk '{print $4}')
+ domain="${fqdn#*.}"
+fi
+# Add domain to list of search domains if not in there yet
+if [ -n "$domain" ] && [ -n "$search" ]; then
+ FOUND=no
+ for sd in $search; do
+ [ "x$sd" = "x$domain" ] && FOUND=yes
+ done
+ [ "$FOUND" = "no" ] && search="$domain $search"
+elif [ -n "$domain" ]; then
+ search="$domain"
+fi
+# Write out
+if [ -n "$domain" ]; then
+ echo "domain $domain" >> "/etc/resolv.conf"
+ echo "SLX_NET_DOMAIN='$domain'" >> "/run/openslx/network.conf"
+fi
+if [ -n "$search" ]; then
+ echo "search $search" >> "/etc/resolv.conf"
+ echo "SLX_NET_SEARCH='$search'" >> "/run/openslx/network.conf"
+fi
+
+if [ -n "$ntpsrv" ]; then
+ echo "SLX_DHCP_NTP='$ntpsrv'" >> "/run/openslx/network.conf"
+fi
+
+# Hostname
+# Ignore hostname/fqdn it if hostname was forced per KCL.
+if [ -n "$SLX_PXE_HOSTNAME" ]; then
+ echo "Hostname set via KCL, ignoring DHCP hostname: '$hostname'"
+ hostname="$SLX_PXE_HOSTNAME"
+else
+ if [ -z "$hostname" ]; then
+ # as with domain, if there's no hostname, try to get via DNS
+ echo "..trying to get hostname via DNS, as DHCP didn't supply one.."
+ [ -z "$fqdn" ] && fqdn=$(timeout -t 3 nslookup "$ip" | grep -E "^Address +[0-9]+: +$ip " | head -n 1 | awk '{print $4}')
+ hostname="${fqdn%%.*}"
+ elif [ -n "$domain" ]; then
+ fqdn="${hostname}.${domain%% *}" # in case domain is a list
+ fi
+fi
+
+if [ -z "$hostname" ]; then
+ # no fallback hostname from DNS, use IP address
+ hostname="${ip//./-}"
+fi
+
+if [ -n "$hostname" ]; then
+ [ -z "$fqdn" ] && fqdn="$hostname"
+ echo "..setting hostname $hostname (fqdn: $fqdn).."
+ echo "$hostname" > "/proc/sys/kernel/hostname"
+ echo "$hostname" > "/etc/hostname"
+ echo "127.0.0.1 localhost" > "/etc/hosts"
+ echo "127.0.1.1 $fqdn $hostname" >> "/etc/hosts"
+ echo "SLX_HOSTNAME='$hostname'" >> "/run/openslx/network.conf"
+fi
+
+touch /.network
+set +x
+} &>> "/run/openslx/initramfs-udhcpc.log.$$"
diff --git a/modules.d/slx-network/scripts/udhcpc-trigger.stage4 b/modules.d/slx-network/scripts/udhcpc-trigger.stage4
new file mode 100755
index 00000000..b4dfeafa
--- /dev/null
+++ b/modules.d/slx-network/scripts/udhcpc-trigger.stage4
@@ -0,0 +1,208 @@
+#!/bin/bash
+#
+# This script is triggered by udhcpc and handle the DHCP information
+# given to this script as parameters.
+
+export PATH=$PATH:/opt/openslx/sbin:/opt/openslx/bin
+
+. /opt/openslx/config
+
+if [ -z "$SLX_PXE_NETIF" ]; then
+ echo "Missing PXE network interface information."
+ exit 1
+fi
+
+MAIN_NETIF="$SLX_PXE_NETIF"
+[ -n "$SLX_VLAN_ID" ] && MAIN_NETIF="${SLX_PXE_NETIF}.${SLX_VLAN_ID}"
+[ -n "$SLX_BRIDGE" ] && MAIN_NETIF="$SLX_BRIDGE"
+readonly MAIN_NETIF
+
+RESOLV_CONF="/opt/openslx/resolv.conf"
+THIS_RESOLV="/run/network/${MAIN_NETIF}.resolv"
+
+rebuild_resolv_conf () {
+ # Don't do anything if the active resolv.conf is not ours
+ # Also this will not run resolvconf update.d... No idea if we should still do so...
+ [ -L "/etc/resolv.conf" ] || return 0
+ [ "x$(readlink "/etc/resolv.conf")" == "x${RESOLV_CONF}" ] || return 0
+ # Maybe make this smarter some time, if anyone is using clients that are on multiple networks at once etc...
+ # This is a little braindead but should work most of the time
+ sort -u /run/network/*.resolv > "$RESOLV_CONF" 2> /dev/null
+
+ # add support for resolv.conf update scripts // see man(8) resolvconf
+ for s in /etc/resolvconf/update.d/*.sh; do
+ [ -f "$s" ] && [ -x "$s" ] && "$s"
+ done
+}
+
+escape_search() {
+ echo "$@" | sed -e 's/[]\/()$*.^|[]/\\&/g'
+}
+
+escape_replace() {
+ echo "$@" | sed -e 's/[\/&]/\\&/g'
+}
+
+check_env() {
+ if [ -z "$ip" ] || [ -z "$subnet" ] || [ -z "$interface" ]; then
+ echo "$1 event with missing data" >&2
+ echo "ip = '$ip'" >&2
+ echo "subnet = '$subnet'" >&2
+ echo "interface = '$interface'" >&2
+ exit 1
+ fi
+ # only run for the boot network interface
+ # TODO VLAN support
+ if [ "$interface" != "$MAIN_NETIF" ]; then
+ echo "Ignoring '$interface'..."
+ exit 1
+ fi
+}
+
+case "$1" in
+ bound|renew)
+ check_env "$1"
+ # Set address on interface
+ ip addr add "$ip/$(ipcalc -s -p "$ip" "$subnet" | sed s/.*=//)" dev "$interface"
+ # Set default route, if given
+ if [ -n "$router" ]; then
+ ip route replace default via "$router"
+ fi
+
+ # get domain, hostname and thus fqdn from DNS
+ dns_fqdn=$(busybox timeout -t 3 rdns "$ip")
+ dns_short="${dns_fqdn%%.*}"
+ # check if it is fqdn
+ if [ "$dns_fqdn" == "$dns_short" ]; then
+ unset dns_fqdn dns_short
+ fi
+
+ # Update resolver configuration file
+ conf_file="$(mktemp)"
+ # Own domain suffix
+ if [ -n "$domain" ]; then
+ :
+ elif [ -n "$dns_fqdn" ]; then
+ domain="${dns_fqdn#*.}"
+
+ elif [ -n "$SLX_NET_DOMAIN" ]; then
+ domain="$SLX_NET_DOMAIN"
+ fi
+ if [ -n "$domain" ]; then
+ echo "domain ${domain%% *}" >> "${conf_file}"
+ fi
+ # Add domain to list of search domains if not in there yet
+ if [ -n "$domain" ] && [ -n "$search" ]; then
+ FOUND=no
+ for sd in $search; do
+ [ "x$sd" = "x$domain" ] && FOUND=yes
+ done
+ [ "$FOUND" = "no" ] && search="$domain $search"
+ elif [ -n "$domain" ]; then
+ search="$domain"
+ fi
+ # Search domains
+ if [ -n "$search" ]; then
+ echo "search $search" >> "${conf_file}"
+ elif [ -n "$SLX_NET_SEARCH" ]; then
+ echo "search $SLX_NET_SEARCH" >> "${conf_file}"
+ elif [ -n "$SLX_NET_DOMAIN" ]; then
+ echo "search $SLX_NET_DOMAIN" >> "${conf_file}"
+ fi
+ for i in $dns; do
+ echo "$0: Adding DNS $i"
+ echo "nameserver $i" >> "${conf_file}"
+ done
+
+ if [ -x "/sbin/resolvconf" ] && [ -L "/etc/resolv.conf" ] && [ -d "/etc/resolvconf/update.d" ]; then
+ # Automatic handling :-)
+ resolvconf --create-runtime-directories
+ resolvconf --enable-updates
+ < "$conf_file" resolvconf -a "${interface}.udhcpc"
+ rm -- "$conf_file"
+ else
+ # Manual handling required :-(
+ mv -f "$conf_file" "$THIS_RESOLV"
+ rebuild_resolv_conf
+ fi
+
+ # TODO: check if we really want/need to overwrite the PXE_IP,
+ # it might be better/clearer to change the SLX_DHCP_CLIENT_IP...
+ sed -i "s/^\(SLX_PXE_CLIENT_IP=\).*$/\1'$ip'/" /opt/openslx/config
+ # Write DOMAIN and SEARCH to /opt/openslx/config if empty
+ if [ -z "$SLX_NET_DOMAIN" ] && [ -n "$domain" ]; then
+ sed -i "/^SLX_NET_DOMAIN=/d" /opt/openslx/config
+ echo "SLX_NET_DOMAIN='$domain'" >> /opt/openslx/config
+ fi
+ if [ -z "$SLX_NET_SEARCH" ] && [ -n "$search" ]; then
+ sed -i "/^SLX_NET_SEARCH=/d" /opt/openslx/config
+ echo "SLX_NET_SEARCH='$search'" >> /opt/openslx/config
+ fi
+ # Same for WINS servers
+ if [ -z "$SLX_NET_WINS" ] && [ -n "$wins" ]; then
+ sed -i "/^SLX_NET_WINS=/d" /opt/openslx/config
+ echo "SLX_NET_WINS='$wins'" >> /opt/openslx/config
+ fi
+
+ # TODO find a better way to trigger additional code, hook dir?
+ # Update /etc/issue for proper spacing
+ [ -x "/opt/openslx/scripts/openslx-create_issue" ] && /opt/openslx/scripts/openslx-create_issue
+
+ # Remove any stray addresses; we expect the primary interface to only have one
+ # address supplied via DHCP. We do this after adding the new one, obviously.
+ rem_list=$( ip -o addr show "$interface" | awk '{ for (i=1;i<NF;++i) if ($i == "inet") print $(i+1) }' | grep -v "^${ip}/" )
+ if [ -n "$rem_list" ]; then
+ echo "PRIMARY: Removing $rem_list since we just got assigned $ip"
+ echo 1 > "/proc/sys/net/ipv4/conf/$interface/promote_secondaries"
+ for addr in $rem_list; do
+ ip addr del "$addr" dev "$interface"
+ sed -i "/^$(escape_search "${addr%/*}")(\s|$)/d" /etc/hosts
+ done
+ fi
+
+ # Write to openslx-config
+ echo "# Config written by openslx-dhcp-script (2)" >> /opt/openslx/config
+ sed -i "/^SLX_DNS=/d" /opt/openslx/config
+ echo "SLX_DNS='$dns'" >> /opt/openslx/config
+ ;;
+
+ deconfig)
+ check_env "$1"
+ if [ "$interface" = "$primary" ]; then
+ echo "Ignoring deconfig for primary interface"
+ else
+ echo 1 > "/proc/sys/net/ipv4/conf/$interface/promote_secondaries"
+ clientip=${ip%%:*}
+ ip addr del "$clientip/$(ipcalc -s -p "$clientip" "$subnet" | sed s/.*=//)" dev "$interface"
+ sed -i "/^$(escape_search "$ip")(\s|$)/d" /etc/hosts
+ fi
+
+ if [ -x /sbin/resolvconf ] && [ -L /etc/resolv.conf ] && [ -d /etc/resolvconf/update.d ]; then
+ # Automatic handling :-)
+ resolvconf -d "${interface}.udhcpc"
+ else
+ # Manual handling required :-(
+ rm -f -- "$THIS_RESOLV"
+ rebuild_resolv_conf
+ fi
+ ;;
+
+ leasefail)
+ echo "$0: Lease failed: $message" >&2
+
+ ;;
+
+ nak)
+ echo "$0: Received a NAK: $message" >&2
+
+ ;;
+
+ *)
+ echo "$0: Unknown udhcpc command: $1" >&2
+ exit 1
+
+ ;;
+esac
+
+exit 0
+
diff --git a/modules.d/slx-network/services/udhcpc-bootif.service b/modules.d/slx-network/services/udhcpc-bootif.service
new file mode 100644
index 00000000..21a5de3c
--- /dev/null
+++ b/modules.d/slx-network/services/udhcpc-bootif.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=DHCP Client for the main boot interface
+Before=network.target
+Requires=systemd-tmpfiles-setup.service
+After=systemd-tmpfiles-setup.service
+
+[Service]
+Type=forking
+ExecStart=/opt/openslx/scripts/setup-bootif-network
+
+[Install]
+WantedBy=network.target
diff --git a/modules.d/slx-runmode/module-setup.sh b/modules.d/slx-runmode/module-setup.sh
new file mode 100755
index 00000000..7705ad06
--- /dev/null
+++ b/modules.d/slx-runmode/module-setup.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+check() {
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ return 255
+}
+depends() {
+ echo dnbd3-rootfs
+}
+install() {
+ # unpacking config.tgz should be pre-pivot 10, let's do this afterwards
+ inst_hook pre-pivot 50 "$moddir/scripts/runmode.sh"
+}
diff --git a/modules.d/slx-runmode/scripts/runmode.sh b/modules.d/slx-runmode/scripts/runmode.sh
new file mode 100644
index 00000000..a563486f
--- /dev/null
+++ b/modules.d/slx-runmode/scripts/runmode.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+#
+# SLX_SYSTEMD_TARGET overrides the default.target to boot
+# the stage4 into - required for the so-called 'run mode'.
+
+. /etc/openslx
+
+if [ -n "$SLX_SYSTEMD_TARGET" ]; then
+ SLX_SYSTEMD_TARGET="${SLX_SYSTEMD_TARGET%.target}.target"
+ ln -sf "$SLX_SYSTEMD_TARGET" "$NEWROOT/etc/systemd/system/default.target"
+fi
+
+true
diff --git a/modules.d/slx-splash/data/splash.ppm.gz b/modules.d/slx-splash/data/splash.ppm.gz
new file mode 100644
index 00000000..d30d44e2
--- /dev/null
+++ b/modules.d/slx-splash/data/splash.ppm.gz
Binary files differ
diff --git a/modules.d/slx-splash/module-setup.sh b/modules.d/slx-splash/module-setup.sh
new file mode 100755
index 00000000..05542269
--- /dev/null
+++ b/modules.d/slx-splash/module-setup.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+check() {
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ return 255
+}
+depends() {
+ echo slx-drm
+}
+install() {
+ cp "$moddir/data/splash.ppm.gz" "$initdir/etc/splash.ppm.gz"
+ inst_hook pre-trigger 10 "$moddir/scripts/slx-splash.sh"
+ inst_hook pre-pivot 20 "$moddir/scripts/restore-cursor.sh"
+}
diff --git a/modules.d/slx-splash/scripts/restore-cursor.sh b/modules.d/slx-splash/scripts/restore-cursor.sh
new file mode 100644
index 00000000..4ba9880d
--- /dev/null
+++ b/modules.d/slx-splash/scripts/restore-cursor.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+#
+# The console cursor is disabled when starting the splash screen.
+# This will add a drop-in to getty@.service to ensure the cursor
+# is restored when starting gettys.
+
+mkdir -p "$NEWROOT/etc/systemd/system/getty@.service.d/"
+cat <<- EOF > "$NEWROOT/etc/systemd/system/getty@.service.d/restore-cursor.conf"
+ [Service]
+ ExecStartPre=-/usr/bin/env bash -c "echo -en '\033c' > /dev/%I"
+EOF
diff --git a/modules.d/slx-splash/scripts/slx-splash.sh b/modules.d/slx-splash/scripts/slx-splash.sh
new file mode 100644
index 00000000..7381997b
--- /dev/null
+++ b/modules.d/slx-splash/scripts/slx-splash.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+show_splash() {
+ if [ -e "/etc/splash.ppm.gz" ]; then
+ systemd-preserve-process-marker /bin/busybox fbsplash -x -b -s "/etc/splash.ppm.gz" &
+ elif [ -e "/etc/splash.ppm" ]; then
+ systemd-preserve-process-marker /bin/busybox fbsplash -x -b -s "/etc/splash.ppm" &
+ else
+ echo "Splash screen requested, but not found in initramfs..."
+ fi
+}
+
+init_drm() {
+ # taken from dracut's plymouth module
+ # first trigger graphics subsystem
+ udevadm trigger --action=add --attr-match=class=0x030000 >/dev/null 2>&1
+ # first trigger graphics and tty subsystem
+ udevadm trigger --action=add \
+ --subsystem-match=graphics \
+ --subsystem-match=drm \
+ --subsystem-match=tty \
+ --subsystem-match=acpi \
+ >/dev/null 2>&1
+
+ udevadm settle --timeout=180 2>&1
+}
+
+if grep -wqE 'splash' /proc/cmdline; then
+ # first init graphics
+ init_drm
+ # disable non-critical kernel messages
+ echo "1 1 0 1" > /proc/sys/kernel/printk
+ # disable systemd's status message on console
+ # See: https://www.freedesktop.org/software/systemd/man/systemd.html#Signals
+ kill -55 1
+ # clear console
+ busybox clear
+ # disable cursor
+ echo -e "\033[?25l" > /dev/console
+ # finally:
+ show_splash
+fi
+
+true
diff --git a/modules.d/slx-tools/module-setup.sh b/modules.d/slx-tools/module-setup.sh
new file mode 100644
index 00000000..faf2a04f
--- /dev/null
+++ b/modules.d/slx-tools/module-setup.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+build() {
+ # clone if not cloned yet
+ if [ ! -d "${moddir}/src" ]; then
+ git clone --depth 1 "git://git.openslx.org/openslx-ng/slx-tools" "${moddir}/src"
+ fi
+ cd "${moddir}/src"
+ bash make.sh /usr/share/slx-tools
+ cd - &>/dev/null
+}
+check() {
+ if [ ! -s "${moddir}/src/slx-tools" ] && ! build; then
+ derror "Failed to build slx-tools"
+ return 1
+ fi
+ return 255
+}
+
+depends() {
+ echo "busybox"
+}
+
+install() {
+ inst "${moddir}/src/slx-tools" "/usr/bin/slx-tools"
+ mkdir -p "${initdir}/usr/share/slx-tools"
+ cp -r "${moddir}/src/modules" "${initdir}/usr/share/slx-tools"
+}
diff --git a/modules.d/slx-tpm/module-setup.sh b/modules.d/slx-tpm/module-setup.sh
new file mode 100755
index 00000000..f9a239e0
--- /dev/null
+++ b/modules.d/slx-tpm/module-setup.sh
@@ -0,0 +1,93 @@
+#!/usr/bin/env bash
+
+declare -rg openssl_tpm2_engine_url="https://git.kernel.org/pub/scm/linux/kernel/git/jejb/openssl_tpm2_engine.git/snapshot"
+declare -rg openssl_tpm2_engine_target="openssl_tpm2_engine-1.2.1"
+declare -rg ibm_tss_target="ibmtss1234.tar.gz"
+declare -rg ibm_tss_url="https://sourceforge.net/projects/ibmtpm20tss/files/$ibm_tss_target/download"
+# TODO download in "$moddir/src"
+check() {
+ if ! hash help2man 2>&1 /dev/null; then
+ echo "Missing help2man, please install it..."
+ return 1
+ fi
+ mkdir -p "$moddir/build"
+ if [ ! -d "$moddir/build/${openssl_tpm2_engine_target}" ]; then
+ compile_openssl_tpm2_engine || return 1
+ fi
+ return 255
+}
+depends() {
+ :
+}
+compile_ibm_tss() {
+ (
+ set -o errexit
+ wget -O "$ibm_tss_target" "$ibm_tss_url"
+ local build_dir="$moddir/build/${ibm_tss_target%%.*}"
+ mkdir -p "$build_dir"
+ tar xvf "$ibm_tss_target" -C "$build_dir"
+ cd "$build_dir/utils"
+ make
+ )
+ local ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed to compile IBM TSS"
+ rm -rf "$moddir/build/${ibm_tss_target%%.*}"
+ fi
+ return $ret
+}
+compile_openssl_tpm2_engine() {
+ if [ -d "$moddir/build/${ibm_tss_target%%.*}" ]; then
+ compile_ibm_tss || return 1
+ fi
+ install_ibm_tss "/"
+ (
+ set -o errexit
+ wget -O "$openssl_tpm2_engine_target.tar.gz" "$openssl_tpm2_engine_url/$openssl_tpm2_engine_target.tar.gz"
+ tar xvf "$openssl_tpm2_engine_target.tar.gz" -C "$moddir/build"
+ cd "$moddir/build/$openssl_tpm2_engine_target"
+ bash bootstrap.sh
+ CFLAGS="-I$moddir/build/${ibm_tss_target%%.*}/utils -Wno-pointer-sign" ./configure
+ # cause help2man suck...
+ sed -i '/^HELP2MAN/ s/$/ --no-discard-stderr/' Makefile
+ make
+ )
+}
+install_ibm_tss() {
+ if [ "$#" -ne 1 ]; then
+ echo "Failed: Needs one arg."
+ return 1
+ fi
+ if [ ! -d "$moddir/build/${ibm_tss_target%%.*}" ]; then
+ compile_ibm_tss || return 1
+ fi
+ cd "$moddir/build/${ibm_tss_target%%.*}/utils"
+ mkdir -p "$1/usr/local/bin"
+ # this is hacky, TODO better with /etc/ld.cache.conf.d ?
+ cp -a *.so* "$1/usr/lib"
+ mkdir -p "$1/usr/local/bin"
+ find . -perm /a+x -type f -exec cp {} "$1/usr/local/bin/" \;
+ # only needed to compile some tpm binary (not needed in initramfs)
+# tar cvf - tss2 | tar xvf - -C "$1/usr/local/include"
+ cd -
+}
+install_openssl_tpm2_engine() {
+ if [ ! -d "$moddir/build/${openssl_tpm2_engine_target}" ]; then
+ echo "no build of openssl tpm2 engine"
+ return 1
+ fi
+ cd "$moddir/build/${openssl_tpm2_engine_target}"
+ make DESTDIR="$initdir" install
+ mkdir -p "$initdir/usr/lib/x86_64-linux-gnu/"
+ cp -r /usr/lib/x86_64-linux-gnu/engines-1.1 "$initdir/usr/lib/x86_64-linux-gnu/"
+ ln -s "libtpm2.so" "$initdir/usr/lib/x86_64-linux-gnu/engines-1.1/tpm2.so"
+}
+install() {
+ install_openssl_tpm2_engine
+ install_ibm_tss "$initdir"
+ inst_multiple openssl
+ return 0
+}
+installkernel() {
+ instmods =drivers/char/tpm
+}
diff --git a/modules.d/slx-uuid/bad-uuid-defaults.conf b/modules.d/slx-uuid/bad-uuid-defaults.conf
new file mode 100644
index 00000000..aaf59a7d
--- /dev/null
+++ b/modules.d/slx-uuid/bad-uuid-defaults.conf
@@ -0,0 +1,8 @@
+00000000-0000-0000-0000-000000000000
+03000200-0400-0500-0006-000700080009
+11111111-2222-3333-4444-555555555555
+44454C4C-2000-1020-8020-A0C04F202020
+4C4C4544-0000-2010-8020-80C04F202020
+4C4C4544-0046-3310-805A-B6C04F4B4D31
+A023157C-F692-11DE-977C-7F0F26276F33
+FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
diff --git a/modules.d/slx-uuid/module-setup.sh b/modules.d/slx-uuid/module-setup.sh
new file mode 100755
index 00000000..569b5155
--- /dev/null
+++ b/modules.d/slx-uuid/module-setup.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+check() {
+ # Tell dracut that this module should only be included if it is required
+ # explicitly.
+ if ! hash dmidecode; then
+ echo "dmidecode is missing from this system, please install it."
+ return 1
+ fi
+ return 255
+}
+depends() {
+ echo busybox
+}
+install() {
+ mkdir -p "$initdir/etc/bad-uuid.d"
+ inst_simple "$moddir/bad-uuid-defaults.conf" "/etc/bad-uuid.d/bad-uuid-defaults.conf"
+ inst_multiple dmidecode
+ inst_hook pre-udev 05 "$moddir/scripts/get-system-uuid.sh"
+ inst_hook pre-pivot 10 "$moddir/scripts/copy-system-uuid-to-newroot.sh"
+}
diff --git a/modules.d/slx-uuid/scripts/copy-system-uuid-to-newroot.sh b/modules.d/slx-uuid/scripts/copy-system-uuid-to-newroot.sh
new file mode 100644
index 00000000..553109fb
--- /dev/null
+++ b/modules.d/slx-uuid/scripts/copy-system-uuid-to-newroot.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+if [ -s "/run/system-uuid" ]; then
+ cp "/run/system-uuid" "$NEWROOT/etc/system-uuid"
+fi
+true
diff --git a/modules.d/slx-uuid/scripts/get-system-uuid.sh b/modules.d/slx-uuid/scripts/get-system-uuid.sh
new file mode 100644
index 00000000..fd6bb125
--- /dev/null
+++ b/modules.d/slx-uuid/scripts/get-system-uuid.sh
@@ -0,0 +1,69 @@
+#!/usr/bin/env bash
+#
+# Slighty changed version of:
+# http://git.openslx.org/openslx-ng/mltk.git/plain/core/modules/system-uuid/data/bin/get-uuid
+
+. /lib/dracut-lib.sh
+
+get_system_uuid() {
+ if [ -e /run/openslx/network.conf ]; then
+ . /run/openslx/network.conf
+ fi
+
+ if [ -z "$SLX_PXE_MAC" ]; then
+ eval $(grep -Eo BOOTIF=\\S+ /proc/cmdline)
+ if [ "${#BOOTIF}" -ne "20" ]; then
+ warn "Getting MAC from /proc/cmdline failed, using 'ip a'..."
+ BOOTIF=01-$(ip a | grep -A 1 ": ${SLX_BRIDGE:-br0}" | grep -o 'ether ..:..:..:..:..:..' | cut -d' ' -f2 | sed s/:/-/g)
+ fi
+ if [ "${#BOOTIF}" -ne "20" ]; then
+ warn "Getting MAC from 'ip a' failed, using a default value..."
+ BOOTIF="99-88-77-66-55-44-33"
+ fi
+ else
+ BOOTIF="01-$(tr ':' '-' <<< $SLX_PXE_MAC)"
+ fi
+
+ local UUID=$(dmidecode -q -s system-uuid | grep -v '^#' | head -n 1 | tr 'a-z' 'A-Z')
+ if [ "${#UUID}" -ne "36" ]; then
+ warn "Determined UUID (${UUID}) has not expected length of 36, falling back to MAC..."
+ # Maybe use /proc/sys/kernel/random/uuid ?
+ UUID=
+ else
+ # Got UUID, check blacklist
+ local DIR="/etc/bad-uuid.d"
+ local TMPLIST=$(mktemp)
+ local BADLIST=$(mktemp)
+ for file in "$DIR"/*; do
+ [ -f "$file" ] || continue
+ # 11111111-2222-3333-4444-555555555555
+ < "$file" tr 'a-z' 'A-Z' | grep -Eo '[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}'
+ done | tee "$TMPLIST" > "$BADLIST"
+ # Also add flipped version of bad uuids. Found some of them through googling and discovered that sometimes
+ # users report them in a different order. UUIDs use different endianness for the first three blocks than
+ # the remaining two, but some tools seem to ignore that fact.
+ < "$BADLIST" sed -r 's/^(..)(..)(..)(..)\-(..)(..)\-(..)(..)\-([0-9A-F]{4}\-[0-9A-F]{12})$/\4\3\2\1-\6\5-\8\7-\9/' >> "$TMPLIST"
+ # Finally make unique
+ sort -u "$TMPLIST" > "$BADLIST"
+ if grep -Fxq "$UUID" "$BADLIST"; then
+ warn "WARNING: UUID is blacklisted as potentially not being unique, using MAC fallback"
+ UUID=
+ fi
+ rm -f -- "$TMPLIST" "$BADLIST"
+ fi
+
+ if [ -z "$UUID" ]; then
+ UUID=$( echo "$BOOTIF" | sed -r 's/[^0-9A-Fa-f]//g' )
+ [ "${#UUID}" -eq 14 ] && UUID="${UUID:2}"
+ if [ "${#UUID}" -eq 12 ]; then
+ UUID="baad1d00-9491-4716-b98b-$UUID"
+ else
+ UUID="baad1d00-9491-4716-b98b-000000000000"
+ fi
+ fi
+ UUID=$( echo "$UUID" | tr 'a-z' 'A-Z' )
+ readonly UUID
+ echo "$UUID" > "/run/system-uuid"
+}
+
+get_system_uuid
diff --git a/modules.d/systemd-networkd-ext/hooks/configure-dhcp-for-newroot.sh b/modules.d/systemd-networkd-ext/hooks/configure-dhcp-for-newroot.sh
new file mode 100644
index 00000000..b9803729
--- /dev/null
+++ b/modules.d/systemd-networkd-ext/hooks/configure-dhcp-for-newroot.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+#
+# This hook creates a networkd configuration for the NEWROOT
+# * DHCP configuration for the boot interface
+# * Set static hostname via /etc/hostname
+# This uses the configuration file generated by the parse-kcl-for-networkd.sh
+# hook Note: on systemd v219, UseDomains is bugged and does not seem to do
+# anything thus that option is complemented with the KCL's domain to hopefully
+# garantee one of these will take effect.
+
+. "/run/openslx/network.conf"
+
+NETWORKD_DIR="/etc/systemd/network"
+mkdir -p "${NEWROOT}/${NETWORKD_DIR}"
+
+# First, copy over every configuration made so far,
+# excluding the physical interface if bridged
+cp "${NETWORKD_DIR}/${SLX_BRIDGE}"* "${NEWROOT}/${NETWORKD_DIR}"
+
+# Now determine which network configuration we are running
+# VLANs are already configured to DHCP, so nothing to do
+if [ -z "${SLX_VLAN_ID}" ]; then
+ # In both bridged and non-bridged mode, we need to adjust
+ # the configuration to DHCP for stage4
+ MATCH_LINE=
+ MATCH_LINE_EXTRA=
+ MAIN_NET_CONF=
+ if [ -n "${SLX_BRIDGE}" ]; then
+ MATCH_LINE="Name=${SLX_BRIDGE}"
+ MAIN_NETIF_CONF="${NETWORKD_DIR}/${SLX_BRIDGE}.network"
+ elif [ -n "${SLX_PXE_MAC}" ]; then
+ MATCH_LINE="MACAddress=${SLX_PXE_MAC}"
+ MATCH_LINE_EXTRA="Path=pci*"
+ MAIN_NETIF_CONF="${NETWORKD_DIR}/${SLX_PXE_NETIF}.network"
+ else
+ emergency_shell "Could not determine network configuration mode!"
+ fi
+ # backup current network config for later reference before overwritting it
+ if [ -e "${MAIN_NETIF_CONF}" ]; then
+ mv "${NEWROOT}/${MAIN_NETIF_CONF}" "${NEWROOT}/${MAIN_NETIF_CONF}.stage3"
+ else
+ emergency_shell "Failed to find main networkd configuration: ${MAIN_NETIF_CONF}"
+ fi
+ # Now generate a DHCP configuration for the main interface
+ cat <<-EOF > "${NEWROOT}/${MAIN_NETIF_CONF}"
+ [Match]
+ ${MATCH_LINE}
+ ${MATCH_LINE_EXTRA}
+
+ [Network]
+ DHCP=ipv4
+ LinkLocalAddressing=no
+ IPv6AcceptRA=no
+
+ [DHCP]
+ UseDNS=true
+ UseDomains=true
+ UseHostname=true
+ CriticalConnection=true
+ EOF
+fi
+
+# Workaround: UseHostname seems broken, so manually set the hostname for now...
+[ -n "${SLX_HOSTNAME}" ] && echo "${SLX_HOSTNAME}" > $NEWROOT/etc/hostname
diff --git a/modules.d/systemd-networkd-ext/hooks/copy-networkd-files-to-newroot.sh b/modules.d/systemd-networkd-ext/hooks/copy-networkd-files-to-newroot.sh
new file mode 100644
index 00000000..ec61616c
--- /dev/null
+++ b/modules.d/systemd-networkd-ext/hooks/copy-networkd-files-to-newroot.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# This hook copies the core systemd-networkd related service
+# files to the NEWROOT and activate them in sysinit.target
+# to prevent systemd from killing these while pivot_root
+NEWROOT_SYSTEMD_DIR="${NEWROOT}/usr/lib/systemd/system"
+NEWROOT_SYSINIT_TARGET_DIR="${NEWROOT_SYSTEMD_DIR}/sysinit.target.wants"
+mkdir -p "${NEWROOT_SYSINIT_TARGET_DIR}"
+
+for UNIT in \
+ systemd-networkd.socket \
+ systemd-networkd.service \
+ systemd-resolved.service
+do
+ UNIT_PATH="$(systemctl show -p FragmentPath $UNIT | cut -c 14-)"
+ [ -z "${UNIT_PATH}" ] && continue
+ mkdir -p "${NEWROOT}/${UNIT_PATH%/*}"
+ cp "${UNIT_PATH}" "${NEWROOT}/${UNIT_PATH}"
+ ln -sf "${UNIT_PATH}" "${NEWROOT_SYSINIT_TARGET_DIR}/${UNIT}"
+done
+
+if [ -e "${NEWROOT_SYSTEMD_DIR}/systemd-resolved.service" ]; then
+ # this drop-in is needed to prevent a pull-in loop sysinit.target <-> basic.target
+ mkdir -p "${NEWROOT_SYSTEMD_DIR}/systemd-resolved.service.d/"
+ cat <<-EOF > "${NEWROOT_SYSTEMD_DIR}/systemd-resolved.service.d/00-no-default-deps.conf"
+ [Unit]
+ DefaultDependencies=no
+ EOF
+
+ # finally make sure the NEWROOT resolv.conf links to the one managed by resolved.
+ rm "${NEWROOT}"/etc/resolv.conf
+ ln -s /run/systemd/resolve/resolv.conf "${NEWROOT}"/etc/resolv.conf
+fi
diff --git a/modules.d/systemd-networkd-ext/hooks/parse-kcl-for-networkd.sh b/modules.d/systemd-networkd-ext/hooks/parse-kcl-for-networkd.sh
new file mode 100644
index 00000000..a64e6efe
--- /dev/null
+++ b/modules.d/systemd-networkd-ext/hooks/parse-kcl-for-networkd.sh
@@ -0,0 +1,251 @@
+#!/bin/bash
+#
+# This script was mostly stolen from 40network/parse-ip-opts.sh. It was
+# adapted to generate .network files for systemd-networkd using the IP
+# configuration from PXE/Syslinux in addition to domain, dns and hostname
+
+command -v getarg >/dev/null || . /lib/dracut-lib.sh
+
+# static names for the boot interface and its bridge
+declare -rg BOOTIF_NAME="boot0"
+declare -rg BRIDGE_NAME="br0"
+
+# Get all the ip-related arguments from the KCL
+parse_kernel_command_line() {
+ ## KCL "BOOTIF": MAC address of the interface that DHCP'ed during PXE
+ declare -g BOOTIF="$(getarg BOOTIF=)"
+ # Remove the hardware type prefix of BOOTIF if it has 20 chars to get
+ # the plain MAC address. The hardware type prefix has length 3, e.g. "01-".
+ [ -n "${BOOTIF}" ] && [ ${#BOOTIF} -eq 20 ] && BOOTIF="${BOOTIF#???}"
+ BOOTIF="$(tr '-' ':' <<< $BOOTIF)"
+ readonly BOOTIF
+
+ ## KCL "ip": is expected in following format (syslinux IPAPPEND3):
+ declare -rg IPCONF="$(getarg ip=)"
+ # <CLIENT_IP>:<PXE_SERVER_IP>:<GATEWAY_IP>:<NETMASK>
+ declare -g CLIENT_IP=
+ declare -g SERVER_IP=
+ declare -g GATEWAY_IP=
+ declare -g NETMASK=
+ read -r CLIENT_IP SERVER_IP GATEWAY_IP NETMASK <<< $( awk -F: '{print $1" "$2" "$3" "$4}' <<< "${IPCONF}" )
+ readonly CLIENT_IP SERVER_IP GATEWAY_IP NETMASK
+
+
+ # Taken from parse-ip-opts.sh: Convert the netmask to CIDR notation
+ declare -g CIDR
+ if [[ "x$NETMASK" =~ ^x[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
+ CIDR=$(mask2cidr "$NETMASK")
+ elif [ -n "$NETMASK" -a "x${NETMASK//[0-9]/}" = 'x' ]; then
+ # The mask is already a prefix length (uint), so validate it
+ [[ "x$CLIENT_IP" == x*:*:* && "$NETMASK" -le 128 || "$NETMASK" -le 32 ]] && CIDR=$NETMASK
+ fi
+ readonly CIDR
+
+ # KCL "hostname"
+ declare -rg HOSTNAME="$(getarg hostname=)"
+ [ -n "$HOSTNAME" ] && echo "$HOSTNAME" > /proc/sys/kernel/hostname
+
+ # KCL "dns"
+ declare -rg DNS="$(getarg dns=)"
+
+ # KCL "domain"
+ declare -rg DOMAIN="$(getarg domain=)"
+
+ # VLAN tag
+ declare -rg VLAN="$(getarg vlan=)"
+ if [ -n "$VLAN" ]; then
+ modprobe 8021q || emergency_shell "VLAN mode detected - failed to load 8021q"
+ fi
+
+ # Bridged mode?
+ grep -wqE 'bridged' /proc/cmdline && declare -rg BRIDGED="y"
+}
+
+# Dumps the parsed IP configuration to /run/openslx/network.conf
+# Creates a list of "KEY=value" type variables to source later on
+save_ip_config() {
+ local IP_RUNTIME_CONFIG="/run/openslx/network.conf"
+ mkdir -p "${IP_RUNTIME_CONFIG%/*}" # dirname a la bash
+ cat <<-EOF > "${IP_RUNTIME_CONFIG}"
+ SLX_PXE_CLIENT_IP=${CLIENT_IP}
+ SLX_PXE_SERVER_IP=${SERVER_IP}
+ SLX_PXE_GATEWAY=${GATEWAY_IP}
+ SLX_PXE_DNS=${DNS}
+ SLX_PXE_MAC=${BOOTIF}
+ SLX_PXE_NETIF=${BOOTIF_NAME}
+ SLX_BRIDGE=${BRIDGED:+${BRIDGE_NAME}}
+ SLX_VLAN_ID=${VLAN}
+ SLX_DNS=${DNS}
+ SLX_HOSTNAME=${HOSTNAME}
+ SLX_NET_DOMAIN=${DOMAIN}
+ EOF
+}
+
+# Helper to echo the static configuration,
+# including DNS and Domain, if given per KCL
+print_static_ip_conf() {
+ [ $# -ne 2 ] && echo "Need 2 args: <ip/cidr> <gateway>. Given: $@" && return 1
+ echo "Address=${1}"
+ echo "Gateway=${2}"
+ [ -n "${DNS}" ] && echo "DNS=${DNS}"
+ [ -n "${DOMAIN}" ] && echo "Domains=${DOMAIN}"
+}
+
+# Create udev rule to rename the PXE boot interface to BOOTIF_NAME
+create_udev_bootif_name_rule() {
+ [ -z "${BOOTIF}" ] && echo "No BOOTIF set, was it present in the kernel command line?" && return 1
+ # priority 70 < 80-net-name-slot.rules.
+ echo 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="'${BOOTIF}'", NAME="'${BOOTIF_NAME}'"' > /etc/udev/rules.d/70-pxe-boot-interface.rules
+}
+
+disable_ipv6() {
+ cat <<- EOF
+ LinkLocalAddressing=no
+ IPv6AcceptRA=no
+ EOF
+}
+
+dhcp_options() {
+ cat <<- EOF
+ [DHCP]
+ UseDNS=true
+ UseDomains=true
+ UseHostname=true
+ CriticalConnection=true
+ EOF
+}
+
+## Generate network and link file(s) for networkd
+# Checks if an IP configuration was forwarded by
+generate_networkd_config() {
+ mkdir -p "/etc/systemd/network"
+ local BOOTIF_NETWORK_CONF="/etc/systemd/network/${BOOTIF_NAME}.network"
+ (
+ echo '[Match]'
+ echo "MACAddress=${BOOTIF}"
+ echo "Path=pci*"
+ echo ''
+ # Currently the boot interface is configured to either:
+ # * static ip as given by the initial DHCP during PXE
+ # * bridged
+ # * vlan-tagged (ethernet interface not configured)
+ # In particular, configuring both vlan tags and the physical
+ # interface is not supported (might be needed in some setups)
+ echo '[Network]'
+ disable_ipv6
+ if [ -n "${BRIDGED}" ]; then
+ echo "Bridge=${BRIDGE_NAME}"
+ elif [ -n "${CLIENT_IP}" -a -n "${GATEWAY_IP}" ]; then
+ print_static_ip_conf "${CLIENT_IP}/${CIDR:-24}" "${GATEWAY_IP}"
+ elif [ -n "${VLAN}" ]; then
+ echo "VLAN=$BOOTIF_NAME.$VLAN"
+ else
+ echo -e "DHCP=ipv4\n"
+ dhcp_options
+ fi
+ ) > "${BOOTIF_NETWORK_CONF}"
+
+ if [ -n "$VLAN" ]; then
+ local VLAN_DEV_CONF="/etc/systemd/network/${BOOTIF_NAME}.${VLAN}.netdev"
+ cat <<- EOF > "${VLAN_DEV_CONF}"
+ [NetDev]
+ Name=${BOOTIF_NAME}.${VLAN}
+ MACAddress=${BOOTIF}
+ Kind=vlan
+
+ [VLAN]
+ Id=${VLAN}
+ EOF
+
+ # Configure the vlan tagged interface for DHCPv4, TODO IPv6
+ local VLAN_NETWORK_CONF="/etc/systemd/network/${BOOTIF_NAME}.${VLAN}.network"
+ cat <<- EOF > "${VLAN_NETWORK_CONF}"
+ [Match]
+ Name=${BOOTIF_NAME}.${VLAN}
+ Type=vlan
+
+ [Link]
+ MACAddress=${BOOTIF}
+
+ [Network]
+ DHCP=ipv4
+ EOF
+ (
+ disable_ipv6
+ echo ""
+ dhcp_options
+ ) >> "${VLAN_NETWORK_CONF}"
+ fi
+
+ # bridge setup
+ if [ -n "$BRIDGED" ]; then
+ local BRIDGE_DEV_CONF="/etc/systemd/network/${BRIDGE_NAME}.netdev"
+ cat <<- EOF > "${BRIDGE_DEV_CONF}"
+ [NetDev]
+ Name=${BRIDGE_NAME}
+ Kind=bridge
+ MACAddress=${BOOTIF}
+ EOF
+
+ local BRIDGE_NETWORK_CONF="/etc/systemd/network/${BRIDGE_NAME}.network"
+ (
+ echo '[Match]'
+ echo "Name=${BRIDGE_NAME}"
+ echo ""
+ echo '[Network]'
+ disable_ipv6
+ if [ -n "${CLIENT_IP}" -a -n "${GATEWAY_IP}" ]; then
+ print_static_ip_conf "${CLIENT_IP}/${CIDR:-24}" "${GATEWAY_IP}"
+ else
+ # bad/no IP info, fallback to DHCP
+ echo -e "DHCP=ipv4\n"
+ dhcp_options
+ fi
+ ) > "${BRIDGE_NETWORK_CONF}"
+ fi
+ return 0
+}
+
+# from parse-ip-opts.sh
+# Takes a netmask and outputs the corresponding CIDR
+# e.g.
+# mask2cidr 255.255.255.0
+# returns: 24
+mask2cidr() {
+ local -i bits=0
+ for octet in ${1//./ }; do
+ for i in {0..8}; do
+ [ "$octet" -eq $(( 256 - (1 << i) )) ] && bits+=$((8-i)) && break
+ done
+ [ $i -eq 8 -a "$octet" -ne 0 ] && warn "Bad netmask $mask" && return
+ [ $i -gt 0 ] && break
+ done
+ echo $bits
+}
+
+## MAIN ##
+# Get IP config from KCL
+parse_kernel_command_line
+
+# Save IP config for later use
+save_ip_config
+
+# Create the udev rule to rename the boot interface to the declared BOOTIF_NAME
+create_udev_bootif_name_rule || \
+ emergency_shell "Failed to create udev rule for boot interface renaming."
+
+# Generate config files for networkd
+generate_networkd_config || \
+ emergency_shell "Failed to generate networkd configuration."
+
+# Make dracut wait for network during the udev loop (initqueue) to make
+# sure we have network access in the pre-mount hook as it is needed
+# to get configurations and the root filesystem
+NETIF=
+[ -n "${BOOTIF_NAME}" ] && NETIF="${BOOTIF_NAME}"
+[ -n "${BRIDGED}" ] && [ -n "${BRIDGE_NAME}" ] && NETIF="${BRIDGE_NAME}"
+[ -n "${VLAN}" ] && NETIF="${BOOTIF_NAME}.${VLAN}"
+
+BB=$(command -v busybox)
+[ -n "${BB}" ] && BB+=" timeout -t 60"
+/sbin/initqueue --finished ${BB} /lib/systemd/systemd-networkd-wait-online -i ${NETIF}
diff --git a/modules.d/systemd-networkd-ext/module-setup.sh b/modules.d/systemd-networkd-ext/module-setup.sh
new file mode 100755
index 00000000..be50973d
--- /dev/null
+++ b/modules.d/systemd-networkd-ext/module-setup.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+# shameless hacked version of dracut's systemd-networkd module
+# called by dracut
+check() {
+ [[ $mount_needs ]] && return 1
+
+ if dracut_module_included "network"; then
+ derror "The module 'systemd-networkd' conflicts with 'network'. Use either one not both!"
+ return 1
+ fi
+ return 255
+}
+
+# called by dracut
+depends() {
+ echo "systemd kernel-network-modules"
+}
+
+installkernel() {
+ return 0
+}
+
+# called by dracut
+install() {
+ # need initqueue to get a clean network start
+ dracut_need_initqueue
+
+ # install required systemd units
+ inst_multiple -o \
+ $systemdutildir/systemd-networkd \
+ $systemdutildir/systemd-networkd-wait-online \
+ $systemdutildir/systemd-resolved \
+ $systemdsystemunitdir/systemd-networkd-wait-online.service \
+ $systemdsystemunitdir/systemd-networkd.service \
+ $systemdsystemunitdir/systemd-networkd.socket \
+ $systemdsystemunitdir/systemd-resolved.service \
+ networkctl ip
+
+ # active them
+ for i in \
+ systemd-networkd-wait-online.service \
+ systemd-networkd.service \
+ systemd-networkd.socket \
+ systemd-resolved.service
+ do
+ systemctl --root "$initdir" enable "$i"
+ done
+ mkdir $initdir/$systemdsystemunitdir/network.target.wants
+ ln -s $systemdsystemunitdir/systemd-resolved.service \
+ $initdir/$systemdsystemunitdir/network.target.wants/systemd-resolved.service
+ ln -sf /run/systemd/resolve/resolv.conf $initdir/etc/resolv.conf
+
+ # create system users needed
+ for user in \
+ systemd-network \
+ systemd-resolve
+ do
+ grep "^${user}:" /etc/passwd 2>/dev/null >> "$initdir/etc/passwd"
+ grep "^${user}:" /etc/group >> "$initdir/etc/group"
+ done
+
+ # install basic dns libs
+ _arch=$(uname -m)
+ inst_libdir_file {"tls/$_arch/",tls/,"$_arch/",}"libnss_dns.so.*" \
+ {"tls/$_arch/",tls/,"$_arch/",}"libnss_mdns4_minimal.so.*" \
+ {"tls/$_arch/",tls/,"$_arch/",}"libnss_myhostname.so.*" \
+ {"tls/$_arch/",tls/,"$_arch/",}"libnss_resolve.so.*" \
+ {"tls/$_arch/",tls/,"$_arch/",}"libresolve.so.*"
+
+ # the hook script that will parse the "ip=" kernel command line
+ # parameter and generate the .link and .network files needed
+ # by systemd-networkd.
+ inst_hook cmdline 10 "$moddir/hooks/parse-kcl-for-networkd.sh"
+ inst_hook pre-pivot 10 "$moddir/hooks/copy-networkd-files-to-newroot.sh"
+ inst_hook pre-pivot 20 "$moddir/hooks/configure-dhcp-for-newroot.sh"
+}
+