diff options
Diffstat (limited to 'installer/lib')
| -rw-r--r-- | installer/lib/common.sh | 21 | ||||
| -rw-r--r-- | installer/lib/disk.sh | 59 |
2 files changed, 80 insertions, 0 deletions
diff --git a/installer/lib/common.sh b/installer/lib/common.sh index 2cd4798..7998eeb 100644 --- a/installer/lib/common.sh +++ b/installer/lib/common.sh @@ -102,6 +102,27 @@ pacstrap_packages() { printf '%s\n' "${common[@]}" "${fs_specific[@]}" } +# Print the external commands the installer needs for the given filesystem, +# one per line: common partitioning/bootstrap tools first, then +# filesystem-specific ones. validate_environment loops over these and +# require_command's each, so a missing tool fails fast on the live ISO +# instead of mid-install. Returns 1 for unknown filesystem. +# +# Usage: mapfile -t cmds < <(required_commands zfs) +required_commands() { + local fs="$1" + local common=( + sgdisk wipefs partprobe mkfs.fat pacstrap + ) + local fs_specific + case "$fs" in + zfs) fs_specific=(zpool zfs) ;; + btrfs) fs_specific=(mkfs.btrfs grub-install) ;; + *) return 1 ;; + esac + printf '%s\n' "${common[@]}" "${fs_specific[@]}" +} + ############################# # Password / Passphrase Input ############################# diff --git a/installer/lib/disk.sh b/installer/lib/disk.sh index b548b4f..ae7801b 100644 --- a/installer/lib/disk.sh +++ b/installer/lib/disk.sh @@ -131,3 +131,62 @@ select_disks() { info "Selected disks: ${SELECTED_DISKS[*]}" } +############################# +# Pre-flight: Disk Safety +############################# + +# Minimum usable install disk. Root plus the 50G reservation, packages, and +# snapshots needs real headroom; below this the install fails partway +# through. 20 GB is a hard floor (validate_install_targets errors out). +# Decimal GB (disk-vendor sizing) on purpose: it reads as the natural "20GB" +# minimum and clears a 20 GiB disk image with headroom rather than sitting +# exactly on the boundary. +MIN_DISK_BYTES=20000000000 # 20 * 10^9 (20 GB) + +# Pure size predicate: succeed only when <bytes> is a non-negative integer +# meeting MIN_DISK_BYTES. Non-numeric or empty input fails (treated as an +# unknown size, which is itself a reason not to proceed). +disk_meets_min_size() { + local bytes="$1" + [[ "$bytes" =~ ^[0-9]+$ ]] || return 1 + (( bytes >= MIN_DISK_BYTES )) +} + +# Size of a block device in bytes (live query). Thin wrapper over blockdev; +# exercised by the VM integration harness rather than unit tests. +disk_size_bytes() { + blockdev --getsize64 "$1" 2>/dev/null +} + +# Succeed (return 0) when <disk> is in active use and must NOT be wiped: +# any partition mounted, active swap on it, or membership in an imported +# zpool or assembled md array. Over-detection errs on the safe side +# (refuse). Live-state predicate — validated in the VM harness, where the +# install disks are deliberately idle so the happy path returns 1. +disk_in_use() { + local disk="$1" + local base + base=$(basename "$disk") + + # Any mountpoint on the disk or its children. + if lsblk -nro MOUNTPOINT "$disk" 2>/dev/null | grep -q .; then + return 0 + fi + # Active swap on the disk or a partition of it. + if swapon --show=NAME --noheadings 2>/dev/null | grep -q "^${disk}"; then + return 0 + fi + # Member of an imported zpool. -P prints full device paths (/dev/vda2), + # so a fixed-string match on the disk path catches partition members too + # — a plain word match on the bare name would miss "vda2". + if command_exists zpool && zpool status -LP 2>/dev/null | grep -qF "$disk"; then + return 0 + fi + # Member of an assembled md array. /proc/mdstat lists bare partition names + # (vda1[0]); substring-match the disk name (over-match errs toward refuse). + if grep -qsF "$base" /proc/mdstat 2>/dev/null; then + return 0 + fi + return 1 +} + |
