#!/bin/sh

set -e

echo "installing derive (iso installer)."
echo

#check we are root
if [ "$(id -u)" -ne 0 ]; then
    echo "error: must run as root"
    exit 1
fi

#defaults
DISK=""
PART_STYLE="gpt"
BOOT_SIZE_MB=512
HOSTNAME="derive"
SWAP_SIZE_MB=0
AUTO_MODE=0

print_usage() {
    cat <<EOF
usage: iso-install [options]

options:
  -d DISK       target disk (e.g. /dev/vda)
  -p STYLE      partition style: gpt (default) or mbr
  -b MB         boot partition size in MiB (default: 512)
  -s MB         swap size in MiB (0 to skip)
  -n NAME       hostname (default: derive)
  -y            assume yes / non-interactive
  -h            show this help

examples:
  iso-install -d /dev/vda -p gpt -b 512 -s 2048 -n myhost
EOF
}

while getopts "d:p:b:s:n:yh" opt; do
    case "$opt" in
        d) DISK="$OPTARG" ;;
        p) PART_STYLE="$OPTARG" ;;
        b) BOOT_SIZE_MB="$OPTARG" ;;
        s) SWAP_SIZE_MB="$OPTARG" ;;
        n) HOSTNAME="$OPTARG" ;;
        y) AUTO_MODE=1 ;;
        h)
            print_usage
            exit 0
            ;;
        *)
            print_usage
            exit 1
            ;;
    esac
done

shift $((OPTIND - 1))

case "$PART_STYLE" in
    gpt|mbr) ;;
    *)
        echo "error: partition style must be gpt or mbr"
        exit 1
        ;;
esac

if [ "$PART_STYLE" = "gpt" ] && ! command -v sgdisk >/dev/null 2>&1; then
    echo "error: sgdisk not found; cannot create GPT partition layout"
    exit 1
fi

if [ "$AUTO_MODE" -eq 0 ] && [ -z "$DISK" ]; then
    echo "available disks:"
    for disk in /sys/block/sd* /sys/block/vd* /sys/block/nvme*; do
        [ -e "$disk" ] || continue
        name=$(basename "$disk")
        size=$(cat "$disk/size" 2>/dev/null || echo 0)
        size_gb=$((size / 2097152))
        [ "$size_gb" -gt 0 ] && echo "  /dev/$name (${size_gb}GB)"
    done
    echo

    printf "install to which disk? (e.g., sda, vda): "
    read -r DISK_NAME
    DISK="/dev/$DISK_NAME"
fi

if [ -z "$DISK" ]; then
    echo "error: no disk specified (use -d /dev/<disk>)"
    exit 1
fi

if [ ! -b "$DISK" ]; then
    echo "error: $DISK is not a block device"
    exit 1
fi

if [ "$AUTO_MODE" -eq 0 ]; then
    echo
    echo "warning: This will erase all data on $DISK"
    printf "Type 'yes' to continue: "
    read -r confirm

    if [ "$confirm" != "yes" ]; then
        echo "installation cancelled"
        exit 0
    fi
fi

#interactive
if [ "$AUTO_MODE" -eq 0 ]; then
    echo
    echo "some setup."
    echo

    printf "hostname [$HOSTNAME]: "
    read -r INPUT_HOSTNAME
    [ -n "$INPUT_HOSTNAME" ] && HOSTNAME="$INPUT_HOSTNAME"
fi

# root passwd
echo
echo "root user"
while true; do
    printf "root password: "
    stty -echo 2>/dev/null
    read -r ROOT_PASS
    stty echo 2>/dev/null
    echo

    printf "confirm password: "
    stty -echo 2>/dev/null
    read -r ROOT_PASS_CONFIRM
    stty echo 2>/dev/null
    echo

    if [ "$ROOT_PASS" = "$ROOT_PASS_CONFIRM" ]; then
        break
    else
        echo "passwords do not match, try again"
        echo
    fi
done

#user sloop
USERS_CREATED=0
while true; do
    echo
    if [ $USERS_CREATED -eq 0 ]; then
        printf "create user [leave empty to skip]: "
    else
        printf "create another user? (y/n) [n]: "
        read -r ADD_USER
        ADD_USER="${ADD_USER:-n}"
        case "$ADD_USER" in
            y|Y|yes|YES)
                printf "username: "
                ;;
            *) break ;;
        esac
    fi

    read -r USERNAME
    [ -z "$USERNAME" ] && break

    echo
    echo "user $USERNAME"
    while true; do
        printf "password: "
        stty -echo 2>/dev/null
        read -r USER_PASS
        stty echo 2>/dev/null
        echo

        printf "confirm password: "
        stty -echo 2>/dev/null
        read -r USER_PASS_CONFIRM
        stty echo 2>/dev/null
        echo

        if [ "$USER_PASS" = "$USER_PASS_CONFIRM" ]; then
            break
        else
            echo "passwords do not match, try again"
            echo
        fi
    done

    # store user info for later (after filesystem is mounted)
    USERS_CREATED=$((USERS_CREATED + 1))
    eval "USER_${USERS_CREATED}_NAME=\"\$USERNAME\""
    eval "USER_${USERS_CREATED}_PASS=\"\$USER_PASS\""
done

echo
echo "installing derive to $DISK"

for part in "$DISK"*; do
    [ -b "$part" ] && umount "$part" 2>/dev/null || true
done

echo
echo "partitioning disk..."
echo "  preparing $PART_STYLE partition layout..."

DISK_NAME=$(basename "$DISK")
DISK_SIZE=$(cat "/sys/block/$DISK_NAME/size")
BOOT_START=2048  # 1MiB
BOOT_SIZE_SECTORS=$((BOOT_SIZE_MB * 2048))
SWAP_SIZE_SECTORS=$((SWAP_SIZE_MB * 2048))
ROOT_START=$((BOOT_START + BOOT_SIZE_SECTORS))

if [ "$PART_STYLE" = "gpt" ]; then
    echo "  using GPT layout (FAT32 ESP + root + optional swap)"
    dd if=/dev/zero of="$DISK" bs=1M count=8 conv=notrunc >/dev/null 2>&1

    sgdisk --zap-all "$DISK" >/dev/null 2>&1 || true
    sgdisk -og "$DISK" >/dev/null || {
        echo "error: failed to initialize GPT on $DISK"
        exit 1
    }
    sgdisk -n 1:2048:+${BOOT_SIZE_MB}M -t 1:ef00 -c 1:"EFIBOOT" "$DISK" >/dev/null || {
        echo "error: failed to create EFI partition on $DISK"
        exit 1
    }
    if [ "$SWAP_SIZE_MB" -gt 0 ]; then
        sgdisk -n 2:0:+${SWAP_SIZE_MB}M -t 2:8200 -c 2:"SWAP" "$DISK" >/dev/null || {
            echo "error: failed to create swap partition on $DISK"
            exit 1
        }
        sgdisk -n 3:0:0 -t 3:8300 -c 3:"ROOT" "$DISK" >/dev/null || {
            echo "error: failed to create root partition on $DISK"
            exit 1
        }
    else
        sgdisk -n 2:0:0 -t 2:8300 -c 2:"ROOT" "$DISK" >/dev/null || {
            echo "error: failed to create root partition on $DISK"
            exit 1
        }
    fi
elif [ "$PART_STYLE" = "mbr" ]; then
    echo "  using MBR layout (FAT32 boot + root + optional swap)"
    ROOT_SIZE=$((DISK_SIZE - ROOT_START - SWAP_SIZE_SECTORS))

    dd if=/dev/zero of="$DISK" bs=1M count=10 >/dev/null 2>&1

    {
        printf '\x55\xAA' | dd of="$DISK" bs=1 seek=510 conv=notrunc 2>/dev/null

        BOOT_B1=$((BOOT_START & 0xFF))
        BOOT_B2=$(((BOOT_START >> 8) & 0xFF))
        BOOT_B3=$(((BOOT_START >> 16) & 0xFF))
        BOOT_B4=$(((BOOT_START >> 24) & 0xFF))

        BOOT_SIZE_B1=$((BOOT_SIZE_SECTORS & 0xFF))
        BOOT_SIZE_B2=$(((BOOT_SIZE_SECTORS >> 8) & 0xFF))
        BOOT_SIZE_B3=$(((BOOT_SIZE_SECTORS >> 16) & 0xFF))
        BOOT_SIZE_B4=$(((BOOT_SIZE_SECTORS >> 24) & 0xFF))

        printf '\x80\x00\x00\x00\x0C\x00\x00\x00' | dd of="$DISK" bs=1 seek=446 conv=notrunc 2>/dev/null
        printf "\\x$(printf '%02x' $BOOT_B1)\\x$(printf '%02x' $BOOT_B2)\\x$(printf '%02x' $BOOT_B3)\\x$(printf '%02x' $BOOT_B4)" | \
            dd of="$DISK" bs=1 seek=454 conv=notrunc 2>/dev/null
        printf "\\x$(printf '%02x' $BOOT_SIZE_B1)\\x$(printf '%02x' $BOOT_SIZE_B2)\\x$(printf '%02x' $BOOT_SIZE_B3)\\x$(printf '%02x' $BOOT_SIZE_B4)" | \
            dd of="$DISK" bs=1 seek=458 conv=notrunc 2>/dev/null

        ROOT_B1=$((ROOT_START & 0xFF))
        ROOT_B2=$(((ROOT_START >> 8) & 0xFF))
        ROOT_B3=$(((ROOT_START >> 16) & 0xFF))
        ROOT_B4=$(((ROOT_START >> 24) & 0xFF))

        ROOT_SIZE_B1=$((ROOT_SIZE & 0xFF))
        ROOT_SIZE_B2=$(((ROOT_SIZE >> 8) & 0xFF))
        ROOT_SIZE_B3=$(((ROOT_SIZE >> 16) & 0xFF))
        ROOT_SIZE_B4=$(((ROOT_SIZE >> 24) & 0xFF))

        printf '\x00\x00\x00\x00\x83\x00\x00\x00' | dd of="$DISK" bs=1 seek=462 conv=notrunc 2>/dev/null
        printf "\\x$(printf '%02x' $ROOT_B1)\\x$(printf '%02x' $ROOT_B2)\\x$(printf '%02x' $ROOT_B3)\\x$(printf '%02x' $ROOT_B4)" | \
            dd of="$DISK" bs=1 seek=470 conv=notrunc 2>/dev/null
        printf "\\x$(printf '%02x' $ROOT_SIZE_B1)\\x$(printf '%02x' $ROOT_SIZE_B2)\\x$(printf '%02x' $ROOT_SIZE_B3)\\x$(printf '%02x' $ROOT_SIZE_B4)" | \
            dd of="$DISK" bs=1 seek=474 conv=notrunc 2>/dev/null

        if [ "$SWAP_SIZE_MB" -gt 0 ]; then
            SWAP_START=$((DISK_SIZE - SWAP_SIZE_SECTORS))
            SWAP_B1=$((SWAP_START & 0xFF))
            SWAP_B2=$(((SWAP_START >> 8) & 0xFF))
            SWAP_B3=$(((SWAP_START >> 16) & 0xFF))
            SWAP_B4=$(((SWAP_START >> 24) & 0xFF))

            SWAP_SIZE_B1=$((SWAP_SIZE_SECTORS & 0xFF))
            SWAP_SIZE_B2=$(((SWAP_SIZE_SECTORS >> 8) & 0xFF))
            SWAP_SIZE_B3=$(((SWAP_SIZE_SECTORS >> 16) & 0xFF))
            SWAP_SIZE_B4=$(((SWAP_SIZE_SECTORS >> 24) & 0xFF))

            printf '\x00\x00\x00\x00\x82\x00\x00\x00' | dd of="$DISK" bs=1 seek=478 conv=notrunc 2>/dev/null
            printf "\\x$(printf '%02x' $SWAP_B1)\\x$(printf '%02x' $SWAP_B2)\\x$(printf '%02x' $SWAP_B3)\\x$(printf '%02x' $SWAP_B4)" | \
                dd of="$DISK" bs=1 seek=486 conv=notrunc 2>/dev/null
            printf "\\x$(printf '%02x' $SWAP_SIZE_B1)\\x$(printf '%02x' $SWAP_SIZE_B2)\\x$(printf '%02x' $SWAP_SIZE_B3)\\x$(printf '%02x' $SWAP_SIZE_B4)" | \
                dd of="$DISK" bs=1 seek=490 conv=notrunc 2>/dev/null
        fi
    } 2>&1 | grep -v "records" || true
fi

sync

if [ "$PART_STYLE" = "gpt" ]; then
    _pt_count=$(sgdisk -p "$DISK" 2>/dev/null | awk '/^[[:space:]]*[0-9]+[[:space:]]+/ {c++} END {print c+0}')
    if [ "$_pt_count" -lt 2 ]; then
        echo "error: GPT partitioning failed on $DISK"
        echo "sgdisk did not report expected partitions"
        sgdisk -p "$DISK" 2>/dev/null || true
        exit 1
    fi
fi

BOOT_INDEX=1
if [ "$PART_STYLE" = "gpt" ]; then
    if [ "$SWAP_SIZE_MB" -gt 0 ]; then
        ROOT_INDEX=3
        SWAP_INDEX=2
    else
        ROOT_INDEX=2
        SWAP_INDEX=0
    fi
else
    ROOT_INDEX=2
    if [ "$SWAP_SIZE_MB" -gt 0 ]; then
        SWAP_INDEX=3
    else
        SWAP_INDEX=0
    fi
fi

PART_DELIM=""
case "$DISK_NAME" in
    *[0-9]) PART_DELIM="p" ;;
esac

part_label() {
    printf '%s%s%s' "$DISK_NAME" "$PART_DELIM" "$1"
}

part_path() {
    printf '%s%s%s' "$DISK" "$PART_DELIM" "$1"
}

ensure_part_node() {
    local device="$1"
    [ -n "$device" ] || return
    [ -b "$device" ] && return
    local part_name
    part_name=$(basename "$device")
    local info
    info=$(awk -v part="$part_name" '$4==part {print $1":"$2}' /proc/partitions 2>/dev/null | head -1)
    [ -z "$info" ] && return
    local major=${info%%:*}
    local minor=${info##*:}
    mknod "$device" b "$major" "$minor" 2>/dev/null || true
}

BOOT_PART=$(part_path "$BOOT_INDEX")
ROOT_PART=$(part_path "$ROOT_INDEX")
BOOT_LABEL=$(part_label "$BOOT_INDEX")
ROOT_LABEL=$(part_label "$ROOT_INDEX")
SWAP_PART=""
SWAP_LABEL=""
if [ "$SWAP_INDEX" -gt 0 ]; then
    SWAP_PART=$(part_path "$SWAP_INDEX")
    SWAP_LABEL=$(part_label "$SWAP_INDEX")
fi

echo "  forcing kernel to re-read partition table..."

REQUIRED_PARTS="$BOOT_LABEL $ROOT_LABEL"
[ -n "$SWAP_LABEL" ] && REQUIRED_PARTS="$REQUIRED_PARTS $SWAP_LABEL"

for attempt in 1 2 3 4 5; do
    if command -v blockdev >/dev/null 2>&1; then
        blockdev --rereadpt "$DISK" 2>/dev/null || true
    fi
    if command -v partprobe >/dev/null 2>&1; then
        partprobe "$DISK" 2>/dev/null || true
    fi

    mdev -s 2>/dev/null || true

    sync
    sleep 1

    all_found=1
    for part in $REQUIRED_PARTS; do
        if ! grep -q "$part" /proc/partitions; then
            all_found=0
            break
        fi
    done

    if [ "$all_found" -eq 1 ]; then
        echo "  partitions detected"
        break
    fi

    [ "$attempt" -eq 5 ] && echo "  warning: some partitions may not be detected yet"
done

sync
sleep 1

mdev -s 2>/dev/null || true

echo "  waiting for partitions to appear..."
for i in 1 2 3 4 5 6 7 8 9 10; do
    ready=1
    for dev in "$BOOT_PART" "$ROOT_PART" ${SWAP_PART:+$SWAP_PART}; do
        if [ -n "$dev" ] && [ ! -b "$dev" ]; then
            ready=0
            break
        fi
    done
    [ "$ready" -eq 1 ] && break
    if command -v partprobe >/dev/null 2>&1; then
        partprobe "$DISK" 2>/dev/null || true
    fi
    mdev -s 2>/dev/null || true
    sleep 1
done

ensure_part_node "$BOOT_PART"
ensure_part_node "$ROOT_PART"
[ -n "$SWAP_PART" ] && ensure_part_node "$SWAP_PART"

if [ ! -b "$BOOT_PART" ] || [ ! -b "$ROOT_PART" ]; then
    echo "error: partitions not found"
    echo "available partitions:"
    cat /proc/partitions
    exit 1
fi

if [ "$SWAP_INDEX" -gt 0 ] && [ ! -b "$SWAP_PART" ]; then
    echo "warning: swap partition missing; continuing without swap"
    SWAP_PART=""
    SWAP_LABEL=""
fi

echo "formatting $BOOT_PART as vfat..."
if ! mkfs.vfat "$BOOT_PART" 2>&1; then
    echo "error: failed to format boot partition"
    exit 1
fi

echo "formatting $ROOT_PART as ext4..."
if ! make_ext4fs -L derive "$ROOT_PART" 2>&1; then
    echo "error: failed to format root partition"
    exit 1
fi

if [ -n "$SWAP_PART" ]; then
    echo "formatting $SWAP_PART as swap..."
    if ! mkswap "$SWAP_PART" >/dev/null 2>&1; then
        echo "warning: failed to format swap partition"
        SWAP_PART=""
        SWAP_LABEL=""
    fi
fi

sync
sleep 1

echo "mounting $ROOT_PART..."
MNT="/mnt/derive"
mkdir -p "$MNT"
if ! mount -t ext4 "$ROOT_PART" "$MNT"; then
    echo "error: failed to mount $ROOT_PART"
    exit 1
fi

mkdir -p "$MNT/boot"
echo "mounting $BOOT_PART to /boot..."
if ! mount -t vfat "$BOOT_PART" "$MNT/boot"; then
    echo "error: failed to mount boot partition"
    umount "$MNT"
    exit 1
fi

echo "copying system files"
echo

COPY_DIRS="bin boot dev etc home include lib lib64 libexec local opt root sbin share srv usr var"
for dir in $COPY_DIRS; do
    SRC="/$dir"
    if [ -e "$SRC" ] || [ -L "$SRC" ]; then
        echo "  copying /$dir..."
        cp -a "$SRC" "$MNT/" 2>/dev/null || true
    fi
done

mkdir -p "$MNT/proc" "$MNT/sys" "$MNT/dev" "$MNT/run" "$MNT/tmp" "$MNT/mnt"

echo "  ensuring filesystem symlinks..."
[ -e "$MNT/usr" ] || ln -sf . "$MNT/usr"
[ -e "$MNT/lib64" ] || ln -sf lib "$MNT/lib64"

# Restore proper layout if /usr was copied as a real directory.
if [ -d "$MNT/usr" ] && [ ! -L "$MNT/usr" ]; then
    echo "creating filesystem layout"
    echo
    echo "  creating base directories..."
    for d in bin lib lib64 sbin share include libexec etc; do
        if [ -d "$MNT/usr/$d" ]; then
            mkdir -p "$MNT/$d"
            cp -a "$MNT/usr/$d"/. "$MNT/$d/" 2>/dev/null || true
        fi
    done
    rm -rf "$MNT/usr"
    echo "  creating unified hierarchy symlinks..."
    ln -sfn . "$MNT/usr"
    [ -e "$MNT/lib64" ] || ln -sfn lib "$MNT/lib64"
fi

echo
echo "configuring busybox utilities"
cd "$MNT/bin"
for cmd in basename blkdiscard cal cat chgrp chmod chown chroot chvt cksum clear cmp cols comm cp cron ctrlaltdel cut date dd df dirname dmesg du echo ed eject env expand expr fallocate false find flock fold free freeramdisk fsfreeze getconf getty grep halt head hostname hwclock id insmod join kill killall5 last lastlog link ln logger login logname ls lsmod lsusb md5sum mesg mkdir mkfifo mknod mkswap mktemp mount mountpoint mv nice nl nohup nologin od pagesize passwd paste pathchk pidof pivot_root printenv printf ps pwd pwdx readahead readlink renice respawn rev rm rmdir rmmod sed seq setsid sha1sum sha224sum sha256sum sha384sum sha512sum sha512-224sum sha512-256sum sleep sort split sponge stat strings su swaplabel swapoff swapon switch_root sync sysctl tail tar tee test tftp time touch tr true truncate tsort tty umount uname unexpand uniq unlink unshare uptime uudecode uuencode vtallow watch wc which who whoami xargs yes; do
    if [ -f "$cmd" ] && [ "$cmd" != "busybox" ]; then
        rm -f "$cmd"
        ln -s busybox "$cmd"
    fi
done
cd - >/dev/null

echo "  setting permissions..."
for dir in bin boot etc include lib local sbin share var; do
    if [ -d "$MNT/$dir" ]; then
        chown -R root:root "$MNT/$dir"
    fi
done

# Ensure system directories have correct permissions
for dir in "$MNT"/*; do
    if [ -d "$dir" ] && [ ! -L "$dir" ]; then
        case "$(basename "$dir")" in
            tmp)
                chmod 1777 "$dir"  # sticky bit + world writable
                ;;
            proc|sys|dev|run)
                ;;
            *)
                chmod 755 "$dir"  # readable/executable by all, writable by root only
                ;;
        esac
    fi
done

echo
echo "setting hostname"

echo "$HOSTNAME" > "$MNT/etc/hostname"
echo "setting passwords"
# Configure root password
if command -v mkpasswd >/dev/null 2>&1; then
    ROOT_HASH=$(mkpasswd -m sha-512 "$ROOT_PASS")
else
    echo "could not generate password hash"
fi

# Update root password in shadow file
if [ -f "$MNT/etc/shadow" ]; then
    # Old compat thing for sbase
    sed "s|^root:[^:]*:|root:$ROOT_HASH:|" "$MNT/etc/shadow" > "$MNT/etc/shadow.tmp"
    mv "$MNT/etc/shadow.tmp" "$MNT/etc/shadow"
    chmod 600 "$MNT/etc/shadow"
else
    # Create shadow file if it doesn't exist
    cat > "$MNT/etc/shadow" <<EOF
root:$ROOT_HASH:19000:0:99999:7:::
EOF
    chmod 600 "$MNT/etc/shadow"
fi

if [ $USERS_CREATED -gt 0 ]; then
    CURRENT_UID=1000
    USER_NUM=1

    while [ $USER_NUM -le $USERS_CREATED ]; do
        eval "USERNAME=\$USER_${USER_NUM}_NAME"
        eval "USER_PASS=\$USER_${USER_NUM}_PASS"

        echo "creating user $USERNAME"

        # Get next available UID
        if [ -f "$MNT/etc/passwd" ]; then
            LAST_UID=$(awk -F: '$3 >= 1000 && $3 < 65534 {print $3}' "$MNT/etc/passwd" | sort -n | tail -1)
            [ -n "$LAST_UID" ] && CURRENT_UID=$((LAST_UID + 1))
        fi

        if command -v mkpasswd >/dev/null 2>&1; then
            USER_HASH=$(mkpasswd -m sha-512 "$USER_PASS")
        else
	    echo "could not generate password hash"
        fi

        mkdir -p "$MNT/home/$USERNAME"

        if [ -f "$MNT/etc/passwd" ]; then
            echo "$USERNAME:x:$CURRENT_UID:$CURRENT_UID::/home/$USERNAME:/bin/sh" >> "$MNT/etc/passwd"
        else
            cat > "$MNT/etc/passwd" <<EOF
root:x:0:0:root:/:/bin/sh
$USERNAME:x:$CURRENT_UID:$CURRENT_UID::/home/$USERNAME:/bin/sh
EOF
        fi

        # Add user to shadow
        echo "$USERNAME:$USER_HASH:19000:0:99999:7:::" >> "$MNT/etc/shadow"

        # Add user to group
        if [ -f "$MNT/etc/group" ]; then
            if ! grep -q "^$USERNAME:" "$MNT/etc/group"; then
                echo "$USERNAME:x:$CURRENT_UID:" >> "$MNT/etc/group"
            fi
        else
            cat > "$MNT/etc/group" <<EOF
root:x:0:
$USERNAME:x:$CURRENT_UID:
EOF
        fi

        # Ensure wheel group exists and add user to it
        if ! grep -q "^wheel:" "$MNT/etc/group"; then
            echo "wheel:x:10:" >> "$MNT/etc/group"
        fi
        WHEEL_LINE=$(grep "^wheel:" "$MNT/etc/group")
        if [ -z "${WHEEL_LINE##*:}" ]; then
            sed "s/^wheel:x:10:$/wheel:x:10:$USERNAME/" "$MNT/etc/group" > "$MNT/etc/group.tmp"
            mv "$MNT/etc/group.tmp" "$MNT/etc/group"
        else
            sed "s/^wheel:x:10:\(.*\)$/wheel:x:10:\1,$USERNAME/" "$MNT/etc/group" > "$MNT/etc/group.tmp"
            mv "$MNT/etc/group.tmp" "$MNT/etc/group"
        fi

        # ownership
        chown -R "$CURRENT_UID:$CURRENT_UID" "$MNT/home/$USERNAME" 2>/dev/null || true

        USER_NUM=$((USER_NUM + 1))
    done
fi

echo
echo "installing bootloader"

KERNEL_IMG=""
for img in /boot/bzImage /boot/vmlinuz* /boot/zImage /boot/Image; do
    if [ -f "$img" ]; then
        KERNEL_IMG="$img"
        break
    fi
done

if [ -z "$KERNEL_IMG" ]; then
    echo "error: kernel image not found in /boot"
    echo "cannot complete installation without a kernel"
    umount "$MNT"
    exit 1
fi

mkdir -p "$MNT/boot"

echo "  copying kernel: $(basename "$KERNEL_IMG")"
cp "$KERNEL_IMG" "$MNT/boot/vmlinuz"


if command -v limine >/dev/null 2>&1 && [ -f /usr/share/limine/limine-bios.sys ]; then
    echo "  installing Limine bootloader files"

    cp /usr/share/limine/limine-bios.sys "$MNT/boot/"

    if [ -f /usr/share/limine/BOOTX64.EFI ]; then
        mkdir -p "$MNT/boot/EFI/BOOT"
        cp /usr/share/limine/BOOTX64.EFI "$MNT/boot/EFI/BOOT/"
    fi

    cat > "$MNT/boot/limine.conf" <<EOF
timeout: 1

/derive
    protocol: linux
    kernel_path: boot():/vmlinuz
    cmdline: console=tty0 console=ttyS0 init=/bin/situation root=$ROOT_PART rootfstype=ext4 rw
EOF

    echo "  bootloader files installed"
else
    echo "  warning: limine not found, system may not boot"
fi

# Create fstab
ROOT_MOUNT_OPTS="defaults,noatime,suid"
cat > "$MNT/etc/fstab" <<EOF
$BOOT_PART  /boot  vfat  defaults  0  2
LABEL=derive  /  ext4  $ROOT_MOUNT_OPTS  0  1
EOF
if [ -n "$SWAP_PART" ]; then
    echo "$SWAP_PART  none  swap  sw  0  0" >> "$MNT/etc/fstab"
fi

sync
umount "$MNT/boot"
umount "$MNT"

#limine bio install
if command -v limine >/dev/null 2>&1; then
    echo "deploying limine to MBR..."
    if ! limine bios-install "$DISK" 2>&1; then
        echo "error: limine bios-install failed"
        exit 1
    fi

    if [ -f /usr/share/limine/BOOTX64.EFI ]; then
        echo "deploying limine to EFI..."
    fi
fi

echo
echo "installation complete"
echo
echo "derive has been installed to $DISK"
echo "remove the installation media and reboot"
echo
