#!/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 
 | 
} 
 |