7 # Binaires array for fusing
8 declare -a FUSING_BINARY_ARRAY
9 declare -i FUSING_BINARY_NUM=0
12 declare -i FUS_ENTRY_NUM=0
14 # binary name | part number | bs | label | fs type
15 declare -a PART_TABLE=(
16 "boot.img" 1 4M boot vfat
17 "rootfs.img" 2 4M rootfs_a ext4
18 "system-data.img" 3 4M system-data ext4
19 "user.img" 5 4M user ext4
20 "modules.img" 6 4M modules_a ext4
21 "ramdisk.img" 7 4M ramdisk_a ext4
22 "ramdisk-recovery.img" 8 4M recovery_a ext4
23 "hal.img" 10 4M hal ext4
24 "rootfs.img" 11 4M rootfs_b ext4
25 "modules.img" 12 4M modules_b ext4
26 "ramdisk.img" 13 4M ramdisk_b ext4
27 "ramdisk-recovery.img" 14 4M recovery_b ext4
29 declare -a PART_TABLE_B=(
30 "rootfs.img" 11 4M rootfs_b ext4
31 "modules.img" 12 4M modules_b ext4
32 "ramdisk.img" 13 4M ramdisk_b ext4
33 "ramdisk-recovery.img" 14 4M recovery_b ext4
36 declare -r -i PART_TABLE_COL=5
37 declare -r -i PART_TABLE_ROW=${#PART_TABLE[*]}/${PART_TABLE_COL}
38 declare -r -i PART_TABLE_ROW_B=${#PART_TABLE_B[*]}/${PART_TABLE_COL}
40 # partition table support
41 function get_index_use_name () {
42 local -r binary_name=$1
44 for ((idx=0;idx<$PART_TABLE_ROW;idx++)); do
45 if [ ${PART_TABLE[idx * ${PART_TABLE_COL} + 0]} == "$binary_name" ]; then
50 # return out of bound index
54 # partition table support
55 function get_index_use_name_to_b () {
56 local -r binary_name=$1
58 for ((idx=0;idx<$PART_TABLE_ROW_B;idx++)); do
59 if [ ${PART_TABLE_B[idx * ${PART_TABLE_COL} + 0]} == "$binary_name" ]; then
64 # return out of bound index
68 function print_message () {
79 function check_ddversion () {
81 # before coreutils dd 8.24, dd doesn't support "status=progress"
82 # and the option causes fusing failure. For backward compatibility,
83 # do not use the option for old dd
84 local version=(`dd --version | head -1 | grep -o '[0-9]\+'`)
85 local major=${version[0]}
86 local minor=${version[1]}
88 if [ $major -lt 8 ]; then
90 elif [ $major -eq 8 -a $minor -lt 24 ]; then
95 function fusing_image () {
96 local -r fusing_img=$1
98 # get binary info using basename
99 get_index_use_name $(basename "$fusing_img")
100 local -r -i part_idx=$?
102 if [ $part_idx -ne $PART_TABLE_ROW ];then
103 local -r num=${PART_TABLE[${part_idx} * ${PART_TABLE_COL} + 1]}
104 if [ "${num}" == "" ]; then
105 local -r blktype=disk
107 local -r blktype=part
109 local -r device=/dev/`lsblk ${DEVICE} -o TYPE,KNAME | awk "/^${blktype}.*[a-z]${num}\$/ { print \\\$2 }"`
110 local -r bs=${PART_TABLE[${part_idx} * ${PART_TABLE_COL} + 2]}
112 echo "Not supported binary: $fusing_img"
116 local -r input_size=`du -b $fusing_img | awk '{print $1}'`
117 local -r input_size_mb=`expr $input_size / 1024 / 1024`
119 print_message 2 "[Fusing $1 ($input_size_mb MiB)]"
120 if [ "$blktype" == "part" ]; then
121 local MOUNT_PART=`mount | grep $device`
122 if [ "$MOUNT_PART" != "" ]; then
126 if [ $OLD_DD == 1 ]; then
127 dd if=$fusing_img | pv -s $input_size | dd of=$device bs=$bs
129 dd if=$fusing_img of=$device bs=$bs status=progress oflag=direct
132 local -r fstype=`blkid -o value -s TYPE $device`
133 if [[ "$fstype" =~ "ext" ]]; then
138 function fusing_image_to_b () {
139 local -r fusing_img=$1
141 # get binary info using basename
142 get_index_use_name_to_b $(basename "$fusing_img")
144 local -r -i part_idx=$?
146 if [ $part_idx -ne $PART_TABLE_ROW_B ];then
147 local -r num=${PART_TABLE_B[${part_idx} * ${PART_TABLE_COL} + 1]}
148 if [ "${num}" == "" ]; then
149 local -r blktype=disk
151 local -r blktype=part
153 local -r device=/dev/`lsblk ${DEVICE} -o TYPE,KNAME | awk "/^${blktype}.*[a-z]${num}\$/ { print \\\$2 }"`
154 local -r bs=${PART_TABLE_B[${part_idx} * ${PART_TABLE_COL} + 2]}
156 echo "Not supported binary: $fusing_img"
160 local -r input_size=`du -b $fusing_img | awk '{print $1}'`
161 local -r input_size_mb=`expr $input_size / 1024 / 1024`
163 print_message 2 "[Fusing $1 ($input_size_mb MiB)]"
164 if [ "$blktype" == "part" ]; then
165 local MOUNT_PART=`mount | grep $device`
166 if [ "$MOUNT_PART" != "" ]; then
170 if [ $OLD_DD == 1 ]; then
171 dd if=$fusing_img | pv -s $input_size | dd of=$device bs=$bs
173 dd if=$fusing_img of=$device bs=$bs status=progress oflag=direct
176 local -r fstype=`blkid -o value -s TYPE $device`
177 if [[ "$fstype" =~ "ext" ]]; then
182 function fuse_image_tarball () {
184 local -r temp_dir="tar_tmp"
187 tar xvf $filepath -C $temp_dir
193 fusing_image_to_b $file
201 function fuse_image () {
203 if [ "$FUSING_BINARY_NUM" == 0 ]; then
207 for ((fuse_idx = 0 ; fuse_idx < $FUSING_BINARY_NUM ; fuse_idx++))
209 local filename=${FUSING_BINARY_ARRAY[fuse_idx]}
213 fuse_image_tarball $filename
216 fusing_image $filename
217 fusing_image_to_b $filename
225 function mkpart_3 () {
226 # NOTE: if your sfdisk version is less than 2.26.0, then you should use following sfdisk command:
227 # sfdisk --in-order --Linux --unit M $DISK <<-__EOF__
229 # NOTE: sfdisk 2.26 doesn't support units other than sectors and marks --unit option as deprecated.
230 # The input data needs to contain multipliers (MiB) instead.
231 local version=(`sfdisk -v | grep -o '[0-9]\+'`)
232 local major=${version[0]}
233 local minor=${version[1]}
235 local support_delete=0
237 if [ $major -gt 2 ]; then
239 if [ $major -eq 2 -a $minor -ge 28 ]; then
243 if [ $major -eq 2 -a $minor -ge 26 ]; then
248 if [ $sfdisk_new == 0 ]; then
249 echo "$(tput setaf 3)$(tput bold)NOTICE: Your sfidk ${version[0]}.${version[1]} version is too old. It can do unstable behavior!"
255 local -r DISK=$DEVICE
256 local -r SIZE=`sfdisk -s $DISK`
257 local -r SIZE_MB=$((SIZE >> 10))
260 local -r ROOTFS_SZ=3072
261 local -r DATA_SZ=1344
262 local -r MODULE_SZ=32
263 local -r RAMDISK_SZ=32
264 local -r RAMDISK_RECOVERY_SZ=32
267 local -r RESERVED2_SZ=125
268 local -r EXTEND_SZ=36
270 let "USER_SZ = $SIZE_MB - $BOOT_SZ - $ROOTFS_SZ * 2 - $DATA_SZ - $MODULE_SZ * 2 - $RAMDISK_SZ * 2 - $RAMDISK_RECOVERY_SZ * 2 - $INFORM_SZ - $EXTEND_SZ - $HAL_SZ - $RESERVED2_SZ"
272 local -r BOOT=${PART_TABLE[0 * ${PART_TABLE_COL} + 3]}
273 local -r ROOTFS_A=${PART_TABLE[1 * ${PART_TABLE_COL} + 3]}
274 local -r SYSTEMDATA=${PART_TABLE[2 * ${PART_TABLE_COL} + 3]}
275 local -r USER=${PART_TABLE[3 * ${PART_TABLE_COL} + 3]}
276 local -r MODULE_A=${PART_TABLE[4 * ${PART_TABLE_COL} + 3]}
277 local -r RAMDISK_A=${PART_TABLE[5 * ${PART_TABLE_COL} + 3]}
278 local -r RAMDISK_RECOVERY_A=${PART_TABLE[6 * ${PART_TABLE_COL} + 3]}
279 local -r INFORM=inform
280 local -r HAL=${PART_TABLE[7 * ${PART_TABLE_COL} + 3]}
281 local -r ROOTFS_B=${PART_TABLE[8 * ${PART_TABLE_COL} + 3]}
282 local -r MODULE_B=${PART_TABLE[9 * ${PART_TABLE_COL} + 3]}
283 local -r RAMDISK_B=${PART_TABLE[10 * ${PART_TABLE_COL} + 3]}
284 local -r RAMDISK_RECOVERY_B=${PART_TABLE[10 * ${PART_TABLE_COL} + 3]}
285 local -r RESERVED2=reserved2
287 if [[ $USER_SZ -le 100 ]]
289 echo "We recommend to use more than 4GB disk"
293 echo "================================================"
294 echo "Label dev size"
295 echo "================================================"
296 echo $BOOT" " $DISK"1 " $BOOT_SZ "MB"
297 echo $ROOTFS_A" " $DISK"2 " $ROOTFS_SZ "MB"
298 echo $SYSTEMDATA" " $DISK"3 " $DATA_SZ "MB"
299 echo "[Extend]"" " $DISK"4"
300 echo " "$USER" " $DISK"5 " $USER_SZ "MB"
301 echo " "$MODULE_A" " $DISK"6 " $MODULE_SZ "MB"
302 echo " "$RAMDISK_A" " $DISK"7 " $RAMDISK_SZ "MB"
303 echo " "$RAMDISK_RECOVERY_A" " $DISK"8 " $RAMDISK_RECOVERY_SZ "MB"
304 echo " "$INFORM" " $DISK"9 " $INFORM_SZ "MB"
305 echo " "$HAL" " $DISK"10 " $HAL_SZ "MB"
306 echo " "$ROOTFS_B" " $DISK"11 " $ROOTFS_SZ "MB"
307 echo " "$MODULE_B" " $DISK"12 " $MODULE_SZ "MB"
308 echo " "$RAMDISK_B" " $DISK"13 " $RAMDISK_SZ "MB"
309 echo " "$RAMDISK_RECOVERY_B" " $DISK"14 " $RAMDISK_RECOVERY_SZ "MB"
310 echo " "$RESERVED2" " $DISK"15 " $RESERVED2_SZ "MB"
312 local MOUNT_LIST=`mount | grep $DISK | awk '{print $1}'`
313 for mnt in $MOUNT_LIST
318 echo "Remove partition table..."
319 dd if=/dev/zero of=$DISK bs=512 count=32 conv=notrunc
321 if [ $sfdisk_new == 1 ]; then
322 if [ $support_delete == 1 ]; then
323 sfdisk --delete $DISK
327 for ((idx=0; idx < $PART_TABLE_ROW; idx++)); do
328 NR=${PART_TABLE[idx * ${PART_TABLE_COL} + 1]}
329 eval "PART_LABEL_NR_${NR}=${PART_TABLE[idx * ${PART_TABLE_COL} + 3]}"
332 sfdisk $DISK <<-__EOF__
334 ${DEVICE}1 : start=4MiB, size=${BOOT_SZ}MiB, type= C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name=${PART_LABEL_NR_1}
335 ${DEVICE}2 : size=${ROOTFS_SZ}MiB, name=${PART_LABEL_NR_2}
336 ${DEVICE}3 : size=${DATA_SZ}MiB, name=${PART_LABEL_NR_3}
337 ${DEVICE}4 : size=${EXTEND_SZ}MiB, name=none
338 ${DEVICE}5 : size=${USER_SZ}MiB, name=${PART_LABEL_NR_5}
339 ${DEVICE}6 : size=${MODULE_SZ}MiB, name=${PART_LABEL_NR_6}
340 ${DEVICE}7 : size=${RAMDISK_SZ}MiB, name=${PART_LABEL_NR_7}
341 ${DEVICE}8 : size=${RAMDISK_RECOVERY_SZ}MiB, name=${PART_LABEL_NR_8}
342 ${DEVICE}9 : size=${INFORM_SZ}MiB, name=inform
343 ${DEVICE}10: size=${HAL_SZ}MiB, name=${PART_LABEL_NR_10}
344 ${DEVICE}11: size=${ROOTFS_SZ}MiB, name=${PART_LABEL_NR_11}
345 ${DEVICE}12: size=${MODULE_SZ}MiB, name=${PART_LABEL_NR_12}
346 ${DEVICE}13: size=${RAMDISK_SZ}MiB, name=${PART_LABEL_NR_13}
347 ${DEVICE}14: size=${RAMDISK_RECOVERY_SZ}MiB, name=${PART_LABEL_NR_14}
348 ${DEVICE}15: size=${RESERVED2_SZ}MiB, name=reserved2
351 # calculate start positions for alignment for extended partitions
352 let "USER_START = 4 + $BOOT_SZ + $ROOTFS_SZ + $DATA_SZ + 1"
353 let "MODULE_A_START = $USER_START + $USER_SZ + 1"
354 let "RAMDISK_A_START = $MODULE_A_START + $MODULE_SZ + 1"
355 let "RAMDISK_RECOVERY_A_START = $RAMDISK_A_START + $RAMDISK_SZ + 1"
356 let "INFORM_START = $RAMDISK_RECOVERY_A_START + $RAMDISK_RECOVERY_SZ + 1"
357 let "HAL_START = $INFORM_START + $INFORM_SZ + 1"
358 let "ROOTFS_B_START = $HAL_START + $HAL_SZ + 1"
359 let "MODULE_B_START = $ROOTFS_B_START + $ROOTFS_SZ + 1"
360 let "RAMDISK_B_START = $MODULE_B_START + $MODULE_SZ + 1"
361 let "RAMDISK_RECOVERY_B_START = $RAMDISK_B_START + $RAMDISK_SZ + 1"
362 let "RESERVED2_START = $RAMDISK_RECOVERY_B_START + $RAMDISK_RECOVERY_SZ + 1"
364 sfdisk --in-order --Linux --unit M $DISK <<-__EOF__
369 $USER_START,$USER_SZ,,-
370 $MODULE_A_START,$MODULE_SZ,,-
371 $RAMDISK_A_START,$RAMDISK_SZ,,-
372 $RAMDISK_RECOVERY_A_START,$RAMDISK_RECOVERY_SZ,,-
373 $INFORM_START,$INFORM_SZ,,-
374 $HAL_START,$HAL_SZ,,-
375 $ROOTFS_B_START,$ROOTFS_SZ,,-
376 $MODULE_B_START,$MODULE_SZ,,-
377 $RAMDISK_B_START,$RAMDISK_SZ,,-
378 $RAMDISK_RECOVERY_B_START,$RAMDISK_RECOVERY_SZ,,-
379 $RESERVED2_START,$RESERVED2_SZ,,-
383 for ((idx=0;idx<$PART_TABLE_ROW;idx++)); do
384 local PART=/dev/`lsblk ${DISK} -o TYPE,KNAME | awk "/^part.*[a-z]${PART_TABLE[$idx * ${PART_TABLE_COL} + 1]}\$/ { print \\\$2 }"`
385 if [ "${PART_TABLE[$idx * ${PART_TABLE_COL} + 4]}" == "vfat" ]; then
386 mkfs.vfat -F 16 ${PART} -n ${PART_TABLE[$idx * ${PART_TABLE_COL} + 3]}
387 if [ $? -eq 1 ]; then
388 echo "Failed to format as FAT filesystem"
391 elif [ "${PART_TABLE[$idx * ${PART_TABLE_COL} + 4]}" == "ext4" ]; then
392 mkfs.ext4 -q ${PART} -L ${PART_TABLE[$idx * ${PART_TABLE_COL} + 3]} -F
394 echo "Skip to format for unknown filesystem type ${PART_TABLE[$idx * ${PART_TABLE_COL} + 4]} for part$idx, ${PART_TABLE[$idx * ${PART_TABLE_COL} + 3]}"
398 local -r PART9=/dev/`lsblk ${DISK} -o TYPE,KNAME | grep part | awk '{ print $2 }' | grep -G "[a-z]9\$"`
399 mkfs.ext4 -q ${PART9} -L $INFORM -F
401 # create "reboot-param.bin" file in inform partition for passing reboot parameter
402 # It should be done only once upon partition format.
403 if [ -d mnt_tmp ]; then
404 echo "Remove the existing mnt_tmp directory!!"
408 mount -t ext4 ${PART9} ./mnt_tmp
409 touch ./mnt_tmp/reboot-param.bin
414 local -r PART15=/dev/`lsblk ${DISK} -o TYPE,KNAME | grep part | awk '{ print $2 }' | grep -G "[a-z]15\$"`
415 mkfs.ext4 -q ${PART15} -L $RESERVED2 -F
418 function show_usage () {
420 echo " sudo ./sd_fusing*.sh -d <device> [-b <path> <path> ..] [--format]"
423 function check_partition_format () {
424 if [ "$FORMAT" != "2" ]; then
425 echo "-----------------------"
426 echo "Skip $DEVICE format"
427 echo "-----------------------"
431 echo "-------------------------------"
432 echo "Start $DEVICE format"
435 echo "End $DEVICE format"
436 echo "-------------------------------"
440 function check_args () {
441 if [ "$DEVICE" == "" ]; then
442 echo -n "$(tput setaf 3)$(tput bold)$DEVICE will be formatted, Is it OK? [y/<n>] "
448 if [ "$DEVICE" != "" ]; then
449 echo "Device: $DEVICE"
452 if [ "$FUSING_BINARY_NUM" != 0 ]; then
453 echo "Fusing binary: "
454 for ((bid = 0 ; bid < $FUSING_BINARY_NUM ; bid++))
456 echo " ${FUSING_BINARY_ARRAY[bid]}"
461 if [ "$FORMAT" == "1" ]; then
463 echo "$(tput setaf 3)$(tput bold)$DEVICE will be formatted, Is it OK? [y/<n>]"
466 if [ "$input" == "y" ] || [ "$input" == "Y" ]; then
474 function check_device () {
475 if [ ! -b "$DEVICE" ]; then
476 echo "No such device: $DEVICE"
480 local REMOVABLE=`lsblk $DEVICE -nd -o RM | grep 1 | wc -l`
481 if [ "$REMOVABLE" == "0" ]; then
483 echo "$(tput setaf 3)$(tput bold)$DEVICE is not a removable disk, Is it OK? [y/<n>]"
486 if [ "$input" != "y" ] && [ "$input" != "Y" ]; then
491 if [ ! -w "$DEVICE" ]; then
492 echo "Write not permitted: $DEVICE"
497 function print_logo () {
499 echo "Raspberry Pi4 downloader, version 1.0.0"
505 function add_fusing_binary() {
506 local declare binary_name=$1
508 if [ "$binary_name" != "" ]; then
509 if [ -f "$binary_name" ]; then
510 FUSING_BINARY_ARRAY[$FUSING_BINARY_NUM]=$binary_name
512 FUSING_BINARY_NUM=$((FUSING_BINARY_NUM + 1))
514 echo "No such file: $binary_name"
520 declare -i binary_option=0
522 while test $# -ne 0; do
542 if [ $binary_option == 1 ];then
543 add_fusing_binary $option
545 echo "Unkown command: $option"
554 check_partition_format