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