new/external/rkscript/disk-helper
2025-05-10 21:58:58 +08:00

427 lines
8.7 KiB
Bash
Executable File

#!/bin/sh
# Uncomment below to see more logs
# set -x
BUSYBOX_MOUNT_OPTS="loop (a|)sync (no|)atime (no|)diratime (no|)relatime (no|)dev (no|)exec (no|)suid (r|)shared (r|)slave (r|)private (un|)bindable (r|)bind move remount ro"
NTFS_3G_MOUNT_OPTS="ro uid=[0-9]* gid=[0-9]* umask=[0-9]* fmask=[0-9]* dmask=[0-9]*"
check_tool()
{
TOOL=$(echo $1 | grep -o "^[^ ]*")
BR2_CONFIG=$2
type $TOOL >/dev/null && return 0
if grep -wq "ID=buildroot" /etc/os-release 2>/dev/null; then
[ -n "$BR2_CONFIG" ] && \
echo "You may need to enable $BR2_CONFIG"
else
echo "Missing tool: $TOOL"
fi
return 1
}
device_from_attr()
{
# It's a block device
if [ -b "$1" ]; then
echo $1
return
fi
# Parse from blkid
blkid 2>/dev/null | grep -w "$1" | head -n 1 | \
grep -o "^[^:]*" && return
# Check mtdblock name
for d in $(ls /dev/ | grep mtdblock); do
if grep -q "^$1$" /sys/block/$d/device/name; then
echo $d
return
fi
done
# Fallback to /dev/block/by-name
if [ -b /dev/block/by-name/$1 ]; then
echo /dev/block/by-name/$1
return
fi
echo $1
}
prepare_ubi()
{
# Only support ubi for mtd device
if echo $DEV | grep -vq /dev/mtd; then
echo "$DEV is not a mtd device!"
return 1
fi
[ "$PART_NO" ] || { echo "No valid part number!" && return 1; }
if [ "$FSGROUP" = ubifs ]; then
DEV=/dev/ubi${PART_NO}_0
else
DEV=/dev/ubiblock${PART_NO}_0
fi
MTDDEV=/dev/mtd${PART_NO}
echo "Preparing $DEV from $MTDDEV"
echo "Remove ubi block device"
if echo $DEV | grep -q ubiblock; then
check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1
ubiblock -r /dev/ubi${PART_NO}_0 &>/dev/null
fi
echo "Detach ubi device"
check_tool ubidetach BR2_PACKAGE_MTD_UBIDETACH || return 1
ubidetach -p $MTDDEV &>/dev/null
echo "Attach ubi device"
check_tool ubiattach BR2_PACKAGE_MTD_UBIATTACH || return 1
ubiattach /dev/ubi_ctrl -m $PART_NO -d $PART_NO || return 1
echo "Check for valid volume"
if [ ! -e /dev/ubi${PART_NO}_0 ]; then
echo "No valid ubi volume"
return 1
fi
echo "Create ubi block device"
if echo $DEV | grep -q ubiblock; then
check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1
ubiblock -c /dev/ubi${PART_NO}_0 || return 1
fi
return 0
}
format_ubifs()
{
echo "Formatting $MTDDEV for $DEV"
echo "Remove ubi block device"
if echo $DEV | grep -q ubiblock; then
check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1
ubiblock -r /dev/ubi${PART_NO}_0 &>/dev/null
fi
echo "Detach ubi device"
check_tool ubidetach BR2_PACKAGE_MTD_UBIDETACH || return 1
ubidetach -p $MTDDEV &>/dev/null
echo "Format device"
check_tool ubiformat BR2_PACKAGE_MTD_UBIFORMAT || return 1
ubiformat -yq $MTDDEV || return 1
echo "Attach ubi device"
ubiattach /dev/ubi_ctrl -m $PART_NO -d $PART_NO || return 1
echo "Create ubi volume"
check_tool ubimkvol BR2_PACKAGE_MTD_UBIMKVOL || return 1
ubimkvol /dev/ubi$PART_NO -N $PART_NAME -m || return 1
echo "Create ubi block device"
if echo $DEV | grep -q ubiblock; then
check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1
ubiblock -c /dev/ubi${PART_NO}_0 || return 1
fi
}
is_rootfs()
{
[ $MOUNT_POINT = "/" ]
}
remount_part()
{
mountpoint -q $MOUNT_POINT || return
if touch $MOUNT_POINT &>/dev/null; then
[ "$1" = ro ] && mount -o remount,ro $MOUNT_POINT
else
[ "$1" = rw ] && mount -o remount,rw $MOUNT_POINT
fi
}
format_part()
{
echo "Formatting $DEV($FSTYPE)"
case $FSGROUP in
ext2)
# Set max-mount-counts to 0, and disable the time-dependent checking.
check_tool mke2fs BR2_PACKAGE_E2FSPROGS && \
mke2fs -F -L $PART_NAME $DEV && \
tune2fs -c 0 -i 0 $DEV
;;
vfat)
# Use fat32 by default
check_tool mkfs.vfat BR2_PACKAGE_DOSFSTOOLS_MKFS_FAT && \
mkfs.vfat -I -F 32 -n $PART_NAME $DEV
;;
ntfs)
# Enable compression
check_tool mkntfs BR2_PACKAGE_NTFS_3G_NTFSPROGS && \
mkntfs -FCQ -L $PART_NAME $DEV
;;
ubifs)
format_ubifs
;;
jffs2)
check_tool mkfs.jffs2 BR2_PACKAGE_MTD_MKFSJFFS2 && \
mkfs.jffs2 -o $DEV 0x10000 --pad=0x400000 -s 0x1000 -n
;;
squashfs)
# check_tool mksquashfs BR2_PACKAGE_SQUASHFS && \
# mksquashfs $DEV
echo "It's pointness to format a squashfs partition..."
false
;;
auto)
echo "Unable to format a auto partition..."
false
;;
*)
echo Unsupported file system $FSTYPE for $DEV
false
;;
esac
}
format_resize()
{
BACKUP=$1
SRC=$(realpath $MOUNT_POINT)
echo "Format-resizing $DEV($FSTYPE)"
echo "Backup original data"
cp -a "$SRC" "$BACKUP/" || return 1
umount "$SRC" || return 1
echo "Format and mount rw"
format_part || return 1
mount_part || return 1
remount_part rw
echo "Restore backup data"
cp -a "$BACKUP/$SRC" $(dirname "$SRC") || return 1
}
resize_ext2()
{
check_tool resize2fs BR2_PACKAGE_E2FSPROGS_RESIZE2FS || return 1
resize2fs $DEV
}
resize_vfat()
{
check_tool fatresize BR2_PACKAGE_FATRESIZE || return 1
SIZE=$(fatresize -i $DEV | grep "Size:" | grep -o "[0-9]*$")
# Somehow fatresize only works for 256M+ fat
[ "$SIZE" -gt $((256 * 1024 * 1024)) ] && return 1
MAX_SIZE=$(( $(cat $SYS_PATH/size) * 512))
MIN_SIZE=$(($MAX_SIZE - 16 * 1024 * 1024))
[ $MIN_SIZE -lt $SIZE ] && return 0 # Large enough!
while [ $MAX_SIZE -gt $MIN_SIZE ];do
# Somehow fatresize cannot resize to max size
MAX_SIZE=$(($MAX_SIZE - 512 * 1024))
# Try to resize with fatresize, not always work
fatresize -s $MAX_SIZE $DEV && return
done
return 1
}
resize_ntfs()
{
check_tool ntfsresize BR2_PACKAGE_NTFS_3G_NTFSPROGS || return 1
echo y | ntfsresize -f $DEV
}
resize_part()
{
# Fixed size or already resized
[ -f $MOUNT_POINT/.fixed -o -f $MOUNT_POINT/.resized ] && return
if [ -z "$FSRESIZE" ]; then
echo "No resize for $FSTYPE"
return
fi
echo "Resizing $DEV($FSTYPE)"
# Online resize needs read-write
remount_part rw
if eval $FSRESIZE; then
touch $MOUNT_POINT/.resized
return
fi
echo "Done with rootfs"
is_rootfs && return
echo "Fallback to format resize"
TEMP_BACKUP=$(mktemp -d)
format_resize $TEMP_BACKUP && touch $MOUNT_POINT/.resized
rm -rf $TEMP_BACKUP
}
convert_mount_opts()
{
# Accept all opts by default for standard mount tool
if [ -z "$@" ] && [ "$(readlink $(which mount))" != busybox ]; then
echo $OPTS
return
fi
# Filter out unsupported opts
for opt in ${@:-$BUSYBOX_MOUNT_OPTS}; do
echo ${OPTS//,/ } | xargs -n 1 | grep -oE "^$opt$"
done | tr "\n" ","
}
prepare_part()
{
# Ignore external storages
case "$MOUNT_POINT" in
/mnt/* | /media/*) return 1 ;;
esac
# Find real dev for root dev
if is_rootfs; then
DEV_NO=$(mountpoint -d /)
DEV_NAME=$(grep -l "^$DEV_NO$" /sys/class/block/*/dev | \
cut -d'/' -f5)
DEV=/dev/$DEV_NAME
fi
DEV=$(realpath $DEV 2>/dev/null)
PART_NO=$(echo $DEV | grep -oE "[0-9]*$")
# Only accept block device
[ -b "$DEV" ] || return 1
SYS_PATH=$(echo /sys/class/*/${DEV##*/})
if [ -f "$SYS_PATH/name" ]; then
PART_NAME=$(cat $SYS_PATH/name)
else
PART_NAME=$(grep PARTNAME ${SYS_PATH}/uevent | cut -d '=' -f 2)
fi
PART_NAME=${PART_NAME:-${DEV##*/}}
case $FSTYPE in
ext[234])
FSGROUP=ext2
FSCK="fsck.$FSTYPE -y"
FSCK_CONFIG=BR2_PACKAGE_E2FSPROGS_FSCK
FSRESIZE=resize_ext2
;;
msdos|fat|vfat)
FSGROUP=vfat
FSCK="fsck.vfat -y"
FSCK_CONFIG=BR2_PACKAGE_DOSFSTOOLS_FSCK_FAT
FSRESIZE=resize_vfat
;;
ntfs)
FSGROUP=ntfs
FSCK=ntfsfix
FSCK_CONFIG=BR2_PACKAGE_NTFS_3G_NTFSPROGS
FSRESIZE=resize_ntfs
;;
ubi|ubifs)
FSTYPE=ubifs
FSGROUP=ubifs
unset FSCK
unset FSRESIZE
;;
squashfs)
FSGROUP=squashfs
unset FSCK
unset FSRESIZE
;;
jffs2)
FSGROUP=jffs2
unset FSCK
unset FSRESIZE
;;
auto)
FSGROUP=auto
echo "Running fsck on a random fs is dangerous"
unset FSCK
unset FSRESIZE
;;
*)
echo "Unsupported file system $FSTYPE for $DEV"
return
esac
# Setup mount tool and opts
case $FSGROUP in
ntfs)
MOUNT=ntfs-3g
check_tool ntfs-3g BR2_PACKAGE_NTFS_3G || return 1
OPTS=$(convert_mount_opts "$NTFS_3G_MOUNT_OPTS")
;;
auto)
MOUNT=mount
OPTS=$(convert_mount_opts)
;;
*)
MOUNT="mount -t $FSTYPE"
OPTS=$(convert_mount_opts)
;;
esac
MOUNT_OPTS=${OPTS:+" -o ${OPTS%,}"}
# Prepare for UBI
if [ "$FSGROUP" = ubifs ]; then
if ! prepare_ubi; then
echo "Failed to prepare ubi for $DEV"
[ "$AUTO_MKFS" ] || return
echo "Auto formatting"
format_ubifs || return
fi
fi
}
check_part()
{
[ "$SKIP_FSCK" -o "$PASS" -eq 0 ] && return
if [ -z "$FSCK" ]; then
echo "No fsck for $FSTYPE"
return
fi
echo "Checking $DEV($FSTYPE)"
check_tool "$FSCK" $FSCK_CONFIG || return
# Fsck needs read-only
remount_part ro
$FSCK $DEV
}
mount_part()
{
echo "Mounting $DEV($FSTYPE) on $MOUNT_POINT ${MOUNT_OPTS:+with$MOUNT_OPTS}"
$MOUNT $DEV $MOUNT_POINT $MOUNT_OPTS && return
[ "$AUTO_MKFS" ] || return
echo "Failed to mount $DEV, try to format it"
format_part && $MOUNT $DEV $MOUNT_POINT $MOUNT_OPTS
}