#!/bin/sh
|
|
# Uncomment below to see more logs
|
# set -x
|
|
MISC_DEV=$(realpath /dev/block/by-name/misc 2>/dev/null)
|
|
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
|
}
|
|
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
|
}
|
|
erase_oem_command()
|
{
|
CMD=$1
|
FILE=$2
|
|
echo "OEM: Erasing $CMD in $FILE"
|
|
COUNT=$(echo $CMD | wc -c)
|
OFFSETS=$(strings -t d $FILE | grep -w "$CMD" | awk '{ print $1 }')
|
|
for offset in $OFFSETS; do
|
dd if=/dev/zero of=$FILE bs=1 count=$COUNT seek=$offset conv=notrunc 2>/dev/null
|
done
|
}
|
|
done_oem_command()
|
{
|
CMD=$1
|
|
echo "OEM: Done with $CMD"
|
|
if [ -b "$MISC_DEV" ]; then
|
erase_oem_command $CMD $MISC_DEV
|
else
|
echo "OEM: Erase $CMD from mtd device"
|
|
check_tool nanddump BR2_PACKAGE_MTD_NANDDUMP || return
|
check_tool nandwrite BR2_PACKAGE_MTD_NANDWRITE || return
|
check_tool flash_erase BR2_PACKAGE_MTD_FLASH_ERASE || return
|
|
TEMP=$(mktemp)
|
nanddump $MISC_DEV -f $TEMP
|
erase_oem_command $CMD $TEMP
|
flash_erase $MISC_DEV 0 0
|
nandwrite $MISC_DEV $TEMP
|
fi
|
}
|
|
handle_oem_command()
|
{
|
[ "$OEM_CMD" ] || return
|
|
for cmd in $OEM_CMD; do
|
case $cmd in
|
cmd_wipe_$PART_NAME)
|
is_rootfs && continue
|
|
echo "OEM: $cmd - Wiping $DEV"
|
format_part && done_oem_command $cmd
|
;;
|
esac
|
done
|
}
|
|
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
|
echo $MOUNT_POINT | grep -q "^\/mnt\/" && return 1
|
|
# Find real dev for root dev
|
if is_rootfs; then
|
DEV=$(findmnt -n -o source /)
|
|
# Fallback to the by-name link
|
[ "$DEV" ] || DEV=/dev/block/by-name/rootfs
|
fi
|
|
DEV=$(realpath $DEV 2>/dev/null)
|
PART_NO=$(echo $DEV | grep -oE "[0-9]*$")
|
|
# Unknown device
|
[ -b "$DEV" -o -c "$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)
|
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")
|
;;
|
ubifs)
|
MOUNT="mount -t ubifs"
|
OPTS=$(convert_mount_opts)
|
;;
|
*)
|
MOUNT=mount
|
OPTS=$(convert_mount_opts)
|
;;
|
esac
|
MOUNT_OPTS=${OPTS:+" -o ${OPTS%,}"}
|
|
# Prepare for ubi (consider /dev/mtdX as ubiblock)
|
if [ "$FSGROUP" = ubifs ] || echo $DEV | grep -q "/dev/mtd[0-9]";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
|
}
|