#!/bin/sh # (C) Copyright 2020-2026 # Scott Wiederhold, s.e.wiederhold@gmail.com # https://community.openglow.org # SPDX-License-Identifier: MIT # # Legacy-layout migration: reclaims the legacy ForgeFIRM partition (p4) # and grows /data (p3) to the end of the eMMC, restoring the factory # disk footprint. Runs in rcS before mountall, so /data is not yet # mounted. Every step is keyed off the actual disk state - an # interrupted run resumes on the next boot; a factory-layout disk is a # fast no-op. Only acts when booted from an eMMC rootfs slot: SD boots # (bench/dev) never touch the eMMC and p4 itself must not saw off its # own branch. DISK=/dev/mmcblk2 P3=${DISK}p3 log () { echo "slotmigrate: $*" echo "slotmigrate: $*" > /dev/kmsg 2>/dev/null } case "$1" in start|"") ;; *) exit 0 ;; esac # Runs at S02, possibly before the sysfs/proc mount scripts. mountpoint -q /proc 2>/dev/null || mount -t proc proc /proc 2>/dev/null mountpoint -q /sys 2>/dev/null || mount -t sysfs sysfs /sys 2>/dev/null [ -r /proc/cmdline ] || exit 0 ROOT=$(sed -n 's/.*root=\([^ ]*\).*/\1/p' /proc/cmdline) case "$ROOT" in /dev/mmcblk2p1|/dev/mmcblk2p2) ;; *) exit 0 ;; esac command -v sfdisk >/dev/null || { log "sfdisk missing, skipping"; exit 0; } if grep -q "^${P3} " /proc/mounts; then log "/data already mounted, skipping this boot" exit 0 fi # --- partition table ----------------------------------------------------- if sfdisk -d "$DISK" 2>/dev/null | grep -q "^${DISK}p4"; then log "removing legacy partition p4" sfdisk --no-reread --force --delete "$DISK" 4 >/dev/null 2>&1 \ || { log "p4 delete FAILED"; exit 0; } partx -d --nr 4 "$DISK" 2>/dev/null fi DISK_SECT=$(cat /sys/class/block/mmcblk2/size 2>/dev/null) P3_START=$(sfdisk -d "$DISK" 2>/dev/null | sed -n "s|^${P3} : start=[ ]*\([0-9]*\),.*|\1|p") P3_SIZE=$(sfdisk -d "$DISK" 2>/dev/null | sed -n "s|^${P3} .*size=[ ]*\([0-9]*\),.*|\1|p") [ -n "$DISK_SECT" ] && [ -n "$P3_START" ] && [ -n "$P3_SIZE" ] \ || { log "cannot read disk/p3 geometry"; exit 0; } # 2048-sector tolerance (mirrors the filesystem branch): on a disk where # the grow cannot land exactly on the last sector, an exact comparison # would rewrite the MBR at S02 on EVERY boot - and a power loss inside # that window costs the partition table and /data. if [ $((P3_START + P3_SIZE)) -lt $((DISK_SECT - 2048)) ]; then log "growing p3 toward the end of the disk ($((P3_START + P3_SIZE)) -> $DISK_SECT sectors)" echo ", +" | sfdisk --no-reread --force -N 3 "$DISK" >/dev/null 2>&1 \ || { log "p3 grow FAILED"; exit 0; } partx -u --nr 3 "$DISK" 2>/dev/null P3_NEW=$(sfdisk -d "$DISK" 2>/dev/null | sed -n "s|^${P3} .*size=[ ]*\([0-9]*\),.*|\1|p") if [ -n "$P3_NEW" ] && [ "$P3_NEW" = "$P3_SIZE" ]; then log "p3 grow made no progress ($P3_SIZE sectors); leaving the table alone" exit 0 fi fi # --- filesystem ---------------------------------------------------------- PART_SECT=$(cat /sys/class/block/mmcblk2p3/size 2>/dev/null) [ -n "$PART_SECT" ] || { log "cannot read p3 size"; exit 0; } FS_BLOCKS=$(tune2fs -l "$P3" 2>/dev/null | sed -n 's/^Block count:[ ]*//p') FS_BSIZE=$(tune2fs -l "$P3" 2>/dev/null | sed -n 's/^Block size:[ ]*//p') [ -n "$FS_BLOCKS" ] && [ -n "$FS_BSIZE" ] || { log "cannot read p3 filesystem"; exit 0; } # Bounded retry: a resize that keeps failing must not cost a full # e2fsck pass on every boot forever. Nothing else is mounted this # early, so the attempt counter lives on p3 itself. TRY_FILE=.slotmigrate-resize-tries read_tries () { TRIES=0 T=$(mktemp -d) || return if mount "$P3" "$T" 2>/dev/null; then TRIES=$(cat "$T/$TRY_FILE" 2>/dev/null) umount "$T" 2>/dev/null fi rmdir "$T" 2>/dev/null case "$TRIES" in ''|*[!0-9]*) TRIES=0 ;; esac } write_tries () { T=$(mktemp -d) || return if mount "$P3" "$T" 2>/dev/null; then if [ "$1" -gt 0 ]; then echo "$1" > "$T/$TRY_FILE" else rm -f "$T/$TRY_FILE" fi umount "$T" 2>/dev/null fi rmdir "$T" 2>/dev/null } FS_SECT=$((FS_BLOCKS * (FS_BSIZE / 512))) if [ "$FS_SECT" -lt $((PART_SECT - 2048)) ]; then read_tries if [ "$TRIES" -ge 3 ]; then log "resize2fs failed $TRIES times; giving up (grow /data manually with resize2fs $P3)" exit 0 fi log "growing /data filesystem ($FS_SECT -> $PART_SECT sectors)" e2fsck -f -p "$P3" >/dev/null 2>&1 RC=$? if [ "$RC" -ge 4 ]; then log "e2fsck found errors (rc=$RC), NOT resizing" exit 0 fi if resize2fs "$P3" >/dev/null 2>&1; then log "/data grown to full size" write_tries 0 else log "resize2fs FAILED (attempt $((TRIES + 1)) of 3)" write_tries $((TRIES + 1)) fi fi exit 0