Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]: initrd: Use systemd #120015

Closed
46 changes: 46 additions & 0 deletions nixos/modules/system/boot/find-libs.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{ writeShellScriptBin, patchelf }:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we split out the refactoring of moving these two scripts into different files? I'd love to pick them into master already (as long as they are a no-op). This reduces the amount of changes this PR introduces and we can rule out some issues during the transition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

find-libs gets removed in a later commit. The rust program handles that work now.


writeShellScriptBin "find-libs" ''
set -euo pipefail

declare -A seen
declare -a left

patchelf="${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

IFS=: read -ra paths <<< $rpath
res=
for path in "''${paths[@]}" $ORIGIN; 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
''
91 changes: 91 additions & 0 deletions nixos/modules/system/boot/make-initrd.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
let
# Some metadata on various compression programs, relevant to naming
# the initramfs file and, if applicable, generating a u-boot image
# from it.
compressors = import ../../../../pkgs/build-support/kernel/initrd-compressor-meta.nix;
# Get the basename of the actual compression program from the whole
# compression command, for the purpose of guessing the u-boot
# compression type and filename extension.
compressorName = fullCommand: builtins.elemAt (builtins.match "([^ ]*/)?([^ ]+).*" fullCommand) 1;
in
{ lib, stdenvNoCC, writeShellScript, findLibs, jq, coreutils, gzip, cpio, findutils, gnugrep, rsync, pkgsBuildHost
# Name of the derivation (not of the resulting file!)
, name ? "initrd"

# Program used to compress the cpio archive; use "cat" for no compression.
# This can also be a function which takes a package set and returns the path to the compressor,
# such as `pkgs: "${pkgs.lzop}/bin/lzop"`.
, compressor ? "gzip"
, _compressorFunction ?
if lib.isFunction compressor then compressor
else if ! builtins.hasContext compressor && builtins.hasAttr compressor compressors then compressors.${compressor}.executable
else _: compressor
, _compressorExecutable ? _compressorFunction pkgsBuildHost
, _compressorName ? compressorName _compressorExecutable
, _compressorMeta ? compressors.${_compressorName} or {}

# List of arguments to pass to the compressor program, or null to use its defaults
, compressorArgs ? null
, _compressorArgsReal ? if compressorArgs == null then _compressorMeta.defaultArgs or [] else compressorArgs

# Filename extension to use for the compressed initramfs. This is
# included for clarity, but $out/initrd will always be a symlink to
# the final image.
# If this isn't guessed, you may want to complete the metadata above and send a PR :)
, extension ? _compressorMeta.extension or
(throw "Unrecognised compressor ${_compressorName}, please specify filename extension")

, contents ? [ ]
}:

stdenvNoCC.mkDerivation {
name = "initrd";

__structuredAttrs = true;

inherit contents extension;
PATH =
lib.concatMapStringsSep ":" (p: "${p}/bin") [ findLibs jq coreutils cpio findutils gnugrep rsync ];

compress = "${_compressorExecutable} ${lib.escapeShellArgs _compressorArgsReal}";
passthru = {
compressorExecutableFunction = _compressorFunction;
compressorArgs = _compressorArgsReal;
};

builder = writeShellScript "builder" ''
set -euo pipefail
source .attrs.sh
export out=''${outputs[out]}

mkdir root

jq -cMr '.contents[] | [.object, .symlink, .executable][]' < .attrs.json \
| while read -r obj && read -r sym && read -r exe; do
test -d "$obj" && obj="$obj/"
mkdir -p "root/$(dirname "$obj")"
(set -x; rsync -a "$obj" "root/$obj")

if [ "$sym" != null ]; then
mkdir -p "root/$(dirname "$sym")"
ln -s "$obj" "root/$sym"
fi

if [ "$exe" = true ]; then
find "$obj" -executable -type f | while read -r f; do
(head -c 4 "$f" | grep ELF > /dev/null) || continue
(find-libs "$f" || true) | while read -r lib; do
if [ ! -e "root/$lib" ]; then
mkdir -p "$(dirname "root/$lib")"
cp --preserve=all "$lib" "root/$lib"
fi
done
done
fi
done

mkdir "$out"
(cd root && find * -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null | eval -- $compress >> $out/initrd)
ln -s initrd $out/initrd$extension
'';
}
Loading