Home Explore Blog Models CI



nixpkgs

2nd chunk of `pkgs/build-support/kernel/make-initrd-ng/README.md`
03d6623996f7ecd997152bd0d5e0b2e246f990ac1aa592330000000100000bed
does mean that it is the burden of the developer to ensure that all
necessary dependencies are copied in, as closures won't be
consulted. However, it is rare that full closures are actually
desirable, so in the traditional initrd, the developer was likely to
do manual work on patching the dependencies explicitly anyway.

# How it works

This program is similar to its inspiration (`find-libs` from the
traditional initrd), except that it also handles symlinks and
directories according to certain rules. As input, it receives a
sequence of pairs of paths. The first path is an object to copy into
initrd. The second path (if not empty) is the path to a symlink that
should be placed in the initrd, pointing to that object. How that
object is copied depends on its type.

1. A regular file is copied directly to the same absolute path in the
   initrd.

   - If it is *also* an ELF file, then all of its direct shared
     library dependencies are also listed as objects to be copied.

   - If an unwrapped file exists as `.[filename]-wrapped`, then it is
     also listed as an object to be copied.

2. A directory's direct children are listed as objects to be copied,
   and a directory at the same absolute path in the initrd is created.

3. A symlink's target is listed as an object to be copied.

There are a couple of quirks to mention here. First, the term "object"
refers to the final file path that the developer intends to have
copied into initrd. This means any parent directory is not considered
an object just because its child was listed as an object in the
program input; instead those intermediate directories are simply
created in support of the target object. Second, shared libraries,
directory children, and symlink targets aren't immediately recursed,
because they simply get listed as objects themselves, and are
therefore traversed when they themselves are processed. Finally,
symlinks in the intermediate directories leading to an object are
preserved, meaning an input object `/a/symlink/b` will just result in
initrd containing `/a/symlink -> /target/b` and `/target/b`, even if
`/target` has other children. Preserving symlinks in this manner is
important for things like systemd.

These rules automate the most important and obviously necessary
copying that needs to be done in most cases, allowing programs and
configuration files to go unpatched, while keeping the content of the
initrd to a minimum.

# Why Rust?

- A prototype of this logic was written in Bash, in an attempt to keep
  with its `find-libs` ancestor, but that program was difficult to
  write, and ended up taking several minutes to run. This program runs
  in less than a second, and the code is substantially easier to work
  with.

- This will not require end users to install a rust toolchain to use
  NixOS, as long as this tool is cached by Hydra. And if you're
  bootstrapping NixOS from source, rustc is already required anyway.

- Rust was favored over Python for its type system, and because if you
  want to go fast, why not go *really fast*?

Title: NixOS Initrd Copying Program: Implementation and Rust Rationale
Summary
This chunk describes a new program, inspired by `find-libs`, designed to optimize NixOS's `initrd` generation by selectively copying objects and their dependencies. It details how the program processes input paths, outlining specific rules for copying regular files (including special handling for ELF files and their shared libraries), directories (copying their children), and symlinks (copying their targets). The goal is to automate essential copying, keep `initrd` content minimal, and avoid the need for patching programs. The text also explains the decision to implement the program in Rust, citing its significantly faster performance (under a second compared to minutes for a Bash prototype), improved development experience, and type system advantages over Python, without requiring end-users to install a Rust toolchain.