#!/bin/bash # ===================================================================== # Puts installation media where build.sh can find it, having checked it. # # sudo ./fetch.sh ubuntu # download the pinned release # sudo ./fetch.sh ubuntu ~/Downloads/x.iso # use one already downloaded # sudo ./fetch.sh windows ~/Downloads/x.iso # # EITHER WAY IT IS CHECKSUMMED # # A local file is not trusted more than a downloaded one - it is the same # 6 GB of installer that becomes the machine every session runs from. For # Ubuntu the hash is compared against Canonical's published SHA256SUMS # for that series, fetched at the time, rather than a constant pasted in # here that goes stale at the next point release and gets deleted. # # Windows media has no published list to check against, so its hash is # only RECORDED. That is a real difference and it is not papered over: # the manifest says where the file came from and what it hashed to, and # that is all anyone can honestly claim about it. # # WHY UBUNTU IS NOT FETCHED WITH quickget # # quickget was adopted for image acquisition because the Windows side - # locating an ISO, pairing it with the right virtio-win build - is # genuinely fiddly and well solved there. Ubuntu is not that. Acquisition # is one download and one checksum, and doing it directly keeps a # 2,400-line bash dependency off the path that builds the image this # suite runs on every session. # ===================================================================== set -euo pipefail cd "$(dirname "$(readlink -f "$0")")" ISO_DIR=/var/lib/owuivm/iso [ "$(id -u)" -eq 0 ] || { echo "run as root" >&2; exit 1; } install -d -o owuivmadm -g owuivmadm -m 0755 "$ISO_DIR" # The series to check against, and the release to download when no local # file is given. Bump both together. UBUNTU_SERIES="26.04" UBUNTU_ISO="ubuntu-26.04.1-desktop-amd64.iso" UBUNTU_BASE="https://releases.ubuntu.com/${UBUNTU_SERIES}" verify_against_canonical() { # verify_against_canonical local path="$1" name="$2" want got echo "==> checking $name against Canonical's SHA256SUMS" want=$(curl -fsSL "$UBUNTU_BASE/SHA256SUMS" | awk -v f="*$name" '$2==f{print $1}') [ -n "$want" ] || { echo "$name is not in the published list for $UBUNTU_SERIES." >&2 echo "Either it is from another series, or the name has been changed." >&2 exit 1 } got=$(sha256sum "$path" | awk '{print $1}') [ "$want" = "$got" ] || { echo "CHECKSUM MISMATCH - refusing to use this file." >&2 echo " want $want" >&2 echo " got $got" >&2 exit 1 } echo " ok $got" printf '%s %s verified against %s/SHA256SUMS\n' "$name" "$got" "$UBUNTU_BASE" \ > "$ISO_DIR/ubuntu.manifest" } fetch_ubuntu() { local supplied="${1:-}" if [ -n "$supplied" ]; then [ -f "$supplied" ] || { echo "no such file: $supplied" >&2; exit 1; } local name; name=$(basename "$supplied") verify_against_canonical "$supplied" "$name" # Copied rather than symlinked: the source is in somebody's Downloads # folder, and a base image build that fails halfway through because # the ISO was tidied away is a bad afternoon. echo "==> copying into $ISO_DIR" install -o owuivmadm -g owuivmadm -m 0644 "$supplied" "$ISO_DIR/$name" else local dest="$ISO_DIR/$UBUNTU_ISO" if [ -f "$dest" ]; then echo "already present: $dest" else echo "==> downloading $UBUNTU_ISO" curl -fL --retry 3 --continue-at - -o "$dest.part" "$UBUNTU_BASE/$UBUNTU_ISO" mv -f "$dest.part" "$dest" chown owuivmadm:owuivmadm "$dest" fi verify_against_canonical "$dest" "$UBUNTU_ISO" fi echo cat "$ISO_DIR/ubuntu.manifest" } # The virtio driver disk. Windows setup cannot see a virtio-blk disk # without it and will tell you there are no drives to install to, which # reads like a broken VM rather than a missing driver. Fetched from the # same place every Windows-on-KVM guide uses; it is not signed by anyone # whose signature we can check, so the hash is recorded rather than # verified - exactly like the Windows media itself. VIRTIO_URL="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso" fetch_virtio() { local dest="$ISO_DIR/virtio-win.iso" if [ -f "$dest" ]; then echo "already present: $dest" else echo "==> downloading virtio-win.iso" curl -fL --retry 3 --continue-at - -o "$dest.part" "$VIRTIO_URL" mv -f "$dest.part" "$dest" chown owuivmadm:owuivmadm "$dest"; chmod 0644 "$dest" fi printf 'virtio-win.iso %s recorded only - from %s\n' \ "$(sha256sum "$dest" | awk '{print $1}')" "$VIRTIO_URL" > "$ISO_DIR/virtio.manifest" cat "$ISO_DIR/virtio.manifest" } fetch_windows() { local supplied="${1:-}" [ -n "$supplied" ] || { echo "Windows media must be supplied: $0 windows /path/to.iso" >&2; exit 2; } [ -f "$supplied" ] || { echo "no such file: $supplied" >&2; exit 1; } local name got name=$(basename "$supplied") # The maintenance boot picks Windows media by name, so a file that does # not look like Windows media would either be ignored or - worse - the # Ubuntu ISO would be picked instead. Checked here, once, where it can # still be fixed by renaming rather than debugged from a boot failure. case "$name" in [Ww]in*.iso|*[Ww]indows*.iso) ;; *) echo "refusing '$name': Windows media must have a name starting with Win or containing Windows," >&2 echo "because that is how the maintenance boot tells it apart from the Ubuntu ISO." >&2 exit 1 ;; esac got=$(sha256sum "$supplied" | awk '{print $1}') install -o owuivmadm -g owuivmadm -m 0644 "$supplied" "$ISO_DIR/$name" # RECORDED, not verified. See the header. printf '%s %s recorded only - no published checksum to compare against\n' "$name" "$got" \ > "$ISO_DIR/windows.manifest" cat "$ISO_DIR/windows.manifest" echo fetch_virtio } case "${1:-}" in ubuntu) fetch_ubuntu "${2:-}" ;; windows) fetch_windows "${2:-}" ;; virtio) fetch_virtio ;; *) echo "usage: $0 {ubuntu|windows|virtio} [/path/to/local.iso]" >&2; exit 2 ;; esac