Skip to content

Instantly share code, notes, and snippets.

@mjbnz
Created March 17, 2023 03:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjbnz/deabcbd193bb6223841f746daccf575f to your computer and use it in GitHub Desktop.
Save mjbnz/deabcbd193bb6223841f746daccf575f to your computer and use it in GitHub Desktop.
Disk image writing initrd for iPXE netbooting

Disk-Write initrd creation script

Inspired by this post on ipxe.org, the following script downloads and extracts the current Debian Bullseye netboot installer kernel and initrd, and prepares them for usage as a rudimentary disk image writing utility. It is intended to be used for KVM virtio guests on Proxmox VE, to install Mikrotik RouterOS via network boot.

Appropriate iPXE commands to use the resulting kernel and initrd would be something like the following:

dhcp
kernel tftp://${next-server}/disk-write/kernel
initrd tftp://${next-server}/disk-write/initrd
imgfetch http://${next-server}/chr-7.6.img /sda.img
boot kernel quiet

How it works.

The iPXE imgfetch command fetches the raw disk image file from an appropriate http (or other) server on the net booting network, and presents it as /sda.img within the initrd after boot. The embedded /init script within the initrd looks for this file and will use dd to write it to /dev/sda, as long as the first 16MB of the disk consists of binary zeros.

#!/bin/bash -e
echo -e "Creating Disk-Write initrd...\n"
if [ -d initramfs ];then
echo -n " -> Removing previous initramfs build dir... "
rm -r initramfs
echo "done."
fi
# Make directory structure
echo -n " -> Creating directory structure... "
mkdir -p initramfs/{bin,dev,etc,lib/x86_64-linux-gnu,lib64,proc,run,sbin,sys}
echo "done."
# Download debian-installer netboot kernel and initrd
echo -n " -> Downloading Debian Installer kernel and initrd image... "
curl -s -o kernel http://deb.debian.org/debian/dists/bullseye/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux
curl -s -O http://deb.debian.org/debian/dists/bullseye/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz
echo "done."
# Extract initrd
echo -n " -> Extracting initrd.gz... "
unmkinitramfs initrd.gz d-i
echo "done."
# Copy files from initrd
echo -n " -> Copying files from debian installer initrd... "
cp -a d-i/usr/bin/{\[,cmp} d-i/bin/{busybox,dd,echo,kmod,mkdir,mount,sh,sleep} initramfs/bin/
cp -a d-i/sbin/{depmod,modprobe,reboot} initramfs/sbin/
cp -a d-i/lib/x86_64-linux-gnu/{ld-2.31.so,ld-linux-x86-64.so.2,libc-2.31.so,libc.so.6} initramfs/lib/x86_64-linux-gnu/
cp -a d-i/lib64/ld-linux-x86-64.so.2 initramfs/lib64
cp -a d-i/etc/fstab initramfs/etc/
cp -a d-i/dev/{console,null} initramfs/dev/
echo "done."
# Make device nodes not present in initrd
echo -n " -> Creating device nodes... "
mknod initramfs/dev/sda b 8 0
mknod initramfs/dev/zero c 1 5
echo "done."
# Copy kernel modules
echo -n " -> Copying kernel modules... "
kver=$(ls -1 d-i/lib/modules | head -1)
(cd d-i; cp --parents -a lib/modules/${kver}/kernel/{block/t10-pi.ko,lib/crc-t10dif.ko,crypto/crct10dif_common.ko} ../initramfs)
(cd d-i; cp --parents -a lib/modules/${kver}/kernel/drivers/{scsi/{sd_mod.ko,scsi_mod.ko},virtio/virtio{.ko,_ring.ko,_pci.ko}} ../initramfs)
echo "done."
echo -n " -> Downloading scsi-modules udeb for KVER ${kver}... "
udebfile=$(curl -s http://deb.debian.org/debian/dists/bullseye/main/installer-amd64/current/images/udeb.list | sed -ne 's/ /_/g;s/$/.udeb/;/^scsi-modules/p')
curl -s -O http://deb.debian.org/debian/pool/main/l/linux-signed-amd64/${udebfile}
echo "done."
echo -n " -> Extracting udeb and copying virtio modules... "
dpkg-deb -x ${udebfile} scsi-modules
(cd scsi-modules; cp --parents -a lib/modules/${kver}/kernel/drivers/{scsi/virtio_scsi.ko,block/virtio_blk.ko} ../initramfs)
echo "done."
# Create /init
echo -n " -> Creating /init script ... "
cat > initramfs/init <<EOF
#!/bin/sh
mount /run
mkdir -p /run/lock
mount /proc
mount /sys
depmod -a 2>/dev/null
modprobe virtio_pci
modprobe virtio_scsi
modprobe sd_mod
if [ "\$(dd if=/dev/sda bs=4096 count=4096 2>/dev/null | cmp /dev/zero 2>&1)" = "cmp: EOF on -" ]; then
echo "Writing, please wait..."
dd if=/sda.img of=/dev/sda
echo "Completed! Rebooting in 5 secs.."
sleep 5
else
echo "WARNING: /dev/sda is not blank - aborting!"
echo "Rebooting in 20 seconds.."
sleep 20
fi
reboot -f
EOF
chmod +x initramfs/init
echo "done."
# Make initrd
echo -n " -> Creating initrd... "
(cd initramfs && find . | sort | cpio -o -H newc -R 0:0 2>/dev/null | gzip -9 > ../initrd)
echo "done."
# Cleanup
echo -n " -> Cleaning up... "
rm -r scsi-modules d-i initrd.gz ${udebfile}
echo "done."
echo -e "\nCompleted!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment