# `router-install`: write a prebuilt router system to a disk. Nothing is built # on the box; the system closure travels with the installer. { config, lib, pkgs, ... }: let cfg = config.router.installer; installScript = pkgs.writeShellApplication { name = "router-install"; runtimeInputs = [ config.system.build.nixos-install pkgs.coreutils pkgs.dosfstools pkgs.e2fsprogs pkgs.gptfdisk pkgs.util-linux ]; text = '' usage() { echo "usage: router-install [--yes] [--secrets DIR] [--system PATH] " >&2 echo " Wipes (e.g. /dev/nvme0n1) and installs a router system." >&2 echo " --secrets DIR copied to /var/lib/router (PPPoE password, WireGuard keys, ...)" >&2 echo " --system PATH the system to install${lib.optionalString (cfg.system != null) " (default: ${cfg.system})"}" >&2 exit 2 } yes=0 secrets= system=${if cfg.system != null then toString cfg.system else ""} disk= while [ $# -gt 0 ]; do case $1 in --yes) yes=1 ;; --secrets) shift; [ $# -gt 0 ] || usage; secrets=$1 ;; --system) shift; [ $# -gt 0 ] || usage; system=$1 ;; -*) usage ;; *) [ -z "$disk" ] || usage; disk=$1 ;; esac shift done [ -n "$disk" ] || usage [ -n "$system" ] || usage [ -x "$system/bin/switch-to-configuration" ] || { echo "router-install: $system is not a NixOS system" >&2; exit 1; } [ "$(id -u)" -eq 0 ] || { echo "router-install: must run as root" >&2; exit 1; } [ -b "$disk" ] || { echo "router-install: $disk is not a block device" >&2; exit 1; } if [ -n "$secrets" ] && [ ! -d "$secrets" ]; then echo "router-install: $secrets is not a directory" >&2 exit 1 fi if lsblk -nr -o MOUNTPOINTS "$disk" | grep -q .; then echo "router-install: $disk or one of its partitions is mounted; refusing" >&2 exit 1 fi [ -d /sys/firmware/efi ] || echo "warning: not booted in UEFI mode; the box itself must boot UEFI" >&2 echo "About to ERASE $disk:" lsblk -o NAME,SIZE,MODEL,FSTYPE,LABEL "$disk" if [ "$yes" -ne 1 ]; then printf 'Type the device name (%s) to continue: ' "$disk" read -r answer [ "$answer" = "$disk" ] || { echo "aborted" >&2; exit 1; } fi part() { case $disk in *[0-9]) echo "''${disk}p$1" ;; *) echo "$disk$1" ;; esac } echo ">> partitioning" sgdisk --zap-all "$disk" >/dev/null sgdisk -n 1:0:+512M -t 1:ef00 -c 1:boot -n 2:0:0 -t 2:8300 -c 2:nixos "$disk" >/dev/null partprobe "$disk" || true udevadm settle echo ">> formatting" mkfs.fat -F 32 -n boot "$(part 1)" >/dev/null mkfs.ext4 -q -F -L nixos "$(part 2)" echo ">> mounting" mkdir -p /mnt mount "$(part 2)" /mnt mkdir -p /mnt/boot mount -o umask=0077 "$(part 1)" /mnt/boot if [ -n "$secrets" ]; then echo ">> copying secrets" install -d -m 0700 /mnt/var/lib/router cp -rT "$secrets" /mnt/var/lib/router chown -R root:root /mnt/var/lib/router chmod -R go-rwx /mnt/var/lib/router else echo "note: no --secrets given; put the PPPoE password etc. in /var/lib/router later" >&2 fi echo ">> installing $system" nixos-install --system "$system" --root /mnt --no-root-passwd --no-channel-copy echo ">> unmounting" umount -R /mnt sync echo "Done. Remove the installer and reboot." ''; }; in { options.router.installer.system = lib.mkOption { type = lib.types.nullOr lib.types.package; default = null; description = '' The system (a `system.build.toplevel`) `router-install` writes to disk; null if it is always given with `--system` (as `router-setup` does). ''; }; config = { environment.systemPackages = [ installScript ]; # The closure must be on the installer itself. system.extraDependencies = lib.optional (cfg.system != null) cfg.system; }; }