#!/bin/sh -e
# run-hurd.sh, a script to fetch and run Debian GNU (Hurd) using qemu, aspiring to be fool-proof
# Copyright (C) 2026 alicia@ion.nu
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
bit64=false
redownload=false
fsck=false
daemon=false
expand=''
while getopts "6rfde:" opt; do
case "$opt" in
6) bit64=true;;
r) redownload=true;;
f) fsck=true;;
d) daemon=true;;
e) expand="$OPTARG"
if ! echo "$expand" | grep -q '[0-9]\+[BKMGTP]'; then
echo 'Invalid format for expansion. Expected number followed by unit (B for bytes, K for kilobytes, M for megabytes etc.)'
exit 1
fi;;
*) echo "Usage: ${0} [options]"
echo 'Options include:'
echo ' -6 = use the new 64bit build'
echo ' -r = redownload instead of booting existing image'
echo ' -f = run a filesystem check (requires losetup and fsck.ext2)'
echo ' -d = daemonize, start qemu and return to the shell'
echo ' -e = expand disk image to the given size'
# TODO: option for curses display (for non-GUI environments and/or to translate keyboard because Hurd console currently lacks keyboard layouts outside US qwerty)
# TODO: option for VNC display
exit;;
esac
done
if [ ! -e debian-hurd.img ] || "$redownload"; then
rm -f debian-hurd.img.tar.gz
if "$bit64"; then
wget 'https://cdimage.debian.org/cdimage/ports/latest/hurd-amd64/debian-hurd.img.tar.gz'
else
wget 'https://cdimage.debian.org/cdimage/ports/latest/hurd-i386/debian-hurd.img.tar.gz'
fi
image="`tar -xvzf debian-hurd.img.tar.gz`"
mv "$image" debian-hurd.img
fi
if "$fsck"; then
# TODO: Dynamically figure out which way (if any, maybe user is root) to run these as root
disk="`sudo losetup -fP --show debian-hurd.img`"
if [ -z "$disk" ]; then echo 'Failed to losetup the disk image. Is losetup installed?'; exit 1; fi
if [ -e "${disk}p5" ]; then
sudo fsck.ext2 -fy "${disk}p5"
else
sudo fsck.ext2 -fy "${disk}p2" # 32bit doesn't use the extended partition
fi
sudo losetup -d "$disk"
fi
if [ -n "$expand" ]; then
num="`echo "$expand" | sed -e 's/[A-Z]$//'`"
unit="`echo "$expand" | sed -e 's/^[0-9]*//'`"
dd if=/dev/zero of=debian-hurd.img bs="1${unit}" count=0 seek="$num"
disk="`sudo losetup -fP --show debian-hurd.img`"
# TODO: Unify the losetup calls?
if [ -z "$disk" ]; then echo 'Failed to losetup the disk image. Is losetup installed?'; exit 1; fi
sudo parted "$disk" resizepart 2 '100%' # Resize the extended partition
sudo parted "$disk" resizepart 5 '100%' || true # Resize the filesystem's partition therein (unless it's 32bit and doesn't have the extended partition)
if [ -e "${disk}p5" ]; then
sudo resize2fs "${disk}p5"
else
sudo resize2fs "${disk}p2"
fi
sudo losetup -d "$disk"
fi
runqemu()
{
kvm="`grep -q ' \(svm\|vmx\)' /proc/cpuinfo && echo '--enable-kvm'`"
# I think 32bit code should work even if we run x86_64 qemu?
# From some testing, it appears -M q35 is not needed for 64bit Hurd, but breaks 32bit Hurd. Therefor omitting it
qemu-system-x86_64 ${kvm} -m 2G -drive cache=writeback,file=debian-hurd.img -net user,hostfwd=tcp:127.0.0.1:2222-:22 -net nic,model=e1000
}
if "$daemon"; then
runqemu > /dev/null 2> /dev/null &
else
runqemu
fi