#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later
# /usr/sbin/pocketds-fs-resize -- first-boot expansion of PARTLABEL=STORAGE
# (the rootfs partition; sda2 on a typical Pocket DS SD layout) to fill
# the entire SD/eMMC, followed by an online ext4 resize. Triggered by
# pocketds-fs-resize.service when /storage/.please_resize_me exists --
# pocketds.spec %post base writes that marker on every install/upgrade,
# but the systemd unit's ExecStartPost removes it after a successful run
# so on every subsequent boot the unit's ConditionPathExists is false.
#
# Partition growth is done by growpart (cloud-utils-growpart), the same
# tool every cloud image uses for exactly this job. The previous
# parted-based implementation had two field failures:
#   * `parted -s resizepart` asks "Partition ... is being used.
#     Continue?" when the target partition is mounted (it always is --
#     it's the rootfs) and script mode answers that prompt with an
#     abort, so the partition never grew and every later download
#     (Steam client, runtime, Proton) ran the rootfs out of space.
#   * some parted builds cleared the GPT partition Name during
#     resizepart, breaking root=PARTLABEL=STORAGE on the next boot.
# growpart handles both: it drives sfdisk with the original dump (Name
# and UUID preserved), relocates the GPT backup header itself, and
# notifies the kernel of the new size via BLKPG (works while mounted).
#
# The ext4 grow is attempted online here (kernel >= 3.6 handles a
# mounted-rootfs grow fine); if that fails the busybox initramfs picks
# it up offline on the next boot (its init runs resize2fs against the
# root partition before mounting it), so a failed online resize is
# logged but NOT fatal to the service.

set -u -o pipefail

ROOT_DEV=$(/usr/sbin/blkid -L STORAGE 2>/dev/null || /usr/bin/findfs PARTLABEL=STORAGE)
if [ -z "${ROOT_DEV:-}" ]; then
    echo "pocketds-fs-resize: no PARTLABEL=STORAGE; nothing to do" >&2
    exit 0
fi

# /dev/sda2 -> parent /dev/sda + partnum 2 (also handles mmcblk0p2).
PARENT_NAME=$(/usr/bin/lsblk -no PKNAME "$ROOT_DEV")
PARENT="/dev/$PARENT_NAME"
PART_NUM=$(echo "$ROOT_DEV" | /usr/bin/grep -oE '[0-9]+$')

echo "pocketds-fs-resize: ROOT=$ROOT_DEV  PARENT=$PARENT  PART_NUM=$PART_NUM"

# Capture the GPT partition Name so we can verify growpart preserved it
# (root=PARTLABEL=STORAGE lookups in the busybox init depend on it).
ORIG_NAME=""
if /usr/bin/lsblk -no PTTYPE "$PARENT" | /usr/bin/grep -q '^gpt$'; then
    ORIG_NAME=$(/usr/sbin/sgdisk -i "$PART_NUM" "$PARENT" 2>/dev/null \
                | /usr/bin/awk -F"'" '/Partition name/{print $2}')
    echo "pocketds-fs-resize: pre-resize PARTNAME=\"$ORIG_NAME\""
fi

# Grow the partition. Exit 0 = grown, 1 = NOCHANGE (already at max --
# fine, e.g. re-run after a failed resize2fs), 2 = real failure.
/usr/bin/growpart "$PARENT" "$PART_NUM"
rc=$?
if [ "$rc" -ge 2 ]; then
    echo "pocketds-fs-resize: growpart failed (rc=$rc)" >&2
    exit 1
fi

# Belt-and-braces: re-assert the GPT Name if anything dropped it.
if /usr/bin/lsblk -no PTTYPE "$PARENT" | /usr/bin/grep -q '^gpt$'; then
    NEW_NAME=$(/usr/sbin/sgdisk -i "$PART_NUM" "$PARENT" 2>/dev/null \
               | /usr/bin/awk -F"'" '/Partition name/{print $2}')
    if [ "$NEW_NAME" != "${ORIG_NAME:-STORAGE}" ]; then
        SET_NAME=${ORIG_NAME:-STORAGE}
        echo "pocketds-fs-resize: re-setting PARTNAME=\"$SET_NAME\" (was=\"$NEW_NAME\")"
        /usr/sbin/sgdisk -c "$PART_NUM:$SET_NAME" "$PARENT" >/dev/null 2>&1 || true
    fi
fi

/usr/bin/udevadm settle 2>/dev/null || true

# Online grow ext4. Failure is non-fatal by design: the initramfs
# resize2fs finishes the job offline on the next boot.
if /usr/sbin/resize2fs "$ROOT_DEV"; then
    echo "pocketds-fs-resize: done"
else
    echo "pocketds-fs-resize: online resize2fs failed -- the initramfs" \
         "will grow the fs offline on the next boot" >&2
fi
exit 0
