|
|
@ -0,0 +1,636 @@ |
|
|
|
# This module builds the initial ramdisk, which contains an init |
|
|
|
# script that performs the first stage of booting the system: it loads |
|
|
|
# the modules necessary to mount the root file system, then calls the |
|
|
|
# init in the root file system to start the second boot stage. |
|
|
|
|
|
|
|
{ config, lib, utils, pkgs, ... }: |
|
|
|
|
|
|
|
with lib; |
|
|
|
|
|
|
|
let |
|
|
|
|
|
|
|
udev = config.systemd.package; |
|
|
|
|
|
|
|
kernel-name = config.boot.kernelPackages.kernel.name or "kernel"; |
|
|
|
|
|
|
|
modulesTree = config.system.modulesTree.override { name = kernel-name + "-modules"; }; |
|
|
|
firmware = config.hardware.firmware; |
|
|
|
|
|
|
|
|
|
|
|
# Determine the set of modules that we need to mount the root FS. |
|
|
|
modulesClosure = pkgs.makeModulesClosure { |
|
|
|
rootModules = config.boot.initrd.availableKernelModules ++ config.boot.initrd.kernelModules; |
|
|
|
kernel = modulesTree; |
|
|
|
firmware = firmware; |
|
|
|
allowMissing = true; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
# The initrd only has to mount `/` or any FS marked as necessary for |
|
|
|
# booting (such as the FS containing `/nix/store`, or an FS needed for |
|
|
|
# mounting `/`, like `/` on a loopback). |
|
|
|
fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems; |
|
|
|
|
|
|
|
# A utility for enumerating the shared-library dependencies of a program |
|
|
|
findLibs = pkgs.buildPackages.writeShellScriptBin "find-libs" '' |
|
|
|
set -euo pipefail |
|
|
|
|
|
|
|
declare -A seen |
|
|
|
left=() |
|
|
|
|
|
|
|
patchelf="${pkgs.buildPackages.patchelf}/bin/patchelf" |
|
|
|
|
|
|
|
function add_needed { |
|
|
|
rpath="$($patchelf --print-rpath $1)" |
|
|
|
dir="$(dirname $1)" |
|
|
|
for lib in $($patchelf --print-needed $1); do |
|
|
|
left+=("$lib" "$rpath" "$dir") |
|
|
|
done |
|
|
|
} |
|
|
|
|
|
|
|
add_needed "$1" |
|
|
|
|
|
|
|
while [ ''${#left[@]} -ne 0 ]; do |
|
|
|
next=''${left[0]} |
|
|
|
rpath=''${left[1]} |
|
|
|
ORIGIN=''${left[2]} |
|
|
|
left=("''${left[@]:3}") |
|
|
|
if [ -z ''${seen[$next]+x} ]; then |
|
|
|
seen[$next]=1 |
|
|
|
|
|
|
|
# Ignore the dynamic linker which for some reason appears as a DT_NEEDED of glibc but isn't in glibc's RPATH. |
|
|
|
case "$next" in |
|
|
|
ld*.so.?) continue;; |
|
|
|
esac |
|
|
|
|
|
|
|
IFS=: read -ra paths <<< $rpath |
|
|
|
res= |
|
|
|
for path in "''${paths[@]}"; do |
|
|
|
path=$(eval "echo $path") |
|
|
|
if [ -f "$path/$next" ]; then |
|
|
|
res="$path/$next" |
|
|
|
echo "$res" |
|
|
|
add_needed "$res" |
|
|
|
break |
|
|
|
fi |
|
|
|
done |
|
|
|
if [ -z "$res" ]; then |
|
|
|
echo "Couldn't satisfy dependency $next" >&2 |
|
|
|
exit 1 |
|
|
|
fi |
|
|
|
fi |
|
|
|
done |
|
|
|
''; |
|
|
|
|
|
|
|
# Some additional utilities needed in stage 1, like mount, lvm, fsck |
|
|
|
# etc. We don't want to bring in all of those packages, so we just |
|
|
|
# copy what we need. Instead of using statically linked binaries, |
|
|
|
# we just copy what we need from Glibc and use patchelf to make it |
|
|
|
# work. |
|
|
|
extraUtils = pkgs.runCommandCC "extra-utils" |
|
|
|
{ nativeBuildInputs = [pkgs.buildPackages.nukeReferences]; |
|
|
|
allowedReferences = [ "out" ]; # prevent accidents like glibc being included in the initrd |
|
|
|
} |
|
|
|
'' |
|
|
|
set +o pipefail |
|
|
|
|
|
|
|
mkdir -p $out/bin $out/lib |
|
|
|
ln -s $out/bin $out/sbin |
|
|
|
|
|
|
|
copy_bin_and_libs () { |
|
|
|
[ -f "$out/bin/$(basename $1)" ] && rm "$out/bin/$(basename $1)" |
|
|
|
cp -pdv $1 $out/bin |
|
|
|
} |
|
|
|
|
|
|
|
# Copy BusyBox. |
|
|
|
for BIN in ${pkgs.busybox}/{s,}bin/*; do |
|
|
|
copy_bin_and_libs $BIN |
|
|
|
done |
|
|
|
|
|
|
|
# Copy some util-linux stuff. |
|
|
|
copy_bin_and_libs ${pkgs.util-linux}/sbin/blkid |
|
|
|
|
|
|
|
# Copy dmsetup and lvm. |
|
|
|
copy_bin_and_libs ${getBin pkgs.lvm2}/bin/dmsetup |
|
|
|
copy_bin_and_libs ${getBin pkgs.lvm2}/bin/lvm |
|
|
|
|
|
|
|
# Add RAID mdadm tool. |
|
|
|
copy_bin_and_libs ${pkgs.mdadm}/sbin/mdadm |
|
|
|
copy_bin_and_libs ${pkgs.mdadm}/sbin/mdmon |
|
|
|
|
|
|
|
# Copy udev. |
|
|
|
copy_bin_and_libs ${udev}/bin/udevadm |
|
|
|
copy_bin_and_libs ${udev}/lib/systemd/systemd-sysctl |
|
|
|
for BIN in ${udev}/lib/udev/*_id; do |
|
|
|
copy_bin_and_libs $BIN |
|
|
|
done |
|
|
|
# systemd-udevd is only a symlink to udevadm these days |
|
|
|
ln -sf udevadm $out/bin/systemd-udevd |
|
|
|
|
|
|
|
# Copy modprobe. |
|
|
|
copy_bin_and_libs ${pkgs.kmod}/bin/kmod |
|
|
|
ln -sf kmod $out/bin/modprobe |
|
|
|
|
|
|
|
# Copy resize2fs if any ext* filesystems are to be resized |
|
|
|
${optionalString (any (fs: fs.autoResize && (lib.hasPrefix "ext" fs.fsType)) fileSystems) '' |
|
|
|
# We need mke2fs in the initrd. |
|
|
|
copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/resize2fs |
|
|
|
''} |
|
|
|
|
|
|
|
# Copy secrets if needed. |
|
|
|
# |
|
|
|
# TODO: move out to a separate script; see #85000. |
|
|
|
${optionalString (!config.boot.loader.supportsInitrdSecrets) |
|
|
|
(concatStringsSep "\n" (mapAttrsToList (dest: source: |
|
|
|
let source' = if source == null then dest else source; in |
|
|
|
'' |
|
|
|
mkdir -p $(dirname "$out/secrets/${dest}") |
|
|
|
# Some programs (e.g. ssh) doesn't like secrets to be |
|
|
|
# symlinks, so we use `cp -L` here to match the |
|
|
|
# behaviour when secrets are natively supported. |
|
|
|
cp -Lr ${source'} "$out/secrets/${dest}" |
|
|
|
'' |
|
|
|
) config.boot.initrd.secrets)) |
|
|
|
} |
|
|
|
|
|
|
|
${config.boot.initrd.extraUtilsCommands} |
|
|
|
|
|
|
|
# Copy ld manually since it isn't detected correctly |
|
|
|
cp -pv ${pkgs.stdenv.cc.libc.out}/lib/ld*.so.? $out/lib |
|
|
|
|
|
|
|
# Copy all of the needed libraries |
|
|
|
find $out/bin $out/lib -type f | while read BIN; do |
|
|
|
echo "Copying libs for executable $BIN" |
|
|
|
for LIB in $(${findLibs}/bin/find-libs $BIN); do |
|
|
|
TGT="$out/lib/$(basename $LIB)" |
|
|
|
if [ ! -f "$TGT" ]; then |
|
|
|
SRC="$(readlink -e $LIB)" |
|
|
|
cp -pdv "$SRC" "$TGT" |
|
|
|
fi |
|
|
|
done |
|
|
|
done |
|
|
|
|
|
|
|
# Strip binaries further than normal. |
|
|
|
chmod -R u+w $out |
|
|
|
stripDirs "$STRIP" "lib bin" "-s" |
|
|
|
|
|
|
|
# Run patchelf to make the programs refer to the copied libraries. |
|
|
|
find $out/bin $out/lib -type f | while read i; do |
|
|
|
if ! test -L $i; then |
|
|
|
nuke-refs -e $out $i |
|
|
|
fi |
|
|
|
done |
|
|
|
|
|
|
|
find $out/bin -type f | while read i; do |
|
|
|
if ! test -L $i; then |
|
|
|
echo "patching $i..." |
|
|
|
patchelf --set-interpreter $out/lib/ld*.so.? --set-rpath $out/lib $i || true |
|
|
|
fi |
|
|
|
done |
|
|
|
|
|
|
|
if [ -z "${toString (pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform)}" ]; then |
|
|
|
# Make sure that the patchelf'ed binaries still work. |
|
|
|
echo "testing patched programs..." |
|
|
|
$out/bin/ash -c 'echo hello world' | grep "hello world" |
|
|
|
export LD_LIBRARY_PATH=$out/lib |
|
|
|
$out/bin/mount --help 2>&1 | grep -q "BusyBox" |
|
|
|
$out/bin/blkid -V 2>&1 | grep -q 'libblkid' |
|
|
|
$out/bin/udevadm --version |
|
|
|
$out/bin/dmsetup --version 2>&1 | tee -a log | grep -q "version:" |
|
|
|
LVM_SYSTEM_DIR=$out $out/bin/lvm version 2>&1 | tee -a log | grep -q "LVM" |
|
|
|
$out/bin/mdadm --version |
|
|
|
|
|
|
|
${config.boot.initrd.extraUtilsCommandsTest} |
|
|
|
fi |
|
|
|
''; # */ |
|
|
|
|
|
|
|
|
|
|
|
linkUnits = pkgs.runCommand "link-units" { |
|
|
|
allowedReferences = [ extraUtils ]; |
|
|
|
preferLocalBuild = true; |
|
|
|
} '' |
|
|
|
mkdir -p $out |
|
|
|
cp -v ${udev}/lib/systemd/network/*.link $out/ |
|
|
|
''; |
|
|
|
|
|
|
|
udevRules = pkgs.runCommand "udev-rules" { |
|
|
|
allowedReferences = [ extraUtils ]; |
|
|
|
preferLocalBuild = true; |
|
|
|
} '' |
|
|
|
mkdir -p $out |
|
|
|
|
|
|
|
echo 'ENV{LD_LIBRARY_PATH}="${extraUtils}/lib"' > $out/00-env.rules |
|
|
|
|
|
|
|
cp -v ${udev}/lib/udev/rules.d/60-cdrom_id.rules $out/ |
|
|
|
cp -v ${udev}/lib/udev/rules.d/60-persistent-storage.rules $out/ |
|
|
|
cp -v ${udev}/lib/udev/rules.d/75-net-description.rules $out/ |
|
|
|
cp -v ${udev}/lib/udev/rules.d/80-drivers.rules $out/ |
|
|
|
cp -v ${udev}/lib/udev/rules.d/80-net-setup-link.rules $out/ |
|
|
|
cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/ |
|
|
|
${config.boot.initrd.extraUdevRulesCommands} |
|
|
|
|
|
|
|
for i in $out/*.rules; do |
|
|
|
substituteInPlace $i \ |
|
|
|
--replace ata_id ${extraUtils}/bin/ata_id \ |
|
|
|
--replace scsi_id ${extraUtils}/bin/scsi_id \ |
|
|
|
--replace cdrom_id ${extraUtils}/bin/cdrom_id \ |
|
|
|
--replace ${pkgs.coreutils}/bin/basename ${extraUtils}/bin/basename \ |
|
|
|
--replace ${pkgs.util-linux}/bin/blkid ${extraUtils}/bin/blkid \ |
|
|
|
--replace ${getBin pkgs.lvm2}/bin ${extraUtils}/bin \ |
|
|
|
--replace ${pkgs.mdadm}/sbin ${extraUtils}/sbin \ |
|
|
|
--replace ${pkgs.bash}/bin/sh ${extraUtils}/bin/sh \ |
|
|
|
--replace ${udev} ${extraUtils} |
|
|
|
done |
|
|
|
|
|
|
|
# Work around a bug in QEMU, which doesn't implement the "READ |
|
|
|
# DISC INFORMATION" SCSI command: |
|
|
|
# https://bugzilla.redhat.com/show_bug.cgi?id=609049 |
|
|
|
# As a result, `cdrom_id' doesn't print |
|
|
|
# ID_CDROM_MEDIA_TRACK_COUNT_DATA, which in turn prevents the |
|
|
|
# /dev/disk/by-label symlinks from being created. We need these |
|
|
|
# in the NixOS installation CD, so use ID_CDROM_MEDIA in the |
|
|
|
# corresponding udev rules for now. This was the behaviour in |
|
|
|
# udev <= 154. See also |
|
|
|
# http://www.spinics.net/lists/hotplug/msg03935.html |
|
|
|
substituteInPlace $out/60-persistent-storage.rules \ |
|
|
|
--replace ID_CDROM_MEDIA_TRACK_COUNT_DATA ID_CDROM_MEDIA |
|
|
|
''; # */ |
|
|
|
|
|
|
|
|
|
|
|
# The init script of boot stage 1 (loading kernel modules for |
|
|
|
# mounting the root FS). |
|
|
|
bootStage1 = pkgs.substituteAll { |
|
|
|
src = ./stage-1-init.sh; |
|
|
|
|
|
|
|
shell = "${extraUtils}/bin/ash"; |
|
|
|
|
|
|
|
isExecutable = true; |
|
|
|
|
|
|
|
postInstall = '' |
|
|
|
echo checking syntax |
|
|
|
# check both with bash |
|
|
|
${pkgs.buildPackages.bash}/bin/sh -n $target |
|
|
|
# and with ash shell, just in case |
|
|
|
${pkgs.buildPackages.busybox}/bin/ash -n $target |
|
|
|
''; |
|
|
|
|
|
|
|
inherit linkUnits udevRules extraUtils modulesClosure; |
|
|
|
|
|
|
|
inherit (config.boot) resumeDevice; |
|
|
|
|
|
|
|
inherit (config.system.build) earlyMountScript; |
|
|
|
|
|
|
|
inherit (config.boot.initrd) checkJournalingFS |
|
|
|
preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules; |
|
|
|
|
|
|
|
resumeDevices = map (sd: if sd ? device then sd.device else "/dev/disk/by-label/${sd.label}") |
|
|
|
(filter (sd: hasPrefix "/dev/" sd.device && !sd.randomEncryption.enable |
|
|
|
# Don't include zram devices |
|
|
|
&& !(hasPrefix "/dev/zram" sd.device) |
|
|
|
) config.swapDevices); |
|
|
|
|
|
|
|
fsInfo = |
|
|
|
let f = fs: [ fs.mountPoint (if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}") fs.fsType (builtins.concatStringsSep "," fs.options) ]; |
|
|
|
in pkgs.writeText "initrd-fsinfo" (concatStringsSep "\n" (concatMap f fileSystems)); |
|
|
|
|
|
|
|
setHostId = optionalString (config.networking.hostId != null) '' |
|
|
|
hi="${config.networking.hostId}" |
|
|
|
${if pkgs.stdenv.isBigEndian then '' |
|
|
|
echo -ne "\x''${hi:0:2}\x''${hi:2:2}\x''${hi:4:2}\x''${hi:6:2}" > /etc/hostid |
|
|
|
'' else '' |
|
|
|
echo -ne "\x''${hi:6:2}\x''${hi:4:2}\x''${hi:2:2}\x''${hi:0:2}" > /etc/hostid |
|
|
|
''} |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
# The closure of the init script of boot stage 1 is what we put in |
|
|
|
# the initial RAM disk. |
|
|
|
initialRamdisk = pkgs.makeInitrd { |
|
|
|
name = "initrd-${kernel-name}"; |
|
|
|
inherit (config.boot.initrd) compressor compressorArgs prepend; |
|
|
|
|
|
|
|
contents = |
|
|
|
[ { object = bootStage1; |
|
|
|
symlink = "/init"; |
|
|
|
} |
|
|
|
{ object = pkgs.writeText "mdadm.conf" config.boot.initrd.mdadmConf; |
|
|
|
symlink = "/etc/mdadm.conf"; |
|
|
|
} |
|
|
|
{ object = pkgs.runCommand "initrd-kmod-blacklist-ubuntu" { |
|
|
|
src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf"; |
|
|
|
preferLocalBuild = true; |
|
|
|
} '' |
|
|
|
target=$out |
|
|
|
${pkgs.buildPackages.perl}/bin/perl -0pe 's/## file: iwlwifi.conf(.+?)##/##/s;' $src > $out |
|
|
|
''; |
|
|
|
symlink = "/etc/modprobe.d/ubuntu.conf"; |
|
|
|
} |
|
|
|
{ object = pkgs.kmod-debian-aliases; |
|
|
|
symlink = "/etc/modprobe.d/debian.conf"; |
|
|
|
} |
|
|
|
]; |
|
|
|
}; |
|
|
|
|
|
|
|
# Script to add secret files to the initrd at bootloader update time |
|
|
|
initialRamdiskSecretAppender = |
|
|
|
let |
|
|
|
compressorExe = initialRamdisk.compressorExecutableFunction pkgs; |
|
|
|
in pkgs.writeScriptBin "append-initrd-secrets" |
|
|
|
'' |
|
|
|
#!${pkgs.bash}/bin/bash -e |
|
|
|
function usage { |
|
|
|
echo "USAGE: $0 INITRD_FILE" >&2 |
|
|
|
echo "Appends this configuration's secrets to INITRD_FILE" >&2 |
|
|
|
} |
|
|
|
|
|
|
|
if [ $# -ne 1 ]; then |
|
|
|
usage |
|
|
|
exit 1 |
|
|
|
fi |
|
|
|
|
|
|
|
if [ "$1"x = "--helpx" ]; then |
|
|
|
usage |
|
|
|
exit 0 |
|
|
|
fi |
|
|
|
|
|
|
|
${lib.optionalString (config.boot.initrd.secrets == {}) |
|
|
|
"exit 0"} |
|
|
|
|
|
|
|
export PATH=${pkgs.coreutils}/bin:${pkgs.cpio}/bin:${pkgs.gzip}/bin:${pkgs.findutils}/bin |
|
|
|
|
|
|
|
function cleanup { |
|
|
|
if [ -n "$tmp" -a -d "$tmp" ]; then |
|
|
|
rm -fR "$tmp" |
|
|
|
fi |
|
|
|
} |
|
|
|
trap cleanup EXIT |
|
|
|
|
|
|
|
tmp=$(mktemp -d initrd-secrets.XXXXXXXXXX) |
|
|
|
|
|
|
|
${lib.concatStringsSep "\n" (mapAttrsToList (dest: source: |
|
|
|
let source' = if source == null then dest else toString source; in |
|
|
|
'' |
|
|
|
mkdir -p $(dirname "$tmp/${dest}") |
|
|
|
cp -a ${source'} "$tmp/${dest}" |
|
|
|
'' |
|
|
|
) config.boot.initrd.secrets) |
|
|
|
} |
|
|
|
|
|
|
|
(cd "$tmp" && find . -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null) | \ |
|
|
|
${compressorExe} ${lib.escapeShellArgs initialRamdisk.compressorArgs} >> "$1" |
|
|
|
''; |
|
|
|
|
|
|
|
in |
|
|
|
|
|
|
|
{ |
|
|
|
options = { |
|
|
|
|
|
|
|
boot.resumeDevice = mkOption { |
|
|
|
type = types.str; |
|
|
|
default = ""; |
|
|
|
example = "/dev/sda3"; |
|
|
|
description = '' |
|
|
|
Device for manual resume attempt during boot. This should be used primarily |
|
|
|
if you want to resume from file. If left empty, the swap partitions are used. |
|
|
|
Specify here the device where the file resides. |
|
|
|
You should also use <varname>boot.kernelParams</varname> to specify |
|
|
|
<literal><replaceable>resume_offset</replaceable></literal>. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.enable = mkOption { |
|
|
|
type = types.bool; |
|
|
|
default = !config.boot.isContainer; |
|
|
|
defaultText = "!config.boot.isContainer"; |
|
|
|
description = '' |
|
|
|
Whether to enable the NixOS initial RAM disk (initrd). This may be |
|
|
|
needed to perform some initialisation tasks (like mounting |
|
|
|
network/encrypted file systems) before continuing the boot process. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.prepend = mkOption { |
|
|
|
default = [ ]; |
|
|
|
type = types.listOf types.str; |
|
|
|
description = '' |
|
|
|
Other initrd files to prepend to the final initrd we are building. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.checkJournalingFS = mkOption { |
|
|
|
default = true; |
|
|
|
type = types.bool; |
|
|
|
description = '' |
|
|
|
Whether to run <command>fsck</command> on journaling filesystems such as ext3. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.mdadmConf = mkOption { |
|
|
|
default = ""; |
|
|
|
type = types.lines; |
|
|
|
description = '' |
|
|
|
Contents of <filename>/etc/mdadm.conf</filename> in stage 1. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.preLVMCommands = mkOption { |
|
|
|
default = ""; |
|
|
|
type = types.lines; |
|
|
|
description = '' |
|
|
|
Shell commands to be executed immediately before LVM discovery. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.preDeviceCommands = mkOption { |
|
|
|
default = ""; |
|
|
|
type = types.lines; |
|
|
|
description = '' |
|
|
|
Shell commands to be executed before udev is started to create |
|
|
|
device nodes. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.postDeviceCommands = mkOption { |
|
|
|
default = ""; |
|
|
|
type = types.lines; |
|
|
|
description = '' |
|
|
|
Shell commands to be executed immediately after stage 1 of the |
|
|
|
boot has loaded kernel modules and created device nodes in |
|
|
|
<filename>/dev</filename>. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.postMountCommands = mkOption { |
|
|
|
default = ""; |
|
|
|
type = types.lines; |
|
|
|
description = '' |
|
|
|
Shell commands to be executed immediately after the stage 1 |
|
|
|
filesystems have been mounted. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.preFailCommands = mkOption { |
|
|
|
default = ""; |
|
|
|
type = types.lines; |
|
|
|
description = '' |
|
|
|
Shell commands to be executed before the failure prompt is shown. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.extraUtilsCommands = mkOption { |
|
|
|
internal = true; |
|
|
|
default = ""; |
|
|
|
type = types.lines; |
|
|
|
description = '' |
|
|
|
Shell commands to be executed in the builder of the |
|
|
|
extra-utils derivation. This can be used to provide |
|
|
|
additional utilities in the initial ramdisk. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.extraUtilsCommandsTest = mkOption { |
|
|
|
internal = true; |
|
|
|
default = ""; |
|
|
|
type = types.lines; |
|
|
|
description = '' |
|
|
|
Shell commands to be executed in the builder of the |
|
|
|
extra-utils derivation after patchelf has done its |
|
|
|
job. This can be used to test additional utilities |
|
|
|
copied in extraUtilsCommands. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.extraUdevRulesCommands = mkOption { |
|
|
|
internal = true; |
|
|
|
default = ""; |
|
|
|
type = types.lines; |
|
|
|
description = '' |
|
|
|
Shell commands to be executed in the builder of the |
|
|
|
udev-rules derivation. This can be used to add |
|
|
|
additional udev rules in the initial ramdisk. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.compressor = mkOption { |
|
|
|
default = "gzip"; |
|
|
|
type = types.unspecified; # We don't have a function type... |
|
|
|
description = '' |
|
|
|
The compressor to use on the initrd image. May be any of: |
|
|
|
|
|
|
|
<itemizedlist> |
|
|
|
<listitem><para>The name of one of the predefined compressors, see <filename>pkgs/build-support/kernel/initrd-compressor-meta.nix</filename> for the definitions.</para></listitem> |
|
|
|
<listitem><para>A function which, given the nixpkgs package set, returns the path to a compressor tool, e.g. <literal>pkgs: "''${pkgs.pigz}/bin/pigz"</literal></para></listitem> |
|
|
|
<listitem><para>(not recommended, because it does not work when cross-compiling) the full path to a compressor tool, e.g. <literal>"''${pkgs.pigz}/bin/pigz"</literal></para></listitem> |
|
|
|
</itemizedlist> |
|
|
|
|
|
|
|
The given program should read data from stdin and write it to stdout compressed. |
|
|
|
''; |
|
|
|
example = "xz"; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.compressorArgs = mkOption { |
|
|
|
default = null; |
|
|
|
type = types.nullOr (types.listOf types.str); |
|
|
|
description = "Arguments to pass to the compressor for the initrd image, or null to use the compressor's defaults."; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.secrets = mkOption |
|
|
|
{ default = {}; |
|
|
|
type = types.attrsOf (types.nullOr types.path); |
|
|
|
description = |
|
|
|
'' |
|
|
|
Secrets to append to the initrd. The attribute name is the |
|
|
|
path the secret should have inside the initrd, the value |
|
|
|
is the path it should be copied from (or null for the same |
|
|
|
path inside and out). |
|
|
|
''; |
|
|
|
example = literalExample |
|
|
|
'' |
|
|
|
{ "/etc/dropbear/dropbear_rsa_host_key" = |
|
|
|
./secret-dropbear-key; |
|
|
|
} |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.initrd.supportedFilesystems = mkOption { |
|
|
|
default = [ ]; |
|
|
|
example = [ "btrfs" ]; |
|
|
|
type = types.listOf types.str; |
|
|
|
description = "Names of supported filesystem types in the initial ramdisk."; |
|
|
|
}; |
|
|
|
|
|
|
|
boot.loader.supportsInitrdSecrets = mkOption |
|
|
|
{ internal = true; |
|
|
|
default = false; |
|
|
|
type = types.bool; |
|
|
|
description = |
|
|
|
'' |
|
|
|
Whether the bootloader setup runs append-initrd-secrets. |
|
|
|
If not, any needed secrets must be copied into the initrd |
|
|
|
and thus added to the store. |
|
|
|
''; |
|
|
|
}; |
|
|
|
|
|
|
|
fileSystems = mkOption { |
|
|
|
type = with lib.types; attrsOf (submodule { |
|
|
|
options.neededForBoot = mkOption { |
|
|
|
default = false; |
|
|
|
type = types.bool; |
|
|
|
description = '' |
|
|
|
If set, this file system will be mounted in the initial ramdisk. |
|
|
|
Note that the file system will always be mounted in the initial |
|
|
|
ramdisk if its mount point is one of the following: |
|
|
|
${concatStringsSep ", " ( |
|
|
|
forEach utils.pathsNeededForBoot (i: "<filename>${i}</filename>") |
|
|
|
)}. |
|
|
|
''; |
|
|
|
}; |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
config = mkIf config.boot.initrd.enable { |
|
|
|
assertions = [ |
|
|
|
{ assertion = any (fs: fs.mountPoint == "/") fileSystems; |
|
|
|
message = "The ‘fileSystems’ option does not specify your root file system."; |
|
|
|
} |
|
|
|
{ assertion = let inherit (config.boot) resumeDevice; in |
|
|
|
resumeDevice == "" || builtins.substring 0 1 resumeDevice == "/"; |
|
|
|
message = "boot.resumeDevice has to be an absolute path." |
|
|
|
+ " Old \"x:y\" style is no longer supported."; |
|
|
|
} |
|
|
|
# TODO: remove when #85000 is fixed |
|
|
|
{ assertion = !config.boot.loader.supportsInitrdSecrets -> |
|
|
|
all (source: |
|
|
|
builtins.isPath source || |
|
|
|
(builtins.isString source && hasPrefix builtins.storeDir source)) |
|
|
|
(attrValues config.boot.initrd.secrets); |
|
|
|
message = '' |
|
|
|
boot.loader.initrd.secrets values must be unquoted paths when |
|
|
|
using a bootloader that doesn't natively support initrd |
|
|
|
secrets, e.g.: |
|
|
|
|
|
|
|
boot.initrd.secrets = { |
|
|
|
"/etc/secret" = /path/to/secret; |
|
|
|
}; |
|
|
|
|
|
|
|
Note that this will result in all secrets being stored |
|
|
|
world-readable in the Nix store! |
|
|
|
''; |
|
|
|
} |
|
|
|
]; |
|
|
|
|
|
|
|
system.build = |
|
|
|
{ inherit bootStage1 initialRamdisk initialRamdiskSecretAppender extraUtils; }; |
|
|
|
|
|
|
|
system.requiredKernelConfig = with config.lib.kernelConfig; [ |
|
|
|
(isYes "TMPFS") |
|
|
|
(isYes "BLK_DEV_INITRD") |
|
|
|
]; |
|
|
|
|
|
|
|
boot.initrd.supportedFilesystems = map (fs: fs.fsType) fileSystems; |
|
|
|
|
|
|
|
}; |
|
|
|
} |