xref: /OK3568_Linux_fs/external/rkscript/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	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