#!/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 ;; squashfs) # check_tool mksquashfs BR2_PACKAGE_SQUASHFS && \ # mksquashfs $DEV echo "It's pointness to format a squashfs partition..." ;; jffs2) echo "It's pointness to format a jffs2 partition..." ;; auto) echo "Unable to format a auto partition..." ;; *) 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 }