#!/usr/bin/env bash # 16-grow-root-online.sh — kill swap (8.8G, 0B used, 47G RAM) and grow # the ext4 root ONLINE to fill the 438G NVMe (~158G of trailing free # space becomes contiguous with sda1 once sda2/sda5 are deleted). # Charles authorized swap removal 2026-09-01; agent wrote the script # (agent's tool layer blocks sudo). ONLINE-ONLY: no reboot, no unmount, # no data movement (ext4 grow is forward metadata only). # # Protocol: gates -> table backup -> swapoff+fstab -> delete sda5+sda2 # -> rewrite table with sda1 filling the disk (start sector UNCHANGED) # -> partx online update -> resize2fs -> verify. set -euo pipefail [ "$EUID" -eq 0 ] || exec sudo bash "$0" OUT=/home/reachableceo/projects/ultix/16-grow-root-online.out exec > >(tee "$OUT") 2>&1 echo "== grow / online $(date -Is) ==" DEV=/dev/sda PART=${DEV}1 echo "-- gates" [ "$(findmnt -n -o SOURCE /)" = "$PART" ] || { echo "FAIL: / is not on $PART"; exit 1; } [ "$(findmnt -n -o FSTYPE /)" = "ext4" ] || { echo "FAIL: / is not ext4"; exit 1; } SWAP_USED=$(awk '$1=="/dev/sda5" {print $4}' /proc/swaps) [ "${SWAP_USED:-0}" = "0" ] || { echo "FAIL: swap has ${SWAP_USED}kB in use; retry when empty"; exit 1; } AVAIL_MB=$(free -m | awk '/^Mem:/ {print $7}') [ "$AVAIL_MB" -gt 4096 ] || { echo "FAIL: only ${AVAIL_MB}MB free RAM"; exit 1; } echo "-- backup partition table (rollback artifact)" TS=$(date +%Y%m%d-%H%M%S) sfdisk -d "$DEV" > "/root/sda-table.backup-$TS" cp "/root/sda-table.backup-$TS" /home/reachableceo/projects/ultix/ cat "/root/sda-table.backup-$TS" | sed 's/^/ /' DUMP=$(sfdisk -d "$DEV") echo "$DUMP" | grep -q 'start= *2048,' || { echo "FAIL: sda1 does not start at sector 2048; abort"; exit 1; } echo "-- swapoff + comment fstab swap line" swapoff /dev/sda5 sed -i 's/^UUID=611d6da8-3fd6-40f0-9239-d8825a6d256c/#&/' /etc/fstab grep -n swap /etc/fstab | sed 's/^/ /' echo "-- delete sda5 (swap) and sda2 (extended container)" sfdisk --delete "$DEV" 5 sfdisk --delete "$DEV" 2 partprobe "$DEV" || true lsblk "$DEV" | sed 's/^/ /' echo "-- rewrite table: sda1 fills the disk (start 2048 unchanged)" DISKSECT=$(blockdev --getsz "$DEV") NEWSEC=$((DISKSECT - 2048)) echo " disk sectors: $DISKSECT, new sda1 size: $NEWSEC" sfdisk -d "$DEV" | awk -v new="$NEWSEC" ' /^last-lba:/ { next } /^\/dev\/sda1/ { sub(/size= *[0-9]+/, "size=" new); print; next } { print } ' > /tmp/sda-grown.table cat /tmp/sda-grown.table | sed 's/^/ /' sfdisk --force "$DEV" < /tmp/sda-grown.table partx --update "$DEV" || partprobe "$DEV" echo "-- online ext4 grow" resize2fs "$PART" echo "-- verify" blockdev --getsz "$PART" lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT "$DEV" | sed 's/^/ /' df -h / | sed 's/^/ /' cat /proc/swaps echo "== done $(date -Is) — no reboot needed; swap is gone by design" echo " (rollback BEFORE resize2fs only: sfdisk $DEV < /root/sda-table.backup-$TS)" chown reachableceo:reachableceo "$OUT" 2>/dev/null || true