wren-linux / tools / try-install-iso.sh
#!/bin/bash
# Tries an install image from prep/make-install-iso.sh in a throwaway VM, the
# way a real laptop would start it: UEFI firmware, the image plugged in as a USB
# stick, and an empty 20 GB disk. Nothing on this computer is touched; the VM's
# files are in ~/.cache/wren/iso-test (left out of backups).
#
# bash tools/try-install-iso.sh install from the newest built image
# bash tools/try-install-iso.sh --iso FILE ...from FILE
# bash tools/try-install-iso.sh --two-disks with a second empty disk: the
# installer should then ask which
# bash tools/try-install-iso.sh --no-net no network in the VM: everything
# the installer asks should still
# be answerable (this laptop's
# wifi-only case)
# bash tools/try-install-iso.sh --boot start the installed system again
# bash tools/try-install-iso.sh --clean delete the VM's files, to start over
# (no software is removed)
# bash tools/try-install-iso.sh --remove remove the packages this script
# installed (not ones you had, or that
# other Wren Linux scripts need)
# bash tools/try-install-iso.sh --print ... only show the QEMU commands
#
# It needs QEMU (qemu-system-x86, qemu-utils, and qemu-system-gui for its
# window), the UEFI firmware (ovmf) and
# access to /dev/kvm, and offers to install the packages (sudo) if they are
# missing. Run it as your normal user, in your sway session (the VM is a window).
# shellcheck disable=SC2054 # QEMU's options are comma-separated on purpose
. "$(dirname -- "${BASH_SOURCE[0]}")/../lib.sh"
not_root
DIR=${XDG_CACHE_HOME:-$HOME/.cache}/wren/iso-test
OVMF=${WREN_OVMF_DIR:-/usr/share/OVMF} # (a test points this elsewhere)
CODE=$OVMF/OVMF_CODE_4M.fd
VARS_TEMPLATE=$OVMF/OVMF_VARS_4M.fd
DISK=$DIR/disk.qcow2
DISK2=$DIR/disk2.qcow2
VARS=$DIR/vars.fd
mode=install iso='' two=false print=false no_net=false
while [ $# -gt 0 ]; do
case $1 in
--iso) iso=${2:-}; shift 2 ;;
--two-disks) two=true; shift ;;
--no-net) no_net=true; shift ;;
--boot) mode=boot; shift ;;
--clean) mode=clean; shift ;;
--remove) mode=remove; shift ;;
--print) print=true; shift ;;
-h | --help) sed -n '2,25p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) die "Unknown option $1. Try: bash tools/try-install-iso.sh --help" ;;
esac
done
if [ "$mode" = clean ]; then
rm -rf "$DIR"
note "Deleted $DIR. No software was removed."
exit 0
fi
if [ "$mode" = remove ]; then
if ! is_installed "$(apt_marker)"; then
note "This script installed no packages, so there is nothing to remove."
exit 0
fi
mapfile -t mine < <(marker_depends "$(apt_marker)")
note "This script installed: ${mine[*]}."
note "Removed are only those that nothing else needs: QEMU stays if Whonix, claude-vm or"
note "mockvps-kvm use it, and so does anything you had before."
ask "Remove them?" n && apt_purge
exit 0
fi
if [ -z "$iso" ]; then
iso=$(find "$OFFLINE_DIR/install-iso" -maxdepth 1 -name '*-wren.iso' -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
[ -n "$iso" ] || $print || [ "$mode" = boot ] ||
die "No built image in $OFFLINE_DIR/install-iso. Make one: bash prep/make-install-iso.sh"
fi
[ "$mode" = boot ] || [ -f "$iso" ] || $print || die "No image $iso."
# The machine: KVM, UEFI (its settings in a copy of its own), virtio network,
# in a window (asked for by name: without it QEMU falls back to a hidden VNC
# screen, and the installer waits where you can't see it)
base=(qemu-system-x86_64 -enable-kvm -cpu host -machine q35 -m 2048 -display gtk
-drive "if=pflash,format=raw,readonly=on,file=$CODE"
-drive "if=pflash,format=raw,file=$VARS")
# a wired look by default; --no-net takes the network out (a wifi-only laptop)
nic=(-nic user,model=virtio-net-pci)
$no_net && nic=("-nic" "none")
install_cmd=("${base[@]}" "${nic[@]}"
-drive "if=none,id=disk,file=$DISK" -device virtio-blk-pci,drive=disk,bootindex=1)
$two && install_cmd+=(-drive "if=none,id=disk2,file=$DISK2" -device virtio-blk-pci,drive=disk2)
# the image as a USB stick, read-only, booted first; when the installer
# restarts at the end, QEMU stops instead (else the stick starts it again)
install_cmd+=(-drive "if=none,id=stick,format=raw,readonly=on,file=$iso"
-device qemu-xhci -device usb-storage,drive=stick,bootindex=0 -no-reboot)
boot_cmd=("${base[@]}" "${nic[@]}" -drive "if=none,id=disk,file=$DISK" -device virtio-blk-pci,drive=disk,bootindex=1)
$two && boot_cmd+=(-drive "if=none,id=disk2,file=$DISK2" -device virtio-blk-pci,drive=disk2)
if $print; then
[ "$mode" = boot ] || { echo "# the installer:"; printf '%q ' "${install_cmd[@]}" | sed 's/\\,/,/g'; echo; }
echo "# the installed system:"
printf '%q ' "${boot_cmd[@]}" | sed 's/\\,/,/g'
echo
exit 0
fi
# ---- what it needs ----
need=()
command -v qemu-system-x86_64 >/dev/null || need+=(qemu-system-x86)
command -v qemu-img >/dev/null || need+=(qemu-utils)
# the window: a package of its own, which QEMU only recommends (and other
# Wren Linux VMs, run without a window, don't install)
is_installed qemu-system-gui || need+=(qemu-system-gui)
[ -f "$CODE" ] && [ -f "$VARS_TEMPLATE" ] || need+=(ovmf)
if [ ${#need[@]} -gt 0 ]; then
note "Missing: ${need[*]}."
ask "Install them (needs your sudo password)? bash tools/try-install-iso.sh --remove removes them again." y ||
die "Nothing was started. Install them yourself: sudo apt install ${need[*]}"
apt_install "${need[@]}"
fi
[ -r /dev/kvm ] && [ -w /dev/kvm ] ||
die "No access to /dev/kvm. Add yourself to the kvm group (sudo adduser $(id -un) kvm), log out and back in, and run this again. (No KVM in the firmware settings? Turn on VT-x / AMD-V.)"
[ -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ] || warn "No graphical session: QEMU's window needs one (run this inside sway)."
mkdir -p "$DIR"
if [ "$mode" = boot ]; then
[ -s "$DISK" ] || die "Nothing installed yet. Run: bash tools/try-install-iso.sh"
else
if [ -s "$DISK" ]; then
ask "A test disk from before is there. Start over with an empty one?" y || die "Kept it. Start the installed system with: bash tools/try-install-iso.sh --boot"
rm -f "$DISK" "$DISK2"
fi
qemu-img create -q -f qcow2 "$DISK" 20G
$two && qemu-img create -q -f qcow2 "$DISK2" 20G
# the firmware's settings start fresh with the disk
cp "$VARS_TEMPLATE" "$VARS"
chmod u+w "$VARS"
fi
[ -f "$VARS" ] || { cp "$VARS_TEMPLATE" "$VARS"; chmod u+w "$VARS"; }
if [ "$mode" = install ]; then
say "The installer, from $(basename -- "$iso") as a USB stick"
cat <<EOF
What to check in the window:
1. The menu's first entry, highlighted: "Automatic install with Wren Linux".
Press Enter.
2. It asks only for the disk encryption passphrase (twice) and your
user's password (twice). Use throwaway ones.
EOF
if $no_net; then
cat <<'EOF'
-- With --no-net there are NO network questions at all: no wifi prompt,
no "network autoconfiguration failed" (the install uses the stick
alone; wifi.sh asks for the wifi after the install).
EOF
fi
if $two; then
echo " 3. With two disks it should ASK which disk (vda or vdb), never the stick."
else
echo " 3. \"Write the changes to disks?\" names /dev/vda (the 20 GB disk), not the stick."
fi
cat <<EOF
If it names anything else, choose No.
4. "Erasing data" fills the disk with random data: a few minutes.
5. When it is done it restarts: the window closes by itself, and this
script goes on to the installed system.
To stop earlier: close the window, or Ctrl+C here.
EOF
# It stops by itself when the installer restarts at the end (-no-reboot)
"${install_cmd[@]}" || die "QEMU stopped before the install was done (an error above, or Ctrl+C). Run this again to start over."
ask "Start the installed system now?" y || { note "Later: bash tools/try-install-iso.sh --boot"; exit 0; }
fi
say "The installed system"
cat <<'EOF'
What to check:
- It asks for the disk passphrase at start, then shows a login.
- You can log in with your user; sudo true works with your password.
- Wren Linux is the package, root's, in /usr/share/wren, and not in your home:
dpkg -s wren-linux says "install ok installed", ls -ld /usr/share/wren
shows root, and there is no ~/wren.
- "Set it up now?" at the first login runs /usr/share/wren/start.sh; after it,
~/Documents/wren-docs has the docs, and wrenctl --dir says /usr/share/wren.
EOF
if $no_net; then
cat <<'EOF'
- It was installed without a network, so also: the setup puts deb.debian.org
into /etc/apt/sources.list, and `sudo apt-get update` works after the wifi
is on (bash /usr/share/wren/wifi.sh, with the packages saved in
~/.local/share/wren/offline).
EOF
fi
cat <<'EOF'
Keys: your own sway takes Super (Super+Enter, Super+d...) before the VM
sees it. Press Ctrl+Alt+G in the window to give the VM the keyboard, and
again to take it back; or click wren in the VM's bar, then Terminal.
Close the window to stop it. Start over: bash tools/try-install-iso.sh --clean
EOF
"${boot_cmd[@]}" || warn "QEMU ended with an error (see above)."