547 lines
11 KiB
Bash
Executable File
547 lines
11 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]*"
|
|
|
|
message()
|
|
{
|
|
echo "${ID:+"[$ID]: "}$@"
|
|
}
|
|
|
|
check_tool()
|
|
{
|
|
TOOL=${1%% *}
|
|
BR2_CONFIG=$2
|
|
|
|
type $TOOL >/dev/null && return 0
|
|
|
|
if grep -wq "ID=buildroot" /etc/os-release 2>/dev/null; then
|
|
[ -n "$BR2_CONFIG" ] && \
|
|
message "You may need to enable $BR2_CONFIG"
|
|
else
|
|
message "Missing tool: $TOOL"
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
is_rootfs()
|
|
{
|
|
[ $MOUNT_POINT = "/" ]
|
|
}
|
|
|
|
is_ro()
|
|
{
|
|
mountpoint -q $MOUNT_POINT || return 1
|
|
touch $MOUNT_POINT 2>/dev/null || return 0
|
|
return 1
|
|
}
|
|
|
|
normalize_device()
|
|
{
|
|
if is_rootfs; then
|
|
DEV_NO="$(mountpoint -d /)"
|
|
ROOT_DEV="$(find /sys/dev/ -name "$DEV_NO" | tail -n 1)"
|
|
echo "/dev/$(basename "$(realpath "$ROOT_DEV")")"
|
|
return
|
|
fi
|
|
|
|
case "$DEV" in
|
|
""|tmpfs|proc|devtmpfs|devpts|sysfs|configfs|debugfs|pstore)
|
|
return
|
|
;;
|
|
/dev/*)
|
|
echo $DEV
|
|
return
|
|
;;
|
|
esac
|
|
|
|
# Try udev rules symlink
|
|
if find /dev/block/by-name/$DEV 2>/dev/null; then
|
|
return
|
|
fi
|
|
if find /dev/disk/*/$DEV 2>/dev/null; then
|
|
return
|
|
fi
|
|
|
|
# Check partition name
|
|
UEVENT=$(grep -l "^PARTNAME=$DEV$" \
|
|
/sys/class/block/*/uevent 2>/dev/null | tail -n 1 || true)
|
|
if [ "$UEVENT" ]; then
|
|
echo "/dev/$(basename $(dirname $UEVENT))"
|
|
return
|
|
fi
|
|
|
|
# Check mtdblock name
|
|
for d in $(ls /dev/ | grep mtdblock || true); do
|
|
if grep -q "^$DEV$" /sys/block/$d/device/name; then
|
|
echo "/dev/$d"
|
|
return
|
|
fi
|
|
done
|
|
|
|
# Check mtd
|
|
if grep -q "\"$DEV\"$" /proc/mtd 2>/dev/null; then
|
|
echo "/dev/$(grep "\"$DEV\"$" /proc/mtd | cut -d':' -f1)"
|
|
return
|
|
fi
|
|
|
|
# Parse from blkid
|
|
if blkid 2>/dev/null | grep -w "$DEV" | tail -n 1 | \
|
|
grep -o "^[^:]*"; then
|
|
return
|
|
fi
|
|
|
|
# Give up
|
|
echo $DEV
|
|
}
|
|
|
|
prepare_ubi()
|
|
{
|
|
# Only support ubi for mtd device
|
|
if echo $DEV | grep -vq /dev/mtd; then
|
|
message "$DEV is not a mtd device!"
|
|
return 1
|
|
fi
|
|
|
|
[ "$PART_NO" ] || { message "No valid part number!" && return 1; }
|
|
|
|
MTD_DEV=/dev/mtd${PART_NO}
|
|
UBI_DEV=/dev/ubi${PART_NO}
|
|
UBIVOL_DEV=/dev/ubi${PART_NO}_0
|
|
UBIBLOCK_DEV=/dev/ubiblock${PART_NO}_0
|
|
|
|
if [ "$FSGROUP" = ubifs ]; then
|
|
DEV=$UBIVOL_DEV
|
|
else
|
|
DEV=$UBIBLOCK_DEV
|
|
fi
|
|
|
|
message "Preparing $DEV from $MTD_DEV"
|
|
|
|
message "Remove ubi block device"
|
|
if echo $DEV | grep -q ubiblock; then
|
|
check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1
|
|
ubiblock -r $UBIVOL_DEV >/dev/null 2>/dev/null
|
|
fi
|
|
|
|
message "Detach ubi device"
|
|
check_tool ubidetach BR2_PACKAGE_MTD_UBIDETACH || return 1
|
|
ubidetach -p $MTD_DEV >/dev/null 2>/dev/null
|
|
|
|
message "Attach ubi device"
|
|
check_tool ubiattach BR2_PACKAGE_MTD_UBIATTACH || return 1
|
|
ubiattach /dev/ubi_ctrl -m $PART_NO -d $PART_NO || return 1
|
|
|
|
message "Check for valid volume"
|
|
if [ ! -e $UBIVOL_DEV ]; then
|
|
message "No valid ubi volume"
|
|
return 1
|
|
fi
|
|
|
|
message "Create ubi block device"
|
|
if echo $DEV | grep -q ubiblock; then
|
|
check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1
|
|
ubiblock -c $UBIVOL_DEV || return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
format_ubifs()
|
|
{
|
|
message "Formatting $MTD_DEV for $DEV"
|
|
|
|
message "Remove ubi block device"
|
|
if echo $DEV | grep -q ubiblock; then
|
|
check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1
|
|
ubiblock -r $UBIVOL_DEV >/dev/null 2>/dev/null
|
|
fi
|
|
|
|
message "Detach ubi device"
|
|
check_tool ubidetach BR2_PACKAGE_MTD_UBIDETACH || return 1
|
|
ubidetach -p $MTD_DEV >/dev/null 2>/dev/null
|
|
|
|
message "Format device"
|
|
check_tool ubiformat BR2_PACKAGE_MTD_UBIFORMAT || return 1
|
|
ubiformat -yq $MTD_DEV || return 1
|
|
|
|
message "Attach ubi device"
|
|
ubiattach /dev/ubi_ctrl -m $PART_NO -d $PART_NO || return 1
|
|
|
|
message "Create ubi volume"
|
|
check_tool ubimkvol BR2_PACKAGE_MTD_UBIMKVOL || return 1
|
|
ubimkvol $UBI_DEV -N $PART_NAME -m || return 1
|
|
|
|
message "Create ubi block device"
|
|
if echo $DEV | grep -q ubiblock; then
|
|
check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1
|
|
ubiblock -c $UBIVOL_DEV || return 1
|
|
fi
|
|
}
|
|
|
|
remount_part()
|
|
{
|
|
mountpoint -q $MOUNT_POINT || return
|
|
|
|
if is_ro; then
|
|
[ "$1" != ro ] || return
|
|
else
|
|
[ "$1" != rw ] || return
|
|
fi
|
|
|
|
mount -o remount,$1 $MOUNT_POINT
|
|
}
|
|
|
|
format_part()
|
|
{
|
|
message "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 -b 4096 -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
|
|
;;
|
|
exfat)
|
|
check_tool mkexfatfs BR2_PACKAGE_EXFAT_UTILS && \
|
|
mkexfatfs -n $PART_NAME $DEV
|
|
;;
|
|
ntfs)
|
|
# Enable compression
|
|
check_tool mkntfs BR2_PACKAGE_NTFS_3G_NTFSPROGS && \
|
|
mkntfs -FCQ -L $PART_NAME $DEV
|
|
;;
|
|
btrfs)
|
|
check_tool mkfs.btrfs BR2_PACKAGE_BTRFS_PROGS && \
|
|
mkfs.btrfs -f -L $PART_NAME $DEV
|
|
;;
|
|
f2fs)
|
|
check_tool mkfs.f2fs BR2_PACKAGE_F2FS_TOOLS && \
|
|
mkfs.f2fs -f -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
|
|
;;
|
|
erofs|squashfs)
|
|
message "It's pointness to format a read-only partition..."
|
|
false
|
|
;;
|
|
auto)
|
|
message "Unable to format a auto partition..."
|
|
false
|
|
;;
|
|
*)
|
|
message "Unsupported file system $FSTYPE for $DEV"
|
|
false
|
|
;;
|
|
esac
|
|
}
|
|
|
|
format_resize()
|
|
{
|
|
BACKUP=$1
|
|
SRC=$(realpath $MOUNT_POINT)
|
|
|
|
message "Format-resizing $DEV($FSTYPE)"
|
|
|
|
message "Backup original data"
|
|
cp -a "$SRC" "$BACKUP/" || return 1
|
|
umount "$SRC" || return 1
|
|
|
|
message "Format and mount rw"
|
|
format_part || return 1
|
|
mount_part || return 1
|
|
remount_part rw
|
|
|
|
message "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_btrfs()
|
|
{
|
|
check_tool btrfs BR2_PACKAGE_BTRFS_PROGS || return 1
|
|
|
|
btrfs filesystem resize max $DEV
|
|
}
|
|
|
|
resize_f2fs()
|
|
{
|
|
check_tool resize.f2fs BR2_PACKAGE_F2FS_TOOLS || return 1
|
|
|
|
resize.f2fs $DEV
|
|
}
|
|
|
|
resize_part()
|
|
{
|
|
# Already resized
|
|
if [ -f $MOUNT_POINT/.resized ]; then
|
|
message "Already resized $DEV($FSTYPE)"
|
|
return
|
|
fi
|
|
|
|
if [ -z "$FSRESIZE" ]; then
|
|
message "No resize for $FSTYPE"
|
|
return
|
|
fi
|
|
|
|
message "Resizing $DEV($FSTYPE)"
|
|
|
|
# Online resize needs read-write
|
|
remount_part rw
|
|
if eval $FSRESIZE; then
|
|
touch $MOUNT_POINT/.resized
|
|
sync
|
|
return
|
|
fi
|
|
|
|
message "Done with rootfs"
|
|
is_rootfs && return
|
|
|
|
message "Fallback to format resize"
|
|
TEMP_BACKUP=$(mktemp -d)
|
|
if format_resize $TEMP_BACKUP; then
|
|
touch $MOUNT_POINT/.resized
|
|
sync
|
|
fi
|
|
rm -rf $TEMP_BACKUP
|
|
}
|
|
|
|
convert_mount_opts()
|
|
{
|
|
# Accept all opts by default for standard mount tool
|
|
if [ -z "$@" ] && ! mount --help 2>&1 | grep -q 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
|
|
|
|
DEV="$(realpath "$(normalize_device | head -n 1)" 2>/dev/null)"
|
|
[ "$DEV" ] || return 1
|
|
|
|
# Only accept block or char device
|
|
[ -b "$DEV" -o -c "$DEV" ] || return 1
|
|
|
|
message "Handling $DEV $MOUNT_POINT $FSTYPE $OPTS $PASS"
|
|
|
|
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##*/}}
|
|
PART_NO=$(echo $DEV | grep -oE "[0-9]*$")
|
|
|
|
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
|
|
;;
|
|
exfat)
|
|
FSGROUP=exfat
|
|
FSCK="exfatfsck -y"
|
|
FSCK_CONFIG=BR2_PACKAGE_EXFAT_UTILS
|
|
unset FSRESIZE
|
|
;;
|
|
ntfs)
|
|
FSGROUP=ntfs
|
|
FSCK=ntfsfix
|
|
FSCK_CONFIG=BR2_PACKAGE_NTFS_3G_NTFSPROGS
|
|
FSRESIZE=resize_ntfs
|
|
;;
|
|
btrfs)
|
|
FSGROUP=btrfs
|
|
FSCK="btrfs check --repair"
|
|
FSCK_CONFIG=BR2_PACKAGE_BTRFS_PROGS
|
|
FSRESIZE=resize_btrfs
|
|
;;
|
|
f2fs)
|
|
FSGROUP=f2fs
|
|
FSCK="fsck.f2fs -y"
|
|
FSCK_CONFIG=BR2_PACKAGE_F2FS_TOOLS
|
|
FSRESIZE=resize_f2fs
|
|
;;
|
|
ubifs)
|
|
FSGROUP=ubifs
|
|
unset FSCK
|
|
unset FSRESIZE
|
|
;;
|
|
squashfs)
|
|
FSGROUP=squashfs
|
|
unset FSCK
|
|
unset FSRESIZE
|
|
;;
|
|
erofs)
|
|
FSGROUP=erofs
|
|
unset FSCK
|
|
unset FSRESIZE
|
|
;;
|
|
jffs2)
|
|
FSGROUP=jffs2
|
|
unset FSCK
|
|
unset FSRESIZE
|
|
;;
|
|
auto)
|
|
FSGROUP=auto
|
|
message "Running fsck on a random fs is dangerous"
|
|
unset FSCK
|
|
unset FSRESIZE
|
|
;;
|
|
*)
|
|
message "Unsupported file system $FSTYPE for $DEV"
|
|
return 1
|
|
esac
|
|
|
|
# Setup mount tool and opts
|
|
case $FSGROUP in
|
|
ntfs)
|
|
if grep -wq ntfs3 /proc/filesystems; then
|
|
MOUNT="mount -t ntfs3"
|
|
OPTS=$(convert_mount_opts)
|
|
else
|
|
MOUNT=ntfs-3g
|
|
check_tool ntfs-3g BR2_PACKAGE_NTFS_3G || return 1
|
|
OPTS=$(convert_mount_opts "$NTFS_3G_MOUNT_OPTS")
|
|
fi
|
|
;;
|
|
auto)
|
|
MOUNT=mount
|
|
OPTS=$(convert_mount_opts)
|
|
;;
|
|
*)
|
|
MOUNT="mount -t $FSTYPE"
|
|
OPTS=$(convert_mount_opts)
|
|
;;
|
|
esac
|
|
MOUNT_OPTS=${OPTS:+" -o ${OPTS%,}"}
|
|
|
|
# Detect ro/rw
|
|
MOUNT_RO_RW=$(echo "$OPTS" | tr ',' ' ' | xargs -n 1 | \
|
|
grep -o "^r[ow]$" || true)
|
|
if [ -z "$MOUNT_RO_RW" ]; then
|
|
if is_rootfs && is_ro; then
|
|
MOUNT_RO_RW=ro
|
|
else
|
|
MOUNT_RO_RW=rw
|
|
fi
|
|
fi
|
|
|
|
# Prepare for ubi
|
|
if [ "$FSTYPE" = ubifs ] ||
|
|
[ "$(dd if=$DEV bs=1 count=3 status=none)" = UBI ]; then
|
|
if ! prepare_ubi; then
|
|
message "Failed to prepare ubi for $DEV"
|
|
|
|
if [ "$AUTO_MKFS" ] && [ "$FSGROUP" = ubifs ]; then
|
|
message "Auto formatting"
|
|
format_ubifs || true
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_part()
|
|
{
|
|
[ "$SKIP_FSCK" -o "$PASS" -eq 0 ] && return
|
|
|
|
if [ -z "$FSCK" ]; then
|
|
message "No fsck for $FSTYPE"
|
|
return
|
|
fi
|
|
|
|
message "Checking $DEV($FSTYPE)"
|
|
|
|
if is_rootfs; then
|
|
# Remount ro for checking
|
|
remount_part ro
|
|
elif mountpoint -q "$MOUNT_POINT"; then
|
|
# Unmount for checking
|
|
umount "$MOUNT_POINT" || remount_part ro
|
|
fi
|
|
|
|
check_tool "$FSCK" $FSCK_CONFIG || return
|
|
|
|
$FSCK $DEV
|
|
}
|
|
|
|
mount_part()
|
|
{
|
|
mountpoint -q "$MOUNT_POINT" && return
|
|
|
|
message "Mounting $DEV($FSTYPE) on $MOUNT_POINT ${MOUNT_OPTS:+with$MOUNT_OPTS}"
|
|
$MOUNT $DEV $MOUNT_POINT $MOUNT_OPTS && return
|
|
[ "$AUTO_MKFS" ] || return
|
|
|
|
message "Failed to mount $DEV, try to format it"
|
|
format_part && $MOUNT $DEV $MOUNT_POINT $MOUNT_OPTS
|
|
}
|