diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 95df0ace1ca4..94cecdf1fd79 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -71,6 +71,24 @@ mount -t devtmpfs -o "size=@devSize@" devtmpfs /dev
mkdir -p /run
mount -t tmpfs -o "mode=0755,size=@runSize@" tmpfs /run
+# Optionally log the script output to /dev/kmsg or /run/log/stage-1-init.log
+if test -n "@logCommands@"; then
+ mkdir -p /tmp
+ mkfifo /tmp/stage-1-init.log.fifo
+ logOutFd=8 && logErrFd=9
+ eval "exec $logOutFd>&1 $logErrFd>&2"
+ if test -w /dev/kmsg; then
+ tee -i < /tmp/stage-1-init.log.fifo /proc/self/fd/"$logOutFd" | while read line; do
+ if test -n "$line"; then
+ echo "stage-1-init: $line" > /dev/kmsg
+ fi
+ done &
+ else
+ mkdir -p /run/log
+ tee -i < /tmp/stage-1-init.log.fifo /run/log/stage-1-init.log &
+ fi
+ exec > /tmp/stage-1-init.log.fifo 2>&1
+fi
# Process the kernel command line.
export stage2Init=/init
@@ -415,6 +433,14 @@ fi
# Stop udevd.
udevadm control --exit
+# Reset the logging file descriptors.
+# Do this just before pkill, which will kill the tee process.
+if test -n "@logCommands@"
+then
+ exec 1>&$logOutFd 2>&$logErrFd
+ eval "exec $logOutFd>&- $logErrFd>&-"
+fi
+
# Kill any remaining processes, just to be sure we're not taking any
# with us into stage 2. But keep storage daemons like unionfs-fuse.
pkill -9 -v -f '@'
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index f31620df1d85..45652b355c80 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -200,8 +200,8 @@ let
inherit (config.boot) resumeDevice devSize runSize;
- inherit (config.boot.initrd) checkJournalingFS
- preLVMCommands preDeviceCommands postDeviceCommands postMountCommands kernelModules;
+ inherit (config.boot.initrd) checkJournalingFS
+ logCommands preLVMCommands preDeviceCommands postDeviceCommands postMountCommands kernelModules;
resumeDevices = map (sd: if sd ? device then sd.device else "/dev/disk/by-label/${sd.label}")
(filter (sd: (sd ? label || hasPrefix "/dev/" sd.device) && !sd.randomEncryption) config.swapDevices);
@@ -269,6 +269,14 @@ in
'';
};
+ boot.initrd.logCommands = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Whether to replicate command output of stage-1 booting to /dev/kmsg or /run/log/stage-1-init.log if /dev/kmsg is not writable.
+ '';
+ };
+
boot.initrd.prepend = mkOption {
default = [ ];
type = types.listOf types.str;