xref: /OK3568_Linux_fs/debian/overlay/usr/bin/disk-helper (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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