hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
#!/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
}