Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1{
2 lib,
3 stdenv,
4 buildPackages,
5 bash,
6 bashInteractive,
7 busybox,
8 coreutils,
9 cpio,
10 dpkg,
11 e2fsprogs,
12 fetchurl,
13 glibc,
14 kmod,
15 linux,
16 makeInitrd,
17 makeModulesClosure,
18 mtdutils,
19 rpm,
20 runCommand,
21 util-linux,
22 virtiofsd,
23 writeScript,
24 writeText,
25 xz,
26 zstd,
27
28 # ----------------------------
29 # The following arguments form the "interface" of `pkgs.vmTools`.
30 # Note that `img` is a real package, but is set to this default in `all-packages.nix`.
31 # ----------------------------
32 customQemu ? null,
33 kernel ? linux,
34 img ? stdenv.hostPlatform.linux-kernel.target,
35 storeDir ? builtins.storeDir,
36 rootModules ? [
37 "virtio_pci"
38 "virtio_mmio"
39 "virtio_blk"
40 "virtio_balloon"
41 "virtio_rng"
42 "ext4"
43 "virtiofs"
44 "crc32c_generic"
45 ],
46}:
47
48let
49 qemu-common = import ../../../nixos/lib/qemu-common.nix { inherit lib stdenv; };
50
51 qemu = buildPackages.qemu_kvm;
52
53 modulesClosure = makeModulesClosure {
54 kernel = lib.getOutput "modules" kernel;
55 inherit rootModules;
56 firmware = kernel;
57 };
58
59 hd = "vda"; # either "sda" or "vda"
60
61 initrdUtils =
62 runCommand "initrd-utils"
63 {
64 nativeBuildInputs = [ buildPackages.nukeReferences ];
65 allowedReferences = [
66 "out"
67 modulesClosure
68 ]; # prevent accidents like glibc being included in the initrd
69 }
70 ''
71 mkdir -p $out/bin
72 mkdir -p $out/lib
73
74 # Copy what we need from Glibc.
75 cp -p \
76 ${stdenv.cc.libc}/lib/ld-*.so.? \
77 ${stdenv.cc.libc}/lib/libc.so.* \
78 ${stdenv.cc.libc}/lib/libm.so.* \
79 ${stdenv.cc.libc}/lib/libresolv.so.* \
80 ${stdenv.cc.libc}/lib/libpthread.so.* \
81 ${zstd.out}/lib/libzstd.so.* \
82 ${xz.out}/lib/liblzma.so.* \
83 $out/lib
84
85 # Copy BusyBox.
86 cp -pd ${busybox}/bin/* $out/bin
87 cp -pd ${kmod}/bin/* $out/bin
88
89 # Run patchelf to make the programs refer to the copied libraries.
90 for i in $out/bin/* $out/lib/*; do if ! test -L $i; then nuke-refs $i; fi; done
91
92 for i in $out/bin/*; do
93 if [ -f "$i" -a ! -L "$i" ]; then
94 echo "patching $i..."
95 patchelf --set-interpreter $out/lib/ld-*.so.? --set-rpath $out/lib $i || true
96 fi
97 done
98
99 find $out/lib -type f \! -name 'ld*.so.?' | while read i; do
100 echo "patching $i..."
101 patchelf --set-rpath $out/lib $i
102 done
103 ''; # */
104
105 stage1Init = writeScript "vm-run-stage1" ''
106 #! ${initrdUtils}/bin/ash -e
107
108 export PATH=${initrdUtils}/bin
109
110 mkdir /etc
111 echo -n > /etc/fstab
112
113 mount -t proc none /proc
114 mount -t sysfs none /sys
115
116 echo 2 > /proc/sys/vm/panic_on_oom
117
118 for o in $(cat /proc/cmdline); do
119 case $o in
120 mountDisk=*)
121 mountDisk=''${mountDisk#mountDisk=}
122 ;;
123 command=*)
124 set -- $(IFS==; echo $o)
125 command=$2
126 ;;
127 esac
128 done
129
130 echo "loading kernel modules..."
131 for i in $(cat ${modulesClosure}/insmod-list); do
132 insmod $i || echo "warning: unable to load $i"
133 done
134
135 mount -t devtmpfs devtmpfs /dev
136 ln -s /proc/self/fd /dev/fd
137 ln -s /proc/self/fd/0 /dev/stdin
138 ln -s /proc/self/fd/1 /dev/stdout
139 ln -s /proc/self/fd/2 /dev/stderr
140
141 ifconfig lo up
142
143 mkdir /fs
144
145 if test -z "$mountDisk"; then
146 mount -t tmpfs none /fs
147 elif [[ -e "$mountDisk" ]]; then
148 mount "$mountDisk" /fs
149 else
150 mount /dev/${hd} /fs
151 fi
152
153 mkdir -p /fs/dev
154 mount -o bind /dev /fs/dev
155
156 mkdir -p /fs/dev/shm /fs/dev/pts
157 mount -t tmpfs -o "mode=1777" none /fs/dev/shm
158 mount -t devpts none /fs/dev/pts
159
160 echo "mounting Nix store..."
161 mkdir -p /fs${storeDir}
162 mount -t virtiofs store /fs${storeDir}
163
164 mkdir -p /fs/tmp /fs/run /fs/var
165 mount -t tmpfs -o "mode=1777" none /fs/tmp
166 mount -t tmpfs -o "mode=755" none /fs/run
167 ln -sfn /run /fs/var/run
168
169 echo "mounting host's temporary directory..."
170 mkdir -p /fs/tmp/xchg
171 mount -t virtiofs xchg /fs/tmp/xchg
172
173 mkdir -p /fs/proc
174 mount -t proc none /fs/proc
175
176 mkdir -p /fs/sys
177 mount -t sysfs none /fs/sys
178
179 mkdir -p /fs/etc
180 ln -sf /proc/mounts /fs/etc/mtab
181 echo "127.0.0.1 localhost" > /fs/etc/hosts
182 # Ensures tools requiring /etc/passwd will work (e.g. nix)
183 if [ ! -e /fs/etc/passwd ]; then
184 echo "root:x:0:0:System administrator:/root:/bin/sh" > /fs/etc/passwd
185 fi
186
187 echo "starting stage 2 ($command)"
188 exec switch_root /fs $command
189 '';
190
191 initrd = makeInitrd {
192 contents = [
193 {
194 object = stage1Init;
195 symlink = "/init";
196 }
197 ];
198 };
199
200 stage2Init = writeScript "vm-run-stage2" ''
201 #! ${bash}/bin/sh
202 set -euo pipefail
203 source /tmp/xchg/saved-env
204 if [ -f /tmp/xchg/.attrs.sh ]; then
205 source /tmp/xchg/.attrs.sh
206 export NIX_ATTRS_JSON_FILE=/tmp/xchg/.attrs.json
207 export NIX_ATTRS_SH_FILE=/tmp/xchg/.attrs.sh
208 fi
209
210 export NIX_STORE=${storeDir}
211 export NIX_BUILD_TOP=/tmp
212 export TMPDIR=/tmp
213 export PATH=/empty
214 cd "$NIX_BUILD_TOP"
215
216 source $stdenv/setup
217
218 if ! test -e /bin/sh; then
219 ${coreutils}/bin/mkdir -p /bin
220 ${coreutils}/bin/ln -s ${bash}/bin/sh /bin/sh
221 fi
222
223 # Set up automatic kernel module loading.
224 export MODULE_DIR=${lib.getOutput "modules" kernel}/lib/modules/
225 ${coreutils}/bin/cat <<EOF > /run/modprobe
226 #! ${bash}/bin/sh
227 export MODULE_DIR=$MODULE_DIR
228 exec ${kmod}/bin/modprobe "\$@"
229 EOF
230 ${coreutils}/bin/chmod 755 /run/modprobe
231 echo /run/modprobe > /proc/sys/kernel/modprobe
232
233 # For debugging: if this is the second time this image is run,
234 # then don't start the build again, but instead drop the user into
235 # an interactive shell.
236 if test -n "$origBuilder" -a ! -e /.debug; then
237 exec < /dev/null
238 ${coreutils}/bin/touch /.debug
239 declare -a argsArray=()
240 concatTo argsArray origArgs
241 "$origBuilder" "''${argsArray[@]}"
242 echo $? > /tmp/xchg/in-vm-exit
243
244 ${busybox}/bin/mount -o remount,ro dummy /
245
246 ${busybox}/bin/poweroff -f
247 else
248 export PATH=/bin:/usr/bin:${coreutils}/bin
249 echo "Starting interactive shell..."
250 echo "(To run the original builder: \$origBuilder \$origArgs)"
251 exec ${busybox}/bin/setsid ${bashInteractive}/bin/bash < /dev/${qemu-common.qemuSerialDevice} &> /dev/${qemu-common.qemuSerialDevice}
252 fi
253 '';
254
255 qemuCommandLinux = ''
256 ${if (customQemu != null) then customQemu else (qemu-common.qemuBinary qemu)} \
257 -nographic -no-reboot \
258 -device virtio-rng-pci \
259 -chardev socket,id=store,path=virtio-store.sock \
260 -device vhost-user-fs-pci,chardev=store,tag=store \
261 -chardev socket,id=xchg,path=virtio-xchg.sock \
262 -device vhost-user-fs-pci,chardev=xchg,tag=xchg \
263 ''${diskImage:+-drive file=$diskImage,if=virtio,cache=unsafe,werror=report} \
264 -kernel ${kernel}/${img} \
265 -initrd ${initrd}/initrd \
266 -append "console=${qemu-common.qemuSerialDevice} panic=1 command=${stage2Init} mountDisk=$mountDisk loglevel=4" \
267 $QEMU_OPTS
268 '';
269
270 vmRunCommand =
271 qemuCommand:
272 writeText "vm-run" ''
273 ${coreutils}/bin/mkdir xchg
274 export > xchg/saved-env
275
276 if [ -f "''${NIX_ATTRS_SH_FILE-}" ]; then
277 ${coreutils}/bin/cp $NIX_ATTRS_JSON_FILE $NIX_ATTRS_SH_FILE xchg
278 source "$NIX_ATTRS_SH_FILE"
279 fi
280 source $stdenv/setup
281
282 eval "$preVM"
283
284 if [ "$enableParallelBuilding" = 1 ]; then
285 QEMU_NR_VCPUS=0
286 if [ ''${NIX_BUILD_CORES:-0} = 0 ]; then
287 QEMU_NR_VCPUS="$(nproc)"
288 else
289 QEMU_NR_VCPUS="$NIX_BUILD_CORES"
290 fi
291 # qemu only supports 255 vCPUs (see error from `qemu-system-x86_64 -smp 256`)
292 if [ "$QEMU_NR_VCPUS" -gt 255 ]; then
293 QEMU_NR_VCPUS=255
294 fi
295 QEMU_OPTS+=" -smp cpus=$QEMU_NR_VCPUS"
296 fi
297
298 # Write the command to start the VM to a file so that the user can
299 # debug inside the VM if the build fails (when Nix is called with
300 # the -K option to preserve the temporary build directory).
301 ${coreutils}/bin/cat > ./run-vm <<EOF
302 #! ${bash}/bin/sh
303 ''${diskImage:+diskImage=$diskImage}
304 # GitHub Actions runners seems to not allow installing seccomp filter: https://github.com/rcambrj/nix-pi-loader/issues/1#issuecomment-2605497516
305 # Since we are running in a sandbox already, the difference between seccomp and none is minimal
306 ${virtiofsd}/bin/virtiofsd --xattr --socket-path virtio-store.sock --sandbox none --seccomp none --shared-dir "${storeDir}" &
307 ${virtiofsd}/bin/virtiofsd --xattr --socket-path virtio-xchg.sock --sandbox none --seccomp none --shared-dir xchg &
308
309 # Wait until virtiofsd has created these sockets to avoid race condition.
310 until [[ -e virtio-store.sock ]]; do ${coreutils}/bin/sleep 1; done
311 until [[ -e virtio-xchg.sock ]]; do ${coreutils}/bin/sleep 1; done
312
313 ${qemuCommand}
314 EOF
315
316 ${coreutils}/bin/chmod +x ./run-vm
317 source ./run-vm
318
319 if ! test -e xchg/in-vm-exit; then
320 echo "Virtual machine didn't produce an exit code."
321 exit 1
322 fi
323
324 exitCode="$(${coreutils}/bin/cat xchg/in-vm-exit)"
325 if [ "$exitCode" != "0" ]; then
326 exit "$exitCode"
327 fi
328
329 eval "$postVM"
330 '';
331
332 # A bash script fragment that produces a disk image at `destination`.
333 createEmptyImage =
334 {
335 # Disk image size in MiB (1024*1024 bytes)
336 size,
337 # Name that will be written to ${destination}/nix-support/full-name
338 fullName,
339 # Where to write the image files, defaulting to $out
340 destination ? "$out",
341 }:
342 ''
343 mkdir -p ${destination}
344 diskImage=${destination}/disk-image.qcow2
345 ${qemu}/bin/qemu-img create -f qcow2 $diskImage "${toString size}M"
346
347 mkdir ${destination}/nix-support
348 echo "${fullName}" > ${destination}/nix-support/full-name
349 '';
350
351 defaultCreateRootFS = ''
352 mkdir /mnt
353 ${e2fsprogs}/bin/mkfs.ext4 /dev/${hd}
354 ${util-linux}/bin/mount -t ext4 /dev/${hd} /mnt
355
356 if test -e /mnt/.debug; then
357 exec ${bash}/bin/sh
358 fi
359 touch /mnt/.debug
360
361 mkdir /mnt/proc /mnt/dev /mnt/sys
362 '';
363
364 /*
365 Run a derivation in a Linux virtual machine (using Qemu/KVM). By
366 default, there is no disk image; the root filesystem is a tmpfs,
367 and the nix store is shared with the host (via the 9P protocol).
368 Thus, any pure Nix derivation should run unmodified, e.g. the
369 call
370
371 runInLinuxVM patchelf
372
373 will build the derivation `patchelf' inside a VM. The attribute
374 `preVM' can optionally contain a shell command to be evaluated
375 *before* the VM is started (i.e., on the host). The attribute
376 `memSize' specifies the memory size of the VM in MiB (1024*1024
377 bytes), defaulting to 512. The attribute `diskImage' can
378 optionally specify a file system image to be attached to /dev/sda.
379 (Note that currently we expect the image to contain a filesystem,
380 not a full disk image with a partition table etc.)
381
382 If the build fails and Nix is run with the `-K' option, a script
383 `run-vm' will be left behind in the temporary build directory
384 that allows you to boot into the VM and debug it interactively.
385 */
386
387 runInLinuxVM =
388 drv:
389 lib.overrideDerivation drv (
390 {
391 memSize ? 512,
392 QEMU_OPTS ? "",
393 args,
394 builder,
395 ...
396 }:
397 {
398 requiredSystemFeatures = [ "kvm" ];
399 builder = "${bash}/bin/sh";
400 args = [
401 "-e"
402 (vmRunCommand qemuCommandLinux)
403 ];
404 origArgs = args;
405 origBuilder = builder;
406 QEMU_OPTS = "${QEMU_OPTS} -m ${toString memSize} -object memory-backend-memfd,id=mem,size=${toString memSize}M,share=on -machine memory-backend=mem";
407 passAsFile = [ ]; # HACK fix - see https://github.com/NixOS/nixpkgs/issues/16742
408 }
409 );
410
411 extractFs =
412 {
413 file,
414 fs ? null,
415 }:
416 runInLinuxVM (
417 stdenv.mkDerivation {
418 name = "extract-file";
419 buildInputs = [ util-linux ];
420 buildCommand = ''
421 ln -s ${kernel}/lib /lib
422 ${kmod}/bin/modprobe loop
423 ${kmod}/bin/modprobe ext4
424 ${kmod}/bin/modprobe hfs
425 ${kmod}/bin/modprobe hfsplus
426 ${kmod}/bin/modprobe squashfs
427 ${kmod}/bin/modprobe iso9660
428 ${kmod}/bin/modprobe ufs
429 ${kmod}/bin/modprobe cramfs
430
431 mkdir -p $out
432 mkdir -p tmp
433 mount -o loop,ro,ufstype=44bsd ${lib.optionalString (fs != null) "-t ${fs} "}${file} tmp ||
434 mount -o loop,ro ${lib.optionalString (fs != null) "-t ${fs} "}${file} tmp
435 cp -Rv tmp/* $out/ || exit 0
436 '';
437 }
438 );
439
440 extractMTDfs =
441 {
442 file,
443 fs ? null,
444 }:
445 runInLinuxVM (
446 stdenv.mkDerivation {
447 name = "extract-file-mtd";
448 buildInputs = [
449 util-linux
450 mtdutils
451 ];
452 buildCommand = ''
453 ln -s ${kernel}/lib /lib
454 ${kmod}/bin/modprobe mtd
455 ${kmod}/bin/modprobe mtdram total_size=131072
456 ${kmod}/bin/modprobe mtdchar
457 ${kmod}/bin/modprobe mtdblock
458 ${kmod}/bin/modprobe jffs2
459 ${kmod}/bin/modprobe zlib
460
461 mkdir -p $out
462 mkdir -p tmp
463
464 dd if=${file} of=/dev/mtd0
465 mount ${lib.optionalString (fs != null) "-t ${fs} "}/dev/mtdblock0 tmp
466
467 cp -R tmp/* $out/
468 '';
469 }
470 );
471
472 /*
473 Like runInLinuxVM, but run the build not using the stdenv from
474 the Nix store, but using the tools provided by /bin, /usr/bin
475 etc. from the specified filesystem image, which typically is a
476 filesystem containing a non-NixOS Linux distribution.
477 */
478
479 runInLinuxImage =
480 drv:
481 runInLinuxVM (
482 lib.overrideDerivation drv (attrs: {
483 mountDisk = attrs.mountDisk or true;
484
485 /*
486 Mount `image' as the root FS, but use a temporary copy-on-write
487 image since we don't want to (and can't) write to `image'.
488 */
489 preVM = ''
490 diskImage=$(pwd)/disk-image.qcow2
491 origImage=${attrs.diskImage}
492 if test -d "$origImage"; then origImage="$origImage/disk-image.qcow2"; fi
493 ${qemu}/bin/qemu-img create -F ${attrs.diskImageFormat} -b "$origImage" -f qcow2 $diskImage
494 '';
495
496 /*
497 Inside the VM, run the stdenv setup script normally, but at the
498 very end set $PATH and $SHELL to the `native' paths for the
499 distribution inside the VM.
500 */
501 postHook = ''
502 PATH=/usr/bin:/bin:/usr/sbin:/sbin
503 SHELL=/bin/sh
504 eval "$origPostHook"
505 '';
506
507 origPostHook = lib.optionalString (attrs ? postHook) attrs.postHook;
508
509 # Don't run Nix-specific build steps like patchelf.
510 fixupPhase = "true";
511 })
512 );
513
514 /*
515 Create a filesystem image of the specified size and fill it with
516 a set of RPM packages.
517 */
518
519 fillDiskWithRPMs =
520 {
521 size ? 4096,
522 rpms,
523 name,
524 fullName,
525 preInstall ? "",
526 postInstall ? "",
527 runScripts ? true,
528 createRootFS ? defaultCreateRootFS,
529 QEMU_OPTS ? "",
530 memSize ? 512,
531 unifiedSystemDir ? false,
532 }:
533
534 runInLinuxVM (
535 stdenv.mkDerivation {
536 inherit
537 name
538 preInstall
539 postInstall
540 rpms
541 QEMU_OPTS
542 memSize
543 ;
544 preVM = createEmptyImage { inherit size fullName; };
545
546 buildCommand = ''
547 ${createRootFS}
548
549 chroot=$(type -tP chroot)
550
551 # Make the Nix store available in /mnt, because that's where the RPMs live.
552 mkdir -p /mnt${storeDir}
553 ${util-linux}/bin/mount -o bind ${storeDir} /mnt${storeDir}
554 # Some programs may require devices in /dev to be available (e.g. /dev/random)
555 ${util-linux}/bin/mount -o bind /dev /mnt/dev
556
557 # Newer distributions like Fedora 18 require /lib etc. to be
558 # symlinked to /usr.
559 ${lib.optionalString unifiedSystemDir ''
560 mkdir -p /mnt/usr/bin /mnt/usr/lib /mnt/usr/lib64
561 ln -s /usr/bin /mnt/bin
562 ln -s /usr/bin /mnt/sbin
563 ln -s /usr/bin /mnt/usr/sbin
564 ln -s /usr/lib /mnt/lib
565 ln -s /usr/lib64 /mnt/lib64
566 ${util-linux}/bin/mount -t proc none /mnt/proc
567 ''}
568
569 echo "unpacking RPMs..."
570 set +o pipefail
571 for i in $rpms; do
572 echo "$i..."
573 ${rpm}/bin/rpm2cpio "$i" | chroot /mnt ${cpio}/bin/cpio -i --make-directories --unconditional
574 done
575
576 eval "$preInstall"
577
578 echo "initialising RPM DB..."
579 PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \
580 ldconfig -v || true
581 PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \
582 rpm --initdb
583
584 ${util-linux}/bin/mount -o bind /tmp /mnt/tmp
585
586 echo "installing RPMs..."
587 PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \
588 rpm -iv --nosignature ${lib.optionalString (!runScripts) "--noscripts"} $rpms
589
590 echo "running post-install script..."
591 eval "$postInstall"
592
593 rm /mnt/.debug
594
595 ${util-linux}/bin/umount /mnt${storeDir} /mnt/tmp /mnt/dev ${lib.optionalString unifiedSystemDir "/mnt/proc"}
596 ${util-linux}/bin/umount /mnt
597 '';
598
599 passthru = { inherit fullName; };
600 }
601 );
602
603 /*
604 Generate a script that can be used to run an interactive session
605 in the given image.
606 */
607
608 makeImageTestScript =
609 image:
610 writeScript "image-test" ''
611 #! ${bash}/bin/sh
612 if test -z "$1"; then
613 echo "Syntax: $0 <copy-on-write-temp-file>"
614 exit 1
615 fi
616 diskImage="$1"
617 if ! test -e "$diskImage"; then
618 ${qemu}/bin/qemu-img create -b ${image}/disk-image.qcow2 -f qcow2 -F qcow2 "$diskImage"
619 fi
620 export TMPDIR=$(mktemp -d)
621 export out=/dummy
622 export origBuilder=
623 export origArgs=
624 mkdir $TMPDIR/xchg
625 export > $TMPDIR/xchg/saved-env
626 mountDisk=1
627 ${qemuCommandLinux}
628 '';
629
630 /*
631 Build RPM packages from the tarball `src' in the Linux
632 distribution installed in the filesystem `diskImage'. The
633 tarball must contain an RPM specfile.
634 */
635
636 buildRPM =
637 attrs:
638 runInLinuxImage (
639 stdenv.mkDerivation (
640 {
641 prePhases = [
642 "prepareImagePhase"
643 "sysInfoPhase"
644 ];
645 dontConfigure = true;
646
647 outDir = "rpms/${attrs.diskImage.name}";
648
649 prepareImagePhase = ''
650 if test -n "$extraRPMs"; then
651 for rpmdir in $extraRPMs ; do
652 rpm -iv $(ls $rpmdir/rpms/*/*.rpm | grep -v 'src\.rpm' | sort | head -1)
653 done
654 fi
655 '';
656
657 sysInfoPhase = ''
658 echo "System/kernel: $(uname -a)"
659 if test -e /etc/fedora-release; then echo "Fedora release: $(cat /etc/fedora-release)"; fi
660 if test -e /etc/SuSE-release; then echo "SUSE release: $(cat /etc/SuSE-release)"; fi
661 echo "installed RPM packages"
662 rpm -qa --qf "%{Name}-%{Version}-%{Release} (%{Arch}; %{Distribution}; %{Vendor})\n"
663 '';
664
665 buildPhase = ''
666 eval "$preBuild"
667
668 srcName="$(rpmspec --srpm -q --qf '%{source}' *.spec)"
669 cp "$src" "$srcName" # `ln' doesn't work always work: RPM requires that the file is owned by root
670
671 export HOME=/tmp/home
672 mkdir $HOME
673
674 rpmout=/tmp/rpmout
675 mkdir $rpmout $rpmout/SPECS $rpmout/BUILD $rpmout/RPMS $rpmout/SRPMS
676
677 echo "%_topdir $rpmout" >> $HOME/.rpmmacros
678
679 if [ `uname -m` = i686 ]; then extra="--target i686-linux"; fi
680 rpmbuild -vv $extra -ta "$srcName"
681
682 eval "$postBuild"
683 '';
684
685 installPhase = ''
686 eval "$preInstall"
687
688 mkdir -p $out/$outDir
689 find $rpmout -name "*.rpm" -exec cp {} $out/$outDir \;
690
691 for i in $out/$outDir/*.rpm; do
692 echo "Generated RPM/SRPM: $i"
693 rpm -qip $i
694 done
695
696 eval "$postInstall"
697 ''; # */
698 }
699 // attrs
700 )
701 );
702
703 /*
704 Create a filesystem image of the specified size and fill it with
705 a set of Debian packages. `debs' must be a list of list of
706 .deb files, namely, the Debian packages grouped together into
707 strongly connected components. See deb/deb-closure.nix.
708 */
709
710 fillDiskWithDebs =
711 {
712 size ? 4096,
713 debs,
714 name,
715 fullName,
716 postInstall ? null,
717 createRootFS ? defaultCreateRootFS,
718 QEMU_OPTS ? "",
719 memSize ? 512,
720 ...
721 }@args:
722
723 runInLinuxVM (
724 stdenv.mkDerivation (
725 {
726 inherit
727 name
728 postInstall
729 QEMU_OPTS
730 memSize
731 ;
732
733 debs = (lib.intersperse "|" debs);
734
735 preVM = createEmptyImage { inherit size fullName; };
736
737 buildCommand = ''
738 ${createRootFS}
739
740 PATH=$PATH:${
741 lib.makeBinPath [
742 dpkg
743 glibc
744 xz
745 ]
746 }
747
748 # Unpack the .debs. We do this to prevent pre-install scripts
749 # (which have lots of circular dependencies) from barfing.
750 echo "unpacking Debs..."
751
752 for deb in $debs; do
753 if test "$deb" != "|"; then
754 echo "$deb..."
755 dpkg-deb --extract "$deb" /mnt
756 fi
757 done
758
759 # Make the Nix store available in /mnt, because that's where the .debs live.
760 mkdir -p /mnt/inst${storeDir}
761 ${util-linux}/bin/mount -o bind ${storeDir} /mnt/inst${storeDir}
762 ${util-linux}/bin/mount -o bind /proc /mnt/proc
763 ${util-linux}/bin/mount -o bind /dev /mnt/dev
764
765 # Misc. files/directories assumed by various packages.
766 echo "initialising Dpkg DB..."
767 touch /mnt/etc/shells
768 touch /mnt/var/lib/dpkg/status
769 touch /mnt/var/lib/dpkg/available
770 touch /mnt/var/lib/dpkg/diversions
771
772 # Now install the .debs. This is basically just to register
773 # them with dpkg and to make their pre/post-install scripts
774 # run.
775 echo "installing Debs..."
776
777 export DEBIAN_FRONTEND=noninteractive
778
779 oldIFS="$IFS"
780 IFS="|"
781 for component in $debs; do
782 IFS="$oldIFS"
783 echo
784 echo ">>> INSTALLING COMPONENT: $component"
785 debs=
786 for i in $component; do
787 debs="$debs /inst/$i";
788 done
789 chroot=$(type -tP chroot)
790
791 # Create a fake start-stop-daemon script, as done in debootstrap.
792 mv "/mnt/sbin/start-stop-daemon" "/mnt/sbin/start-stop-daemon.REAL"
793 echo "#!/bin/true" > "/mnt/sbin/start-stop-daemon"
794 chmod 755 "/mnt/sbin/start-stop-daemon"
795
796 PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \
797 /usr/bin/dpkg --install --force-all $debs < /dev/null || true
798
799 # Move the real start-stop-daemon back into its place.
800 mv "/mnt/sbin/start-stop-daemon.REAL" "/mnt/sbin/start-stop-daemon"
801 done
802
803 echo "running post-install script..."
804 eval "$postInstall"
805
806 rm /mnt/.debug
807
808 ${util-linux}/bin/umount /mnt/inst${storeDir}
809 ${util-linux}/bin/umount /mnt/proc
810 ${util-linux}/bin/umount /mnt/dev
811 ${util-linux}/bin/umount /mnt
812 '';
813
814 passthru = { inherit fullName; };
815 }
816 // args
817 )
818 );
819
820 /*
821 Generate a Nix expression containing fetchurl calls for the
822 closure of a set of top-level RPM packages from the
823 `primary.xml.gz' file of a Fedora or openSUSE distribution.
824 */
825
826 rpmClosureGenerator =
827 {
828 name,
829 packagesLists,
830 urlPrefixes,
831 packages,
832 archs ? [ ],
833 }:
834 assert (builtins.length packagesLists) == (builtins.length urlPrefixes);
835 runCommand "${name}.nix"
836 {
837 nativeBuildInputs = [
838 buildPackages.perl
839 buildPackages.perlPackages.URI
840 buildPackages.perlPackages.XMLSimple
841 buildPackages.zstd
842 ];
843 inherit archs;
844 }
845 ''
846 ${lib.concatImapStrings (i: pl: ''
847 echo "decompressing ${pl}..."
848 case ${pl} in
849 *.zst)
850 zstd -d < ${pl} > ./packages_${toString i}.xml
851 ;;
852 *.xz | *.lzma)
853 xz -d < ${pl} > ./packages_${toString i}.xml
854 ;;
855 *.bz2)
856 bunzip2 < ${pl} > ./packages_${toString i}.xml
857 ;;
858 *.gz)
859 gunzip < ${pl} > ./packages_${toString i}.xml
860 ;;
861 *)
862 cp ${pl} ./packages_${toString i}.xml
863 ;;
864 esac
865 '') packagesLists}
866 perl -w ${rpm/rpm-closure.pl} \
867 ${
868 lib.concatImapStrings (i: pl: "./packages_${toString i}.xml ${pl.snd} ") (
869 lib.zipLists packagesLists urlPrefixes
870 )
871 } \
872 ${toString packages} > $out
873 '';
874
875 /*
876 Helper function that combines rpmClosureGenerator and
877 fillDiskWithRPMs to generate a disk image from a set of package
878 names.
879 */
880
881 makeImageFromRPMDist =
882 {
883 name,
884 fullName,
885 size ? 4096,
886 urlPrefix ? "",
887 urlPrefixes ? [ urlPrefix ],
888 packagesList ? "",
889 packagesLists ? [ packagesList ],
890 packages,
891 extraPackages ? [ ],
892 preInstall ? "",
893 postInstall ? "",
894 archs ? [
895 "noarch"
896 "i386"
897 ],
898 runScripts ? true,
899 createRootFS ? defaultCreateRootFS,
900 QEMU_OPTS ? "",
901 memSize ? 512,
902 unifiedSystemDir ? false,
903 }:
904
905 fillDiskWithRPMs {
906 inherit
907 name
908 fullName
909 size
910 preInstall
911 postInstall
912 runScripts
913 createRootFS
914 unifiedSystemDir
915 QEMU_OPTS
916 memSize
917 ;
918 rpms = import (rpmClosureGenerator {
919 inherit
920 name
921 packagesLists
922 urlPrefixes
923 archs
924 ;
925 packages = packages ++ extraPackages;
926 }) { inherit fetchurl; };
927 };
928
929 /*
930 Like `rpmClosureGenerator', but now for Debian/Ubuntu releases
931 (i.e. generate a closure from a Packages.bz2 file).
932 */
933
934 debClosureGenerator =
935 {
936 name,
937 packagesLists,
938 urlPrefix,
939 packages,
940 }:
941
942 runCommand "${name}.nix"
943 {
944 nativeBuildInputs = [
945 buildPackages.perl
946 buildPackages.dpkg
947 buildPackages.nixfmt
948 ];
949 }
950 ''
951 for i in ${toString packagesLists}; do
952 echo "adding $i..."
953 case $i in
954 *.xz | *.lzma)
955 xz -d < $i >> ./Packages
956 ;;
957 *.bz2)
958 bunzip2 < $i >> ./Packages
959 ;;
960 *.gz)
961 gzip -dc < $i >> ./Packages
962 ;;
963 esac
964 done
965
966 perl -w ${deb/deb-closure.pl} \
967 ./Packages ${urlPrefix} ${toString packages} > $out
968 nixfmt $out
969 '';
970
971 /*
972 Helper function that combines debClosureGenerator and
973 fillDiskWithDebs to generate a disk image from a set of package
974 names.
975 */
976
977 makeImageFromDebDist =
978 {
979 name,
980 fullName,
981 size ? 4096,
982 urlPrefix,
983 packagesList ? "",
984 packagesLists ? [ packagesList ],
985 packages,
986 extraPackages ? [ ],
987 postInstall ? "",
988 extraDebs ? [ ],
989 createRootFS ? defaultCreateRootFS,
990 QEMU_OPTS ? "",
991 memSize ? 512,
992 ...
993 }@args:
994
995 let
996 expr = debClosureGenerator {
997 inherit name packagesLists urlPrefix;
998 packages = packages ++ extraPackages;
999 };
1000 in
1001 (fillDiskWithDebs (
1002 {
1003 inherit
1004 name
1005 fullName
1006 size
1007 postInstall
1008 createRootFS
1009 QEMU_OPTS
1010 memSize
1011 ;
1012 debs = import expr { inherit fetchurl; } ++ extraDebs;
1013 }
1014 // args
1015 ))
1016 // {
1017 inherit expr;
1018 };
1019
1020 # The set of supported RPM-based distributions.
1021
1022 rpmDistros = {
1023 fedora42x86_64 = {
1024 name = "fedora-42-x86_64";
1025 fullName = "Fedora 42 (x86_64)";
1026 packagesList = fetchurl {
1027 url = "https://dl.fedoraproject.org/pub/fedora/linux/releases/42/Everything/x86_64/os/repodata/cd483b35df017d68b73a878a392bbf666a43d75db54c386e4720bc369eb5c3a3-primary.xml.zst";
1028 hash = "sha256-zUg7Nd8BfWi3OoeKOSu/ZmpD1121TDhuRyC8Np61w6M=";
1029 };
1030 urlPrefix = "https://dl.fedoraproject.org/pub/fedora/linux/releases/42/Everything/x86_64/os";
1031 archs = [
1032 "noarch"
1033 "x86_64"
1034 ];
1035 packages = commonFedoraPackages;
1036 unifiedSystemDir = true;
1037 };
1038
1039 fedora43x86_64 = {
1040 name = "fedora-43-x86_64";
1041 fullName = "Fedora 43 (x86_64)";
1042 packagesList = fetchurl {
1043 url = "https://dl.fedoraproject.org/pub/fedora/linux/releases/43/Everything/x86_64/os/repodata/fffa3e9f63fffd3d21b8ea5e9bb0fe349a7ed1d4e09777a618cec93a2bcc305f-primary.xml.zst";
1044 hash = "sha256-//o+n2P//T0huOpem7D+NJp+0dTgl3emGM7JOivMMF8=";
1045 };
1046 urlPrefix = "https://dl.fedoraproject.org/pub/fedora/linux/releases/43/Everything/x86_64/os";
1047 archs = [
1048 "noarch"
1049 "x86_64"
1050 ];
1051 packages = commonFedoraPackages ++ [ "gpgverify" ];
1052 unifiedSystemDir = true;
1053 };
1054
1055 # Rocky Linux's /pub/rocky/9/ URL is rolling and changes with each minor release. We use the
1056 # vault instead, which provides stable URLs for specific minor versions.
1057 rocky9x86_64 = {
1058 name = "rocky-9.6-x86_64";
1059 fullName = "Rocky Linux 9.6 (x86_64)";
1060 packagesLists = [
1061 (fetchurl {
1062 url = "https://dl.rockylinux.org/vault/rocky/9.6/BaseOS/x86_64/os/repodata/9965e429a90787a87a07eed62872d046411fb7dded524b96d74c4ce1eade327a-primary.xml.gz";
1063 hash = "sha256-mWXkKakHh6h6B+7WKHLQRkEft93tUkuW10xM4ereMno=";
1064 })
1065 (fetchurl {
1066 url = "https://dl.rockylinux.org/vault/rocky/9.6/AppStream/x86_64/os/repodata/8cc9f795679c3365c06b6135f685ebf4188a5863a5f52f09f8cabd4f09c4dfa1-primary.xml.gz";
1067 hash = "sha256-jMn3lWecM2XAa2E19oXr9BiKWGOl9S8J+Mq9TwnE36E=";
1068 })
1069 ];
1070 urlPrefixes = [
1071 "https://dl.rockylinux.org/vault/rocky/9.6/BaseOS/x86_64/os"
1072 "https://dl.rockylinux.org/vault/rocky/9.6/AppStream/x86_64/os"
1073 ];
1074 archs = [
1075 "noarch"
1076 "x86_64"
1077 ];
1078 packages = commonRockyPackages ++ [
1079 "annobin"
1080 ];
1081 unifiedSystemDir = true;
1082 };
1083
1084 # Rocky Linux's /pub/rocky/10/ URL is rolling and changes with each minor release. We use the
1085 # vault instead, which provides stable URLs for specific minor versions.
1086 rocky10x86_64 = {
1087 name = "rocky-10.0-x86_64";
1088 fullName = "Rocky Linux 10.0 (x86_64)";
1089 packagesLists = [
1090 (fetchurl {
1091 url = "https://dl.rockylinux.org/vault/rocky/10.0/BaseOS/x86_64/os/repodata/484d5c43cdb1058dd1328a6b891f45c85f1cb2620c528f2ef423d4b9feb9e2f0-primary.xml.gz";
1092 hash = "sha256-SE1cQ82xBY3RMopriR9FyF8csmIMUo8u9CPUuf654vA=";
1093 })
1094 (fetchurl {
1095 url = "https://dl.rockylinux.org/vault/rocky/10.0/AppStream/x86_64/os/repodata/32c93064142d89f3f19c11e92642c5abd8368418f7ab3f3bdd752e4afa9b5b23-primary.xml.gz";
1096 hash = "sha256-MskwZBQtifPxnBHpJkLFq9g2hBj3qz873XUuSvqbWyM=";
1097 })
1098 ];
1099 urlPrefixes = [
1100 "https://dl.rockylinux.org/vault/rocky/10.0/BaseOS/x86_64/os"
1101 "https://dl.rockylinux.org/vault/rocky/10.0/AppStream/x86_64/os"
1102 ];
1103 archs = [
1104 "noarch"
1105 "x86_64"
1106 ];
1107 packages = commonRockyPackages ++ [
1108 "annobin-plugin-gcc"
1109 ];
1110 unifiedSystemDir = true;
1111 };
1112
1113 # AlmaLinux's repo.almalinux.org URLs are rolling and change with each minor release.
1114 # We use vault.almalinux.org instead, which provides stable URLs for specific versions.
1115 alma9x86_64 = {
1116 name = "alma-9.6-x86_64";
1117 fullName = "AlmaLinux 9.6 (x86_64)";
1118 packagesLists = [
1119 (fetchurl {
1120 url = "https://vault.almalinux.org/9.6/BaseOS/x86_64/os/repodata/26d6cf944c86ef850773e61919e892a375ff10bb2254003e1d71673db9900b07-primary.xml.gz";
1121 hash = "sha256-JtbPlEyG74UHc+YZGeiSo3X/ELsiVAA+HXFnPbmQCwc=";
1122 })
1123 (fetchurl {
1124 url = "https://vault.almalinux.org/9.6/AppStream/x86_64/os/repodata/afb5d18b78d819d826d3d0e32ba439da7b9e0fd91d726dd833366496b1b8ca20-primary.xml.gz";
1125 hash = "sha256-r7XRi3jYGdgm09DjK6Q52nueD9kdcm3YMzZklrG4yiA=";
1126 })
1127 ];
1128 urlPrefixes = [
1129 "https://vault.almalinux.org/9.6/BaseOS/x86_64/os"
1130 "https://vault.almalinux.org/9.6/AppStream/x86_64/os"
1131 ];
1132 archs = [
1133 "noarch"
1134 "x86_64"
1135 ];
1136 packages = commonAlmaPackages ++ [
1137 "annobin"
1138 ];
1139 unifiedSystemDir = true;
1140 };
1141
1142 alma10x86_64 = {
1143 name = "alma-10.0-x86_64";
1144 fullName = "AlmaLinux 10.0 (x86_64)";
1145 packagesLists = [
1146 (fetchurl {
1147 url = "https://vault.almalinux.org/10.0/BaseOS/x86_64/os/repodata/4d88695fa7ccb6298897fa9682ac1ded4628df342ffe08312846225e4469e3e4-primary.xml.gz";
1148 hash = "sha256-TYhpX6fMtimIl/qWgqwd7UYo3zQv/ggxKEYiXkRp4+Q=";
1149 })
1150 (fetchurl {
1151 url = "https://vault.almalinux.org/10.0/AppStream/x86_64/os/repodata/11ac32065bae6f2c2451803458690fc550e79f93a4ea9f438930f0c228964791-primary.xml.gz";
1152 hash = "sha256-EawyBluubywkUYA0WGkPxVDnn5Ok6p9DiTDwwiiWR5E=";
1153 })
1154 ];
1155 urlPrefixes = [
1156 "https://vault.almalinux.org/10.0/BaseOS/x86_64/os"
1157 "https://vault.almalinux.org/10.0/AppStream/x86_64/os"
1158 ];
1159 archs = [
1160 "noarch"
1161 "x86_64"
1162 ];
1163 packages = commonAlmaPackages ++ [
1164 "annobin-plugin-gcc"
1165 ];
1166 unifiedSystemDir = true;
1167 };
1168
1169 # Oracle provides versioned URLs for baseos (e.g., OL9/7/baseos/base/) but not for appstream.
1170 # We can't mix versioned baseos with rolling appstream due to package version dependencies,
1171 # so we use rolling URLs for both. These may need hash updates when Oracle releases new versions.
1172 oracle9x86_64 = {
1173 name = "oracle-9-x86_64";
1174 fullName = "Oracle Linux 9 (x86_64)";
1175 packagesLists = [
1176 (fetchurl {
1177 url = "https://yum.oracle.com/repo/OracleLinux/OL9/baseos/latest/x86_64/repodata/bc292d67f73fc606db1872d5ba8804da06a514efe64523247035f0d3b678fb63-primary.xml.gz";
1178 hash = "sha256-vCktZ/c/xgbbGHLVuogE2galFO/mRSMkcDXw07Z4+2M=";
1179 })
1180 (fetchurl {
1181 url = "https://yum.oracle.com/repo/OracleLinux/OL9/appstream/x86_64/repodata/6fabacadf7cdf22cbb21dc296f58e6b852d5b8ec9a927e214231477ef90083f9-primary.xml.gz";
1182 hash = "sha256-b6usrffN8iy7Idwpb1jmuFLVuOyakn4hQjFHfvkAg/k=";
1183 })
1184 ];
1185 urlPrefixes = [
1186 "https://yum.oracle.com/repo/OracleLinux/OL9/baseos/latest/x86_64"
1187 "https://yum.oracle.com/repo/OracleLinux/OL9/appstream/x86_64"
1188 ];
1189 archs = [
1190 "noarch"
1191 "x86_64"
1192 ];
1193 packages = commonOraclePackages ++ [
1194 "annobin"
1195 ];
1196 unifiedSystemDir = true;
1197 };
1198
1199 # Amazon Linux 2023 uses GUID-based URLs that don't allow directory listing.
1200 # To update: The GUID corresponds to a specific AL2023 release version. You can find the
1201 # current GUID by either:
1202 # 1. Running an AL2023 container: `docker run -it amazonlinux:2023 dnf repolist -v`
1203 # and extracting the GUID from the Repo-baseurl field
1204 # 2. Checking https://github.com/docker-library/repo-info/blob/master/repos/amazonlinux/local/latest.md
1205 # which tracks the repository URLs from the official Docker image
1206 # Release notes: https://docs.aws.amazon.com/linux/al2023/release-notes/relnotes.html
1207 amazon2023x86_64 = {
1208 name = "amazon-2023-x86_64";
1209 fullName = "Amazon Linux 2023 (x86_64)";
1210 packagesList = fetchurl {
1211 url = "https://cdn.amazonlinux.com/al2023/core/guids/6fa961924efb4835a7e8de43c89726dca28a5cf5906f891262d8f78a31ea3aaf/x86_64/repodata/primary.xml.gz";
1212 hash = "sha256-Ezdsc8a2aOIbyXvQ/nyanWe1fl089VgtfegaPcu2oo4=";
1213 };
1214 urlPrefix = "https://cdn.amazonlinux.com/al2023/core/guids/6fa961924efb4835a7e8de43c89726dca28a5cf5906f891262d8f78a31ea3aaf/x86_64";
1215 archs = [
1216 "noarch"
1217 "x86_64"
1218 ];
1219 packages = commonAmazonPackages ++ [
1220 "annobin-plugin-gcc"
1221 ];
1222 unifiedSystemDir = true;
1223 };
1224
1225 };
1226
1227 # The set of supported Dpkg-based distributions.
1228
1229 debDistros = {
1230 # Ubuntu's snapshot service returns the same data for 22.04 regardless of the timestamp in the
1231 # URL. The hashes don't change between mirror://ubuntu and snapshot.ubuntu.com, so this is fine.
1232 ubuntu2204i386 = {
1233 name = "ubuntu-22.04-jammy-i386";
1234 fullName = "Ubuntu 22.04 Jammy (i386)";
1235 packagesLists = [
1236 (fetchurl {
1237 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy/main/binary-i386/Packages.xz";
1238 hash = "sha256-iZBmwT0ep4v+V3sayybbOgZBOFFZwPGpOKtmuLMMVPQ=";
1239 })
1240 (fetchurl {
1241 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy/universe/binary-i386/Packages.xz";
1242 hash = "sha256-DO2LdpZ9rDDBhWj2gvDWd0TJJVZHxKsYTKTi6GXjm1E=";
1243 })
1244 (fetchurl {
1245 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy-updates/main/binary-i386/Packages.xz";
1246 hash = "sha256-g95BtOoMxacZEHMBbcMes4a1P9HKf/QGOMOPr+OKayo=";
1247 })
1248 (fetchurl {
1249 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy-updates/universe/binary-i386/Packages.xz";
1250 hash = "sha256-VbazaDDJKSUyQchGmw5f+FYAr4PIXWZJSBF0WVC5j+0=";
1251 })
1252 (fetchurl {
1253 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy-security/main/binary-i386/Packages.xz";
1254 hash = "sha256-SkP4PqjUAbEMtktR5WQm/3jQl9O0T2VOVTP9QIYIVkQ=";
1255 })
1256 (fetchurl {
1257 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy-security/universe/binary-i386/Packages.xz";
1258 hash = "sha256-citjk8LAGSRlXgOXgf3oe9vBCUC6/DJGhRJl/3ppN9c=";
1259 })
1260 ];
1261 urlPrefix = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z";
1262 packages = commonDebPackages ++ [
1263 "diffutils"
1264 "libc-bin"
1265 ];
1266 };
1267
1268 ubuntu2204x86_64 = {
1269 name = "ubuntu-22.04-jammy-amd64";
1270 fullName = "Ubuntu 22.04 Jammy (amd64)";
1271 packagesLists = [
1272 (fetchurl {
1273 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy/main/binary-amd64/Packages.xz";
1274 hash = "sha256-N8tX8VVMv6ccWinun/7hipqMF4K7BWjgh0t/9M6PnBE=";
1275 })
1276 (fetchurl {
1277 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy/universe/binary-amd64/Packages.xz";
1278 hash = "sha256-0pyyTJP+xfQyVXBrzn60bUd5lSA52MaKwbsUpvNlXOI=";
1279 })
1280 (fetchurl {
1281 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy-updates/main/binary-amd64/Packages.xz";
1282 hash = "sha256-I57YuLZ458RljXfp1xFxqQLGNJh9uu8kQC0hc88XZro=";
1283 })
1284 (fetchurl {
1285 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy-updates/universe/binary-amd64/Packages.xz";
1286 hash = "sha256-ZXobWMi7tkakZ89GoyKpiRhRxMRXud0DOerSfzz5CPE=";
1287 })
1288 (fetchurl {
1289 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy-security/main/binary-amd64/Packages.xz";
1290 hash = "sha256-cifTPY1iyckkaLd7dp+VPRlF0viWKrWXhM8HVWaMuUw=";
1291 })
1292 (fetchurl {
1293 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/jammy-security/universe/binary-amd64/Packages.xz";
1294 hash = "sha256-LTSOGbzkv0KrF2JM6oVT1Ml2KQkySXMbKNMBb9AyfQM=";
1295 })
1296 ];
1297 urlPrefix = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z";
1298 packages = commonDebPackages ++ [
1299 "diffutils"
1300 "libc-bin"
1301 ];
1302 };
1303
1304 ubuntu2404x86_64 = {
1305 name = "ubuntu-24.04-noble-amd64";
1306 fullName = "Ubuntu 24.04 Noble (amd64)";
1307 packagesLists = [
1308 (fetchurl {
1309 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/noble/main/binary-amd64/Packages.xz";
1310 hash = "sha256-KmoZnhAxpcJ5yzRmRtWUmT81scA91KgqqgMjmA3ZJFE=";
1311 })
1312 (fetchurl {
1313 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/noble/universe/binary-amd64/Packages.xz";
1314 hash = "sha256-upBX+huRQ4zIodJoCNAMhTif4QHQwUliVN+XI2QFWZo=";
1315 })
1316 (fetchurl {
1317 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/noble-updates/main/binary-amd64/Packages.xz";
1318 hash = "sha256-leBJ29a2C2qdIPdjSSuwkHKUSq8GEC9L0DgdxHWZ55s=";
1319 })
1320 (fetchurl {
1321 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/noble-updates/universe/binary-amd64/Packages.xz";
1322 hash = "sha256-CWYA0A4ytptWdClW3ACdIH4hKscblDh5OgxExP4VdJA=";
1323 })
1324 (fetchurl {
1325 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/noble-security/main/binary-amd64/Packages.xz";
1326 hash = "sha256-TYs8ugCYqzOleH2OebdrpB8E68PfxB+7sRb+PlfANEo=";
1327 })
1328 (fetchurl {
1329 url = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z/dists/noble-security/universe/binary-amd64/Packages.xz";
1330 hash = "sha256-bK9R8CUjLQ1V4GP7/KqZooSnKHF5+T5SuBs0butC82M=";
1331 })
1332 ];
1333 urlPrefix = "https://snapshot.ubuntu.com/ubuntu/20260101T000000Z";
1334 packages = commonDebPackages ++ [
1335 "diffutils"
1336 "libc-bin"
1337 ];
1338 };
1339
1340 debian11i386 = {
1341 name = "debian-11.11-bullseye-i386";
1342 fullName = "Debian 11.11 Bullseye (i386)";
1343 packagesList = fetchurl {
1344 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/bullseye/main/binary-i386/Packages.xz";
1345 hash = "sha256-kUg1VBUO6co/5bKloxncta49191oCeF05Hm399+UuDA=";
1346 };
1347 urlPrefix = "https://snapshot.debian.org/archive/debian/20260105T082626Z";
1348 packages = commonDebianPackages;
1349 };
1350
1351 debian11x86_64 = {
1352 name = "debian-11.11-bullseye-amd64";
1353 fullName = "Debian 11.11 Bullseye (amd64)";
1354 packagesList = fetchurl {
1355 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/bullseye/main/binary-amd64/Packages.xz";
1356 hash = "sha256-HDQFREKX6thkcRwY5kvOSBDbY7SDQKL52BGC2fI1rXE=";
1357 };
1358 urlPrefix = "https://snapshot.debian.org/archive/debian/20260105T082626Z";
1359 packages = commonDebianPackages;
1360 };
1361
1362 debian12i386 = {
1363 name = "debian-12.12-bookworm-i386";
1364 fullName = "Debian 12.12 Bookworm (i386)";
1365 packagesLists = [
1366 (fetchurl {
1367 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/bookworm/main/binary-i386/Packages.xz";
1368 hash = "sha256-nIijsNoHUYkrL6eiwN4FCLHnJy/Bv/RMvnbMIHvieVI=";
1369 })
1370 (fetchurl {
1371 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/bookworm-backports/main/binary-i386/Packages.xz";
1372 hash = "sha256-/ja7+DNIKc2ZUIXiocTjLbaD2EPsfeyZcd5ndEMapp4=";
1373 })
1374 ];
1375 urlPrefix = "https://snapshot.debian.org/archive/debian/20260105T082626Z";
1376 packages = commonDebianPackages;
1377 };
1378
1379 debian12x86_64 = {
1380 name = "debian-12.12-bookworm-amd64";
1381 fullName = "Debian 12.12 Bookworm (amd64)";
1382 packagesLists = [
1383 (fetchurl {
1384 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/bookworm/main/binary-amd64/Packages.xz";
1385 hash = "sha256-PfjQeu3tXmXZhH7foSD6WyFrvY4PfwSN/v5pBeShIBE=";
1386 })
1387 (fetchurl {
1388 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/bookworm-backports/main/binary-amd64/Packages.xz";
1389 hash = "sha256-S3NSvw1kX2zxzMh+WYhY58VUR7iLrTEIuXwwSK6itIs=";
1390 })
1391 ];
1392 urlPrefix = "https://snapshot.debian.org/archive/debian/20260105T082626Z";
1393 packages = commonDebianPackages;
1394 };
1395
1396 debian13i386 = {
1397 name = "debian-13.2-trixie-i386";
1398 fullName = "Debian 13.2 Trixie (i386)";
1399 packagesLists = [
1400 (fetchurl {
1401 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/trixie/main/binary-i386/Packages.xz";
1402 hash = "sha256-9zozvFZoWiv3wNe9rb+kPwSOgc5G5f4zmNpdoet5A78=";
1403 })
1404 (fetchurl {
1405 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/trixie-backports/main/binary-i386/Packages.xz";
1406 hash = "sha256-hEBAQ73Jnv8zp9YvNXWLEObyrSlQNBNBj/XoofJL7eI=";
1407 })
1408 ];
1409 urlPrefix = "https://snapshot.debian.org/archive/debian/20260105T082626Z";
1410 packages = commonDebianPackages;
1411 };
1412
1413 debian13x86_64 = {
1414 name = "debian-13.2-trixie-amd64";
1415 fullName = "Debian 13.2 Trixie (amd64)";
1416 packagesLists = [
1417 (fetchurl {
1418 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/trixie/main/binary-amd64/Packages.xz";
1419 hash = "sha256-g7f+tKljUXAC4gxJfzSC8+j0GbiwRZjonv25tYuvxtU=";
1420 })
1421 (fetchurl {
1422 url = "https://snapshot.debian.org/archive/debian/20260105T082626Z/dists/trixie-backports/main/binary-amd64/Packages.xz";
1423 hash = "sha256-9OoR36FsyK7MQMLHLFMRJ9O11WKq9JCfGwnprpztxNw=";
1424 })
1425 ];
1426 urlPrefix = "https://snapshot.debian.org/archive/debian/20260105T082626Z";
1427 packages = commonDebianPackages;
1428 };
1429 };
1430
1431 # Base packages for all RHEL-family distros (Fedora, Rocky, Alma, etc.)
1432 baseRHELFamilyPackages = [
1433 "autoconf"
1434 "automake"
1435 "basesystem"
1436 "bzip2"
1437 "curl"
1438 "diffutils"
1439 "findutils"
1440 "gawk"
1441 "gcc-c++"
1442 "glibc-gconv-extra"
1443 "gzip"
1444 "make"
1445 "patch"
1446 "perl"
1447 "rpm"
1448 "rpm-build"
1449 "tar"
1450 "unzip"
1451 ];
1452
1453 commonFedoraPackages = baseRHELFamilyPackages ++ [
1454 "annobin-plugin-gcc"
1455 "fedora-release"
1456 "gcc-plugin-annobin"
1457 "pkgconf-pkg-config"
1458 ];
1459
1460 commonRockyPackages = baseRHELFamilyPackages ++ [
1461 "gcc-plugin-annobin"
1462 "pkgconf"
1463 "rocky-release"
1464 ];
1465
1466 commonAlmaPackages = baseRHELFamilyPackages ++ [
1467 "almalinux-release"
1468 "gcc-plugin-annobin"
1469 "pkgconf"
1470 ];
1471
1472 commonOraclePackages = baseRHELFamilyPackages ++ [
1473 "gcc-plugin-annobin"
1474 "oraclelinux-release"
1475 "pkgconf"
1476 ];
1477
1478 commonAmazonPackages = baseRHELFamilyPackages ++ [
1479 "gcc-plugin-annobin"
1480 "pkgconf"
1481 "system-release"
1482 ];
1483
1484 # Common packages for openSUSE images.
1485 commonOpenSUSEPackages = [
1486 "aaa_base"
1487 "autoconf"
1488 "automake"
1489 "bzip2"
1490 "curl"
1491 "diffutils"
1492 "findutils"
1493 "gawk"
1494 "gcc-c++"
1495 "gzip"
1496 "make"
1497 "patch"
1498 "perl"
1499 "pkg-config"
1500 "rpm"
1501 "tar"
1502 "unzip"
1503 "util-linux"
1504 "gnu-getopt"
1505 ];
1506
1507 # Common packages for Debian/Ubuntu images.
1508 commonDebPackages = [
1509 "base-passwd"
1510 "dpkg"
1511 "libc6-dev"
1512 "perl"
1513 "bash"
1514 "dash"
1515 "gzip"
1516 "bzip2"
1517 "tar"
1518 "grep"
1519 "mawk"
1520 "sed"
1521 "findutils"
1522 "g++"
1523 "make"
1524 "curl"
1525 "patch"
1526 "locales"
1527 "coreutils"
1528 # Needed by checkinstall:
1529 "util-linux"
1530 "file"
1531 "dpkg-dev"
1532 "pkg-config"
1533 # Needed because it provides /etc/login.defs, whose absence causes
1534 # the "passwd" post-installs script to fail.
1535 "login"
1536 "passwd"
1537 ];
1538
1539 commonDebianPackages = commonDebPackages ++ [
1540 "sysvinit"
1541 "diff"
1542 ];
1543
1544 /*
1545 A set of functions that build the Linux distributions specified
1546 in `rpmDistros' and `debDistros'. For instance,
1547 `diskImageFuns.ubuntu1004x86_64 { }' builds an Ubuntu 10.04 disk
1548 image containing the default packages specified above. Overrides
1549 of the default image parameters can be given. In particular,
1550 `extraPackages' specifies the names of additional packages from
1551 the distribution that should be included in the image; `packages'
1552 allows the entire set of packages to be overridden; and `size'
1553 sets the size of the disk in MiB (1024*1024 bytes). E.g.,
1554 `diskImageFuns.ubuntu1004x86_64 { extraPackages = ["firefox"];
1555 size = 8192; }' builds an 8 GiB image containing Firefox in
1556 addition to the default packages.
1557 */
1558 diskImageFuns =
1559 (lib.mapAttrs (
1560 name: as: as2:
1561 makeImageFromRPMDist (as // as2)
1562 ) rpmDistros)
1563 // (lib.mapAttrs (
1564 name: as: as2:
1565 makeImageFromDebDist (as // as2)
1566 ) debDistros);
1567
1568 # Shorthand for `diskImageFuns.<attr> { extraPackages = ... }'.
1569 diskImageExtraFuns = lib.mapAttrs (
1570 name: f: extraPackages:
1571 f { inherit extraPackages; }
1572 ) diskImageFuns;
1573
1574 /*
1575 Default disk images generated from the `rpmDistros' and
1576 `debDistros' sets.
1577 */
1578 diskImages = lib.mapAttrs (name: f: f { }) diskImageFuns;
1579in
1580{
1581 inherit
1582 buildRPM
1583 commonDebPackages
1584 commonDebianPackages
1585 commonFedoraPackages
1586 commonOpenSUSEPackages
1587 createEmptyImage
1588 debClosureGenerator
1589 debDistros
1590 defaultCreateRootFS
1591 diskImageExtraFuns
1592 diskImageFuns
1593 diskImages
1594 extractFs
1595 extractMTDfs
1596 fillDiskWithDebs
1597 fillDiskWithRPMs
1598 hd
1599 initrd
1600 initrdUtils
1601 makeImageFromDebDist
1602 makeImageFromRPMDist
1603 makeImageTestScript
1604 modulesClosure
1605 qemu
1606 qemuCommandLinux
1607 rpmClosureGenerator
1608 rpmDistros
1609 runInLinuxImage
1610 runInLinuxVM
1611 stage1Init
1612 stage2Init
1613 vmRunCommand
1614 ;
1615}