1#!/bin/sh 2 3# Uncomment below to see more logs 4# set -x 5 6BUSYBOX_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" 7NTFS_3G_MOUNT_OPTS="ro uid=[0-9]* gid=[0-9]* umask=[0-9]* fmask=[0-9]* dmask=[0-9]*" 8 9check_tool() 10{ 11 TOOL=$(echo $1 | grep -o "^[^ ]*") 12 BR2_CONFIG=$2 13 14 type $TOOL >/dev/null && return 0 15 16 if grep -wq "ID=buildroot" /etc/os-release 2>/dev/null; then 17 [ -n "$BR2_CONFIG" ] && \ 18 echo "You may need to enable $BR2_CONFIG" 19 else 20 echo "Missing tool: $TOOL" 21 fi 22 return 1 23} 24 25device_from_attr() 26{ 27 # It's a block device 28 if [ -b "$1" ]; then 29 echo $1 30 return 31 fi 32 33 # Parse from blkid 34 blkid 2>/dev/null | grep -w "$1" | head -n 1 | \ 35 grep -o "^[^:]*" && return 36 37 # Check mtdblock name 38 for d in $(ls /dev/ | grep mtdblock); do 39 if grep -q "^$1$" /sys/block/$d/device/name; then 40 echo $d 41 return 42 fi 43 done 44 45 # Fallback to /dev/block/by-name 46 echo /dev/block/by-name/$1 47} 48 49prepare_ubi() 50{ 51 # Only support ubi for mtd device 52 if echo $DEV | grep -vq /dev/mtd; then 53 echo "$DEV is not a mtd device!" 54 return 1 55 fi 56 57 [ "$PART_NO" ] || { echo "No valid part number!" && return 1; } 58 59 if [ "$FSGROUP" = ubifs ]; then 60 DEV=/dev/ubi${PART_NO}_0 61 else 62 DEV=/dev/ubiblock${PART_NO}_0 63 fi 64 65 MTDDEV=/dev/mtd${PART_NO} 66 67 echo "Preparing $DEV from $MTDDEV" 68 69 echo "Remove ubi block device" 70 if echo $DEV | grep -q ubiblock; then 71 check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1 72 ubiblock -r /dev/ubi${PART_NO}_0 &>/dev/null 73 fi 74 75 echo "Detach ubi device" 76 check_tool ubidetach BR2_PACKAGE_MTD_UBIDETACH || return 1 77 ubidetach -p $MTDDEV &>/dev/null 78 79 echo "Attach ubi device" 80 check_tool ubiattach BR2_PACKAGE_MTD_UBIATTACH || return 1 81 ubiattach /dev/ubi_ctrl -m $PART_NO -d $PART_NO || return 1 82 83 echo "Check for valid volume" 84 if [ ! -e /dev/ubi${PART_NO}_0 ]; then 85 echo "No valid ubi volume" 86 return 1 87 fi 88 89 echo "Create ubi block device" 90 if echo $DEV | grep -q ubiblock; then 91 check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1 92 ubiblock -c /dev/ubi${PART_NO}_0 || return 1 93 fi 94 95 return 0 96} 97 98format_ubifs() 99{ 100 echo "Formatting $MTDDEV for $DEV" 101 102 echo "Remove ubi block device" 103 if echo $DEV | grep -q ubiblock; then 104 check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1 105 ubiblock -r /dev/ubi${PART_NO}_0 &>/dev/null 106 fi 107 108 echo "Detach ubi device" 109 check_tool ubidetach BR2_PACKAGE_MTD_UBIDETACH || return 1 110 ubidetach -p $MTDDEV &>/dev/null 111 112 echo "Format device" 113 check_tool ubiformat BR2_PACKAGE_MTD_UBIFORMAT || return 1 114 ubiformat -yq $MTDDEV || return 1 115 116 echo "Attach ubi device" 117 ubiattach /dev/ubi_ctrl -m $PART_NO -d $PART_NO || return 1 118 119 echo "Create ubi volume" 120 check_tool ubimkvol BR2_PACKAGE_MTD_UBIMKVOL || return 1 121 ubimkvol /dev/ubi$PART_NO -N $PART_NAME -m || return 1 122 123 echo "Create ubi block device" 124 if echo $DEV | grep -q ubiblock; then 125 check_tool ubiblock BR2_PACKAGE_MTD_UBIBLOCK || return 1 126 ubiblock -c /dev/ubi${PART_NO}_0 || return 1 127 fi 128} 129 130is_rootfs() 131{ 132 [ $MOUNT_POINT = "/" ] 133} 134 135remount_part() 136{ 137 mountpoint -q $MOUNT_POINT || return 138 139 if touch $MOUNT_POINT &>/dev/null; then 140 [ "$1" = ro ] && mount -o remount,ro $MOUNT_POINT 141 else 142 [ "$1" = rw ] && mount -o remount,rw $MOUNT_POINT 143 fi 144} 145 146format_part() 147{ 148 echo "Formatting $DEV($FSTYPE)" 149 150 case $FSGROUP in 151 ext2) 152 # Set max-mount-counts to 0, and disable the time-dependent checking. 153 check_tool mke2fs BR2_PACKAGE_E2FSPROGS && \ 154 mke2fs -F -L $PART_NAME $DEV && \ 155 tune2fs -c 0 -i 0 $DEV 156 ;; 157 vfat) 158 # Use fat32 by default 159 check_tool mkfs.vfat BR2_PACKAGE_DOSFSTOOLS_MKFS_FAT && \ 160 mkfs.vfat -I -F 32 -n $PART_NAME $DEV 161 ;; 162 ntfs) 163 # Enable compression 164 check_tool mkntfs BR2_PACKAGE_NTFS_3G_NTFSPROGS && \ 165 mkntfs -FCQ -L $PART_NAME $DEV 166 ;; 167 ubifs) 168 format_ubifs 169 ;; 170 jffs2) 171 check_tool mkfs.jffs2 BR2_PACKAGE_MTD_MKFSJFFS2 && \ 172 mkfs.jffs2 -o $DEV 0x10000 --pad=0x400000 -s 0x1000 -n 173 ;; 174 squashfs) 175 # check_tool mksquashfs BR2_PACKAGE_SQUASHFS && \ 176 # mksquashfs $DEV 177 echo "It's pointness to format a squashfs partition..." 178 false 179 ;; 180 auto) 181 echo "Unable to format a auto partition..." 182 false 183 ;; 184 *) 185 echo Unsupported file system $FSTYPE for $DEV 186 false 187 ;; 188 esac 189} 190 191format_resize() 192{ 193 BACKUP=$1 194 SRC=$(realpath $MOUNT_POINT) 195 196 echo "Format-resizing $DEV($FSTYPE)" 197 198 echo "Backup original data" 199 cp -a "$SRC" "$BACKUP/" || return 1 200 umount "$SRC" || return 1 201 202 echo "Format and mount rw" 203 format_part || return 1 204 mount_part || return 1 205 remount_part rw 206 207 echo "Restore backup data" 208 cp -a "$BACKUP/$SRC" $(dirname "$SRC") || return 1 209} 210 211resize_ext2() 212{ 213 check_tool resize2fs BR2_PACKAGE_E2FSPROGS_RESIZE2FS || return 1 214 215 resize2fs $DEV 216} 217 218resize_vfat() 219{ 220 check_tool fatresize BR2_PACKAGE_FATRESIZE || return 1 221 222 SIZE=$(fatresize -i $DEV | grep "Size:" | grep -o "[0-9]*$") 223 224 # Somehow fatresize only works for 256M+ fat 225 [ "$SIZE" -gt $((256 * 1024 * 1024)) ] && return 1 226 227 MAX_SIZE=$(( $(cat $SYS_PATH/size) * 512)) 228 MIN_SIZE=$(($MAX_SIZE - 16 * 1024 * 1024)) 229 [ $MIN_SIZE -lt $SIZE ] && return 0 # Large enough! 230 while [ $MAX_SIZE -gt $MIN_SIZE ];do 231 # Somehow fatresize cannot resize to max size 232 MAX_SIZE=$(($MAX_SIZE - 512 * 1024)) 233 234 # Try to resize with fatresize, not always work 235 fatresize -s $MAX_SIZE $DEV && return 236 done 237 return 1 238} 239 240resize_ntfs() 241{ 242 check_tool ntfsresize BR2_PACKAGE_NTFS_3G_NTFSPROGS || return 1 243 244 echo y | ntfsresize -f $DEV 245} 246 247resize_part() 248{ 249 # Fixed size or already resized 250 [ -f $MOUNT_POINT/.fixed -o -f $MOUNT_POINT/.resized ] && return 251 252 if [ -z "$FSRESIZE" ]; then 253 echo "No resize for $FSTYPE" 254 return 255 fi 256 257 echo "Resizing $DEV($FSTYPE)" 258 259 # Online resize needs read-write 260 remount_part rw 261 if eval $FSRESIZE; then 262 touch $MOUNT_POINT/.resized 263 return 264 fi 265 266 echo "Done with rootfs" 267 is_rootfs && return 268 269 echo "Fallback to format resize" 270 TEMP_BACKUP=$(mktemp -d) 271 format_resize $TEMP_BACKUP && touch $MOUNT_POINT/.resized 272 rm -rf $TEMP_BACKUP 273} 274 275convert_mount_opts() 276{ 277 # Accept all opts by default for standard mount tool 278 if [ -z "$@" ] && [ "$(readlink $(which mount))" != busybox ]; then 279 echo $OPTS 280 return 281 fi 282 283 # Filter out unsupported opts 284 for opt in ${@:-$BUSYBOX_MOUNT_OPTS}; do 285 echo ${OPTS//,/ } | xargs -n 1 | grep -oE "^$opt$" 286 done | tr "\n" "," 287} 288 289prepare_part() 290{ 291 # Ignore external storages 292 echo $MOUNT_POINT | grep -q "^\/mnt\/" && return 1 293 294 # Find real dev for root dev 295 if is_rootfs; then 296 DEV=/dev/block/$(mountpoint -d /) 297 fi 298 299 DEV=$(realpath $DEV 2>/dev/null) 300 PART_NO=$(echo $DEV | grep -oE "[0-9]*$") 301 302 # Only accept block device 303 [ -b "$DEV" ] || return 1 304 305 SYS_PATH=$(echo /sys/class/*/${DEV##*/}) 306 if [ -f "$SYS_PATH/name" ]; then 307 PART_NAME=$(cat $SYS_PATH/name) 308 else 309 PART_NAME=$(grep PARTNAME ${SYS_PATH}/uevent | cut -d '=' -f 2) 310 fi 311 PART_NAME=${PART_NAME:-${DEV##*/}} 312 313 case $FSTYPE in 314 ext[234]) 315 FSGROUP=ext2 316 FSCK="fsck.$FSTYPE -y" 317 FSCK_CONFIG=BR2_PACKAGE_E2FSPROGS_FSCK 318 FSRESIZE=resize_ext2 319 ;; 320 msdos|fat|vfat) 321 FSGROUP=vfat 322 FSCK="fsck.vfat -y" 323 FSCK_CONFIG=BR2_PACKAGE_DOSFSTOOLS_FSCK_FAT 324 FSRESIZE=resize_vfat 325 ;; 326 ntfs) 327 FSGROUP=ntfs 328 FSCK=ntfsfix 329 FSCK_CONFIG=BR2_PACKAGE_NTFS_3G_NTFSPROGS 330 FSRESIZE=resize_ntfs 331 ;; 332 ubi|ubifs) 333 FSTYPE=ubifs 334 FSGROUP=ubifs 335 unset FSCK 336 unset FSRESIZE 337 ;; 338 squashfs) 339 FSGROUP=squashfs 340 unset FSCK 341 unset FSRESIZE 342 ;; 343 jffs2) 344 FSGROUP=jffs2 345 unset FSCK 346 unset FSRESIZE 347 ;; 348 auto) 349 FSGROUP=auto 350 echo "Running fsck on a random fs is dangerous" 351 unset FSCK 352 unset FSRESIZE 353 ;; 354 *) 355 echo "Unsupported file system $FSTYPE for $DEV" 356 return 357 esac 358 359 # Setup mount tool and opts 360 case $FSGROUP in 361 ntfs) 362 MOUNT=ntfs-3g 363 check_tool ntfs-3g BR2_PACKAGE_NTFS_3G || return 1 364 OPTS=$(convert_mount_opts "$NTFS_3G_MOUNT_OPTS") 365 ;; 366 auto) 367 MOUNT=mount 368 OPTS=$(convert_mount_opts) 369 ;; 370 *) 371 MOUNT="mount -t $FSTYPE" 372 OPTS=$(convert_mount_opts) 373 ;; 374 esac 375 MOUNT_OPTS=${OPTS:+" -o ${OPTS%,}"} 376 377 # Prepare for UBI 378 if [ "$FSGROUP" = ubifs ]; then 379 if ! prepare_ubi; then 380 echo "Failed to prepare ubi for $DEV" 381 [ "$AUTO_MKFS" ] || return 382 383 echo "Auto formatting" 384 format_ubifs || return 385 fi 386 fi 387} 388 389check_part() 390{ 391 [ "$SKIP_FSCK" -o "$PASS" -eq 0 ] && return 392 393 if [ -z "$FSCK" ]; then 394 echo "No fsck for $FSTYPE" 395 return 396 fi 397 398 echo "Checking $DEV($FSTYPE)" 399 400 check_tool "$FSCK" $FSCK_CONFIG || return 401 402 # Fsck needs read-only 403 remount_part ro 404 405 $FSCK $DEV 406} 407 408mount_part() 409{ 410 echo "Mounting $DEV($FSTYPE) on $MOUNT_POINT ${MOUNT_OPTS:+with$MOUNT_OPTS}" 411 $MOUNT $DEV $MOUNT_POINT $MOUNT_OPTS && return 412 [ "$AUTO_MKFS" ] || return 413 414 echo "Failed to mount $DEV, try to format it" 415 format_part && $MOUNT $DEV $MOUNT_POINT $MOUNT_OPTS 416} 417