#!/bin/bash
# userland/installer/asys — AnotherOS system management / updater (distro Phase 6).
# Updates a running installed system in place: the kernel on the FAT /boot
# partition, and packages via apkg. Our installed systems boot rootfs= directly
# (no initramfs on disk), so a kernel update is just replacing /boot/kernel.elf
# on the boot partition; Limine picks it up next boot.
#
#   asys info                       show the boot + root partitions
#   asys update-kernel [kernel.elf] replace the boot kernel (from a file, or fetch
#                                   $AREPO_URL/kernel.elf when no file is given)
#   asys update [pkg...]            no args: refresh the index + upgrade every
#                                   package from the remote repo; else install the
#                                   named packages/files (via apkg)
#   asys upgrade                    full system upgrade: packages + kernel
set -e
export MTOOLS_SKIP_CHECK=1

# apkg wrapper: prefer one on PATH, else the dev-disk copy.
APKG=apkg
command -v apkg >/dev/null 2>&1 || { [ -x /bin/apkg ] && APKG=/bin/apkg; }

# Remote repo URL + arch (mirrors apkg's config resolution; per-arch layout).
# The fallback is what this arch IS. It read `i686` until 2026-08-22, which
# was correct when written and became wrong at #138 — if `uname -m` ever
# failed, asys would fetch i686 packages onto an x86_64 machine and the
# repository would answer, because that arch still has a published tree.
AREPO_ARCH="${AREPO_ARCH:-$(uname -m 2>/dev/null || echo x86_64)}"
[ -z "$AREPO_URL" ] && [ -f /etc/apkg.conf ] && . /etc/apkg.conf
if [ -z "$AREPO_URL" ]; then
    for lr in /Packages /Media/cdrom/Packages; do
        [ -f "$lr/$AREPO_ARCH/INDEX" ] && { AREPO_URL="file://$lr"; break; }
    done
fi
AREPO_URL="${AREPO_URL:-http://buildhost.e1z0.net/AnotherOS/Packages}"
fetch() {   # fetch <relpath-under-arch> <outfile>
    local rel="$AREPO_ARCH/$1"
    case "$AREPO_URL" in
        file://*) cp "${AREPO_URL#file://}/$rel" "$2" ;;
        *) if command -v curl >/dev/null 2>&1; then curl -fsSL "$AREPO_URL/$rel" -o "$2"
           elif command -v wget >/dev/null 2>&1; then wget -q -O "$2" "$AREPO_URL/$rel"
           else echo "asys: no curl/wget"; return 1; fi ;;
    esac
}

# Find the FAT (vfat) /boot partition — the one Limine + the kernel live on.
find_boot() {
    local base p t
    while read -r maj min blocks name; do
        case "$name" in sd*[0-9]|vd*[0-9]|hd*[0-9]) ;; *) continue;; esac
        t=$(/sbin/blkid -s TYPE -o value "/dev/$name" 2>/dev/null || true)
        [ "$t" = "vfat" ] && { echo "/dev/$name"; return 0; }
    done < /proc/partitions
    return 1
}
find_root() {
    while read -r maj min blocks name; do
        case "$name" in sd*[0-9]|vd*[0-9]|hd*[0-9]) ;; *) continue;; esac
        [ "$(/sbin/blkid -s TYPE -o value "/dev/$name" 2>/dev/null)" = "ext2" ] && \
            { echo "/dev/$name"; return 0; }
    done < /proc/partitions
    return 1
}

cmd="${1:-info}"; shift || true
case "$cmd" in
info)
    B=$(find_boot || echo "(none)"); R=$(find_root || echo "(none)")
    echo "AnotherOS system:"
    echo "  boot partition (FAT): $B"
    echo "  root partition (ext2): $R  UUID=$(/sbin/blkid -s UUID -o value "$R" 2>/dev/null)"
    echo "  kernel on boot:"; /sbin/mdir -i "$B" ::/boot 2>/dev/null | grep -i kernel || true
    ;;
update-kernel)
    K="$1"
    if [ -z "$K" ]; then
        # No file given: fetch the current kernel from the remote repo.
        K=/tmp/kernel.elf.new
        echo ">> fetching kernel from $AREPO_URL/kernel.elf"
        fetch kernel.elf "$K" || { echo "asys: kernel download failed"; exit 1; }
    fi
    [ -f "$K" ] || { echo "usage: asys update-kernel [kernel.elf]"; exit 1; }
    B=$(find_boot) || { echo "asys: no FAT /boot partition found"; exit 1; }
    echo ">> updating kernel on $B from $K"
    /sbin/mcopy -o -i "$B" "$K" ::/boot/kernel.elf
    echo ">> kernel updated; reboot to run it"
    ;;
update)
    if [ $# -eq 0 ]; then
        # Full package refresh + upgrade from the remote repo.
        echo ">> refreshing package index"; "$APKG" update
        echo ">> upgrading installed packages"; "$APKG" upgrade
    else
        for pkg in "$@"; do echo ">> installing $pkg"; "$APKG" install "$pkg"; done
    fi
    ;;
upgrade)
    echo ">> refreshing package index"; "$APKG" update || true
    echo ">> upgrading installed packages"; "$APKG" upgrade || true
    # Pull a kernel too if the repo publishes one.
    if fetch kernel.elf /tmp/kernel.elf.new 2>/dev/null; then
        B=$(find_boot) && { echo ">> updating boot kernel"; /sbin/mcopy -o -i "$B" /tmp/kernel.elf.new ::/boot/kernel.elf; }
    fi
    echo ">> system upgrade complete; reboot to run a new kernel"
    ;;
*)
    echo "asys: unknown command '$cmd'"
    echo "usage: asys {info | update-kernel [kernel.elf] | update [pkg...] | upgrade}"
    exit 1
    ;;
esac
