xref: /OK3568_Linux_fs/device/rockchip/common/scripts/partition-helper (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1#!/bin/bash
2
3# Make sure that we are sourced and called inside of RK build scripts.
4if [ "$BASH_SOURCE" = "$0" -o -z "$RK_SESSION" ];then
5	echo "$(realpath $0) is not supposed to be executed directly"
6	exit 1
7fi
8
9# Parsed partition table file
10PART_TABLE="$RK_LOG_DIR/part-table"
11
12# Hidden header partition (part-table and idblock)
13HDR_PART="<hidden>"
14
15rk_partition_size_sector_to_readable()
16{
17	# Consider 0 as unlimited
18	case "${1:-grow}" in
19		- | 0 | grow)
20			echo grow
21			return 0 ;;
22	esac
23
24	SIZE=$(( $1 * 512 ))
25	if [ "$SIZE" -lt 1024 ]; then
26		echo $SIZE
27	elif [ "$SIZE" -ge $(( 1024 * 1024 * 1024 )) ]; then
28		echo "$(echo "scale=1; $SIZE / 1024 / 1024 / 1024" | bc | \
29			sed 's/\.0$//')G"
30	elif [ "$SIZE" -ge $(( 1024 * 1024 )) ]; then
31		echo "$(echo "scale=1; $SIZE / 1024 / 1024" | bc | \
32			sed 's/\.0$//')M"
33	else
34		echo "$(echo "scale=1; $SIZE / 1024" | bc | \
35			sed 's/\.0$//')K"
36	fi
37}
38
39rk_partition_size_readable_to_sector()
40{
41	SIZE=${1%B}
42
43	case "${SIZE:-grow}" in
44		# Consider 0 as unlimited
45		- | 0 | grow)
46			echo '-'
47			return 0
48			;;
49		0x*)
50			echo $SIZE
51			return 0
52			;;
53	esac
54
55	{
56		case "$SIZE" in
57			*K) echo "${SIZE%K} * 2" | bc ;;
58			*M) echo "${SIZE%M} * 2 * 1024" | bc ;;
59			*G) echo "${SIZE%G} * 2 * 1024 * 1024" | bc ;;
60			*) echo "$SIZE / 512" | bc ;;
61		esac
62	} | cut -d'.' -f1 | awk '{printf "0x%08x",$1}'
63}
64
65# Parse parameter to "<name> <size>" pairs
66rk_partition_parse()
67{
68	PARAMETER="${1:-$CHIP_DIR/$RK_PARAMETER}"
69
70	if [ ! -r "$PARAMETER" ]; then
71		echo -e "\e[36m$PARAMETER not exists!\e[0m" >&2
72		exit 1
73	fi
74
75	PARTS="$(grep "^CMDLINE:" "$PARAMETER" | grep -o "0x.*")"
76
77	# NOTE: Assuming partitions are contiguous
78	echo "$HDR_PART $(echo $PARTS | awk -F '[@():]' '{print $2}')"
79	echo "${PARTS//,/ }" | xargs -n 1 | \
80		awk -F '[@():]' '{print $3,$1}'
81}
82
83# Parse parameter to "<name>" arrays
84rk_partition_parse_names()
85{
86	rk_partition_parse "$1" | grep -v "^$HDR_PART " | cut -d' ' -f1 | xargs
87}
88
89# Cache parsed partition table
90rk_partition_init()
91{
92	rk_partition_parse > "$PART_TABLE"
93}
94
95rk_partition_size()
96{
97	grep "^$1 " "$PART_TABLE" | cut -d' ' -f2 | tr -d '\-' || true
98}
99
100rk_partition_num()
101{
102	echo $(( $(cat "$PART_TABLE" | wc -l) - 1 ))
103}
104
105# Print partition table info
106rk_partition_print()
107{
108	echo
109	echo "=========================================="
110	echo "          Partition table"
111	echo "=========================================="
112	{
113		OFFSET=0
114		while read NAME SIZE; do
115			OFFSET=$(echo $OFFSET | awk '{printf "0x%08x",$1}')
116			SIZE_STR=$(rk_partition_size_sector_to_readable $SIZE)
117
118			if [ "$NAME" != "$HDR_PART" ]; then
119				NAME=$(echo $NAME | awk '{printf "%12s",$1}')
120				echo -e "$NAME at $OFFSET size=$SIZE($SIZE_STR)"
121			fi
122
123			# NOTE: Assuming partitions are contiguous
124			OFFSET=$(( $OFFSET + ${SIZE/-/0} ))
125		done < "$PART_TABLE"
126	} | sed "=" | sed "N;s/\n/: /"
127
128	echo
129	echo "Legacy cmdline:"
130	rk_partition_to_cmdline
131	echo
132}
133
134# Convert partition table to Rockchip legacy cmdline format
135rk_partition_to_cmdline()
136{
137	OFFSET=0
138	while read NAME SIZE; do
139		case "$SIZE" in
140			-)
141				# Latest grow part
142				echo "$NAME $OFFSET" | \
143					awk '{printf "-@0x%08x(%s:grow)",$2,$1}'
144				break ;;
145			*) SIZE=$(rk_partition_size_readable_to_sector $SIZE) ;;
146		esac
147
148		# Visible parts
149		if [ "$NAME" != "$HDR_PART" ]; then
150			echo "$NAME $OFFSET $(( $SIZE ))" | \
151				awk '{printf "0x%08x@0x%08x(%s)",$3,$2,$1}'
152		fi
153
154		# NOTE: Assuming partitions are contiguous
155		OFFSET=$(( $OFFSET + $SIZE ))
156	done < "$PART_TABLE" | sed 's/)\([^$]\)/),\1/g'
157}
158
159# Save partition table to parameter
160rk_partition_save()
161{
162	PARAMETER="${1:-$CHIP_DIR/$RK_PARAMETER}"
163	[ -r "$PARAMETER" ] || return 1
164
165	PARTS=$(rk_partition_to_cmdline)
166	[ "$PARTS" ] || return 1
167
168	sed -i "/^CMDLINE:/s/0x.*/$PARTS/" "$PARAMETER"
169
170	# Reflush
171	rk_partition_init
172}
173
174# Edit raw partition table
175rk_partition_edit()
176{
177	sed -i '1i # name size' "$PART_TABLE"
178	eval ${EDITOR:-vi} "$PART_TABLE"
179	sed -i '/#/d' "$PART_TABLE"
180	rk_partition_save
181}
182
183rk_partition_parse_name()
184{
185	unset PART_NAME
186
187	[ "$#" -eq 1 ] || return 1
188
189	# Part name
190	if ! echo $1 | grep -qE "^[0-9]*$"; then
191		if ! grep -q "^$1 " "$PART_TABLE"; then
192			echo -e "\e[35mNo such part ($1)!\e[0m"
193			return 1
194		fi
195
196		PART_NAME=$1
197		return 0
198	fi
199
200	# Part idx
201	IDX=$1
202	if [ "$IDX" -lt 1 ]; then
203		echo -e "\e[35mIndex should not be less than 1!\e[0m"
204		return 1
205	fi
206
207	NUM=$(rk_partition_num)
208	if [ "$IDX" -gt "$NUM" ]; then
209		echo -e "\e[35mIndex should not be greater than $NUM!\e[0m"
210		return 1
211	fi
212
213	PART_NAME=$(sed -n "$(($IDX + 1))s/\(^[^ ]*\) .*/\1/p" "$PART_TABLE")
214}
215
216rk_partition_del()
217{
218	[ "$#" -gt 0 ] || return 1
219
220	rk_partition_parse_name $1 || return 1
221	sed -i "/^$PART_NAME /d" "$PART_TABLE"
222
223	rk_partition_save
224}
225
226rk_partition_rename()
227{
228	[ "$#" -gt 1 ] || return 1
229
230	echo $2 | grep -qE "^[a-zA-Z]" || return 1
231	if rk_partition_parse_name $2 >/dev/null; then
232		echo -e "\e[35mPart already exists ($2)!\e[0m"
233		return 1
234	fi
235
236	rk_partition_parse_name $1 || return 1
237	sed -i "s/^$PART_NAME /$2 /" "$PART_TABLE"
238
239	rk_partition_save
240}
241
242rk_partition_move()
243{
244	[ "$#" -gt 1 ] || return 1
245
246	echo $2 | grep -qE "^[0-9]*$" || return 1
247	rk_partition_parse_name $2 || return 1
248
249	rk_partition_parse_name $1 || return 1
250	PART=$(sed -n "/^$PART_NAME /p" "$PART_TABLE")
251
252	NUM=$(rk_partition_num)
253	if [ "$2" -eq "$NUM" ] && grep -q "\-$" "$PART_TABLE"; then
254		echo -e "\e[35mCannot move after unlimited part!\e[0m"
255		return 1
256	fi
257
258	if echo "$PART" | grep -q "\-$"; then
259		echo -e "\e[35mCannot move unlimited part ($1)!\e[0m"
260		return 1
261	fi
262
263	sed -i "/^$PART$/d" "$PART_TABLE"
264	sed -i "$2 a$PART" "$PART_TABLE"
265
266	rk_partition_save
267}
268
269rk_partition_resize()
270{
271	[ "$#" -gt 1 ] || return 1
272
273	case "$2" in
274		0x*) SIZE=$2 ;;
275		*) SIZE="$(rk_partition_size_readable_to_sector $2)" ;;
276	esac
277
278	rk_partition_parse_name $1 || return 1
279	sed -i "s/^$PART_NAME .*/$PART_NAME $SIZE/" "$PART_TABLE"
280
281	rk_partition_save
282}
283
284rk_partition_insert()
285{
286	[ "$#" -gt 1 ] || return 1
287
288	echo $1 | grep -qE "^[0-9]*$" || return 1
289
290	IDX=$1
291	if [ "$IDX" -lt 1 ]; then
292		echo -e "\e[35mIndex should not be less than 1!\e[0m"
293		return 1
294	fi
295
296	NUM=$(rk_partition_num)
297	if [ "$IDX" -gt "$(($NUM + 1))" ]; then
298		echo -e "\e[35mIndex should not be greater than $(($NUM + 1))!\e[0m"
299		return 1
300	fi
301
302	echo $2 | grep -qE "^[a-zA-Z]" || return 1
303	if rk_partition_parse_name $2 >/dev/null; then
304		echo -e "\e[35mPart already exists ($2)!\e[0m"
305		return 1
306	fi
307
308	case "${3:-grow}" in
309		0x*) SIZE=$3 ;;
310		*) SIZE="$(rk_partition_size_readable_to_sector $3)" ;;
311	esac
312
313	if [ "$SIZE" = "-" ] && [ "$IDX" -lt "$(( $NUM + 1 ))" ]; then
314		echo -e "\e[35mOnly latest part can be unlimited!\e[0m"
315		return 1
316	fi
317
318	if [ "$IDX" -eq "$(( $NUM + 1 ))" ] && grep -q "\-$" "$PART_TABLE"; then
319		echo -e "\e[35mCannot insert after unlimited part!\e[0m"
320		return 1
321	fi
322
323	sed -i "$IDX a$2 $SIZE" "$PART_TABLE"
324
325	rk_partition_save
326}
327
328# Usage: <offset> <name> <size> <name> <size>...
329rk_partition_create()
330{
331	[ "$#" -gt 1 ] || return 1
332
333	{
334		echo "$HDR_PART $(echo $(( $1 )) | awk '{printf "0x%08x",$1}')"
335		shift
336
337		while [ "$1" ]; do
338			NAME=$1
339			shift
340
341			SIZE="$(rk_partition_size_readable_to_sector $1)"
342			[ -z "$1" ] || shift
343
344			if [ "$1" -a "$SIZE" = "-" ]; then
345				echo -e "\e[35mOnly latest part can be unlimited!\e[0m"
346				break
347			fi
348
349			echo "$NAME $SIZE"
350		done
351	} > "$PART_TABLE"
352
353	rk_partition_save
354}
355
356# -------- extra partition helpers -------- #
357
358rk_extra_part_num()
359{
360	echo ${RK_EXTRA_PARTITION_NUM:-0}
361}
362
363rk_extra_part_cfg()
364{
365	[ "$RK_EXTRA_PARTITION_STR" ] || return 0
366
367	RK_EXTRA_PARTITION_ARRAY=( $(echo ${RK_EXTRA_PARTITION_STR//@/ } | \
368		xargs -n 1 | sort) )
369	PART_IDX=$(( ${1:-1} - 1 ))
370	echo "${RK_EXTRA_PARTITION_ARRAY[$PART_IDX]}"
371}
372
373rk_extra_part_arg()
374{
375	PART="$(rk_extra_part_cfg ${1:-1})"
376	ARG="$(echo "$PART" | cut -d':' -f${2:-1})"
377	echo "${ARG:-$3}"
378}
379
380rk_extra_part_dev()
381{
382	rk_extra_part_arg ${1:-1} 1
383}
384
385rk_extra_part_name()
386{
387	rk_extra_part_arg ${1:-1} 2
388}
389
390rk_extra_part_mountpoint()
391{
392	rk_extra_part_arg ${1:-1} 3 "/$(rk_extra_part_name $1)"
393}
394
395rk_extra_part_fstype()
396{
397	rk_extra_part_arg ${1:-1} 4 ext4
398}
399
400rk_extra_part_options()
401{
402	rk_extra_part_arg ${1:-1} 5 defaults
403}
404
405rk_extra_part_src()
406{
407	PART_NAME="$(rk_extra_part_name $1)"
408	for src in $(rk_extra_part_arg ${1:-1} 6 | tr ',' ' '); do
409		# Src is either relative path to $RK_IMAGE_DIR/<name>/, or \
410		# absolute path.
411		if echo "$src" | grep -vq "^/"; then
412			echo "$RK_IMAGE_DIR/$PART_NAME/${PART_NAME}_${src}"
413		else
414			echo "$src"
415		fi
416	done
417}
418
419rk_extra_part_size()
420{
421	rk_extra_part_arg ${1:-1} 7 auto
422}
423
424rk_extra_part_fixed()
425{
426	rk_extra_part_arg ${1:-1} 8 | grep -wq fixed
427}
428
429rk_extra_part_builtin()
430{
431	rk_extra_part_arg ${1:-1} 8 | grep -wq builtin
432}
433
434# Symlink to the mountpoint in rootfs dir
435rk_extra_part_mount_dir()
436{
437	echo "$RK_OUTDIR/$(rk_extra_part_name $1)-mount"
438}
439
440rk_extra_part_outdir()
441{
442	echo "$RK_OUTDIR/$(rk_extra_part_name $1)"
443}
444
445rk_extra_part_fakeroot_script()
446{
447	echo "$(rk_extra_part_outdir $1).fs"
448}
449
450rk_extra_part_img()
451{
452	echo "$RK_FIRMWARE_DIR/$(rk_extra_part_name $1).img"
453}
454
455# Prepare extra part's files and fakeroot script
456rk_extra_part_prepare()
457{
458	PART_NAME="$(rk_extra_part_name $1)"
459	OUTDIR="$(rk_extra_part_outdir $1)"
460	MOUNT_DIR="$(rk_extra_part_mount_dir $1)"
461	FAKEROOT_SCRIPT="$(rk_extra_part_fakeroot_script $1)"
462	SRCS="$(rk_extra_part_src $1)"
463
464	echo "Preparing partiton $PART_NAME"
465
466	rm -rf "$OUTDIR" "$FAKEROOT_SCRIPT"
467
468	if [ ! "$SRCS" ]; then
469		echo "Ignoring $PART_NAME for no sources"
470		return 0
471	fi
472
473	mkdir -p "$OUTDIR"
474
475	if rk_extra_part_fixed $idx; then
476		if ! rk_extra_part_builtin $idx; then
477			# Skip boot-time resizing by adding a tag file
478			touch "$OUTDIR/.fixed"
479		fi
480	fi
481
482	echo "#!/bin/sh -e" > "$FAKEROOT_SCRIPT"
483	chmod a+x "$FAKEROOT_SCRIPT"
484
485	for src in $MOUNT_DIR $SRCS; do
486		[ -d "$src" ] || continue
487		[ "$(ls "$src/")" ] || continue
488
489		echo "Merging $src into $OUTDIR"
490		rsync -a "$src/" "$OUTDIR"
491		for f in $(ls "$OUTDIR" | grep "\.fs$" || true); do
492			echo "Merging $src/$f into $FAKEROOT_SCRIPT"
493			cat "$OUTDIR/$f" >> "$FAKEROOT_SCRIPT"
494			rm -f "$OUTDIR/$f"
495		done
496	done
497}
498