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 ext4
18 "system-data.img" 3 4M system-data ext4
19 "user.img" 5 4M user ext4
20 "modules.img" 6 4M modules ext4
21 "ramdisk.img" 7 4M ramdisk ext4
22 "ramdisk-recovery.img" 8 4M ramdisk-recovery ext4
23 "hal.img" 10 4M hal ext4
26 declare -r -i PART_TABLE_COL=5
27 declare -r -i PART_TABLE_ROW=${#PART_TABLE[*]}/${PART_TABLE_COL}
29 # partition table support
30 function get_index_use_name () {
31 local -r binary_name=$1
33 for ((idx=0;idx<$PART_TABLE_ROW;idx++)); do
34 if [ ${PART_TABLE[idx * ${PART_TABLE_COL} + 0]} == "$binary_name" ]; then
39 # return out of bound index
43 function print_message () {
54 function check_ddversion () {
56 # before coreutils dd 8.24, dd doesn't support "status=progress"
57 # and the option causes fusing failure. For backward compatibility,
58 # do not use the option for old dd
59 local version=(`dd --version | head -1 | grep -o '[0-9]\+'`)
60 local major=${version[0]}
61 local minor=${version[1]}
63 if [ $major -lt 8 ]; then
65 elif [ $major -eq 8 -a $minor -lt 24 ]; then
70 function fusing_image () {
71 local -r fusing_img=$1
73 # get binary info using basename
74 get_index_use_name $(basename "$fusing_img")
75 local -r -i part_idx=$?
77 if [ $part_idx -ne $PART_TABLE_ROW ];then
78 local -r num=${PART_TABLE[${part_idx} * ${PART_TABLE_COL} + 1]}
79 if [ "${num}" == "" ]; then
84 local -r device=/dev/`lsblk ${DEVICE} -o TYPE,KNAME | awk "/^${blktype}.*[a-z]${num}\$/ { print \\\$2 }"`
85 local -r bs=${PART_TABLE[${part_idx} * ${PART_TABLE_COL} + 2]}
87 echo "Not supported binary: $fusing_img"
91 if ! [ -b "$device" ]; then
92 print_message 1 "$device is not a block device."
96 local -r input_size=`du -b $fusing_img | awk '{print $1}'`
97 local -r input_size_mb=`expr $input_size / 1024 / 1024`
99 print_message 2 "[Fusing $1 ($input_size_mb MiB)]"
100 if [ "$blktype" == "part" ]; then
101 local MOUNT_PART=`mount | grep $device`
102 if [ "$MOUNT_PART" != "" ]; then
106 if [ $OLD_DD == 1 ]; then
107 dd if=$fusing_img | pv -s $input_size | dd of=$device bs=$bs
109 dd if=$fusing_img of=$device bs=$bs status=progress oflag=direct
112 local -r fstype=`blkid -o value -s TYPE $device`
113 if [[ "$fstype" =~ "ext" ]]; then
118 function fuse_image_tarball () {
120 local -r temp_dir="tar_tmp"
123 tar xvf $filepath -C $temp_dir
136 function fuse_image () {
138 if [ "$FUSING_BINARY_NUM" == 0 ]; then
142 for ((fuse_idx = 0 ; fuse_idx < $FUSING_BINARY_NUM ; fuse_idx++))
144 local filename=${FUSING_BINARY_ARRAY[fuse_idx]}
148 fuse_image_tarball $filename
151 fusing_image $filename
159 function mkpart_3 () {
160 # NOTE: if your sfdisk version is less than 2.26.0, then you should use following sfdisk command:
161 # sfdisk --in-order --Linux --unit M $DISK <<-__EOF__
163 # NOTE: sfdisk 2.26 doesn't support units other than sectors and marks --unit option as deprecated.
164 # The input data needs to contain multipliers (MiB) instead.
165 local version=(`sfdisk -v | grep -o '[0-9]\+'`)
166 local major=${version[0]}
167 local minor=${version[1]}
169 local support_delete=0
171 if [ $major -gt 2 ]; then
174 if [ $major -eq 2 -a $minor -ge 26 ]; then
176 if [ $major -eq 2 -a $minor -ge 28 ]; then
182 if [ $sfdisk_new == 0 ]; then
183 echo "$(tput setaf 3)$(tput bold)NOTICE: Your sfidk ${version[0]}.${version[1]} version is too old. It can do unstable behavior!"
189 local -r DISK=$DEVICE
190 local -r SIZE=`sfdisk -s $DISK`
191 local -r SIZE_MB=$((SIZE >> 10))
194 local -r ROOTFS_SZ=3072
195 local -r DATA_SZ=1344
196 local -r MODULE_SZ=32
197 local -r RAMDISK_SZ=32
198 local -r RAMDISK_RECOVERY_SZ=32
201 local -r RESERVED2_SZ=125
202 local -r EXTEND_SZ=12
204 let "USER_SZ = $SIZE_MB - $BOOT_SZ - $ROOTFS_SZ - $DATA_SZ - $MODULE_SZ - $RAMDISK_SZ - $RAMDISK_RECOVERY_SZ - $INFORM_SZ - $EXTEND_SZ - $HAL_SZ - $RESERVED2_SZ"
206 local -r BOOT=${PART_TABLE[0 * ${PART_TABLE_COL} + 3]}
207 local -r ROOTFS=${PART_TABLE[1 * ${PART_TABLE_COL} + 3]}
208 local -r SYSTEMDATA=${PART_TABLE[2 * ${PART_TABLE_COL} + 3]}
209 local -r USER=${PART_TABLE[3 * ${PART_TABLE_COL} + 3]}
210 local -r MODULE=${PART_TABLE[4 * ${PART_TABLE_COL} + 3]}
211 local -r RAMDISK=${PART_TABLE[5 * ${PART_TABLE_COL} + 3]}
212 local -r RAMDISK_RECOVERY=${PART_TABLE[6 * ${PART_TABLE_COL} + 3]}
213 local -r INFORM=inform
214 local -r HAL=${PART_TABLE[7 * ${PART_TABLE_COL} + 3]}
215 local -r RESERVED2=reserved2
217 if [[ $USER_SZ -le 100 ]]
219 echo "We recommend to use more than 4GB disk"
223 echo "================================================"
224 echo "Label dev size"
225 echo "================================================"
226 echo $BOOT" " $DISK"1 " $BOOT_SZ "MB"
227 echo $ROOTFS" " $DISK"2 " $ROOTFS_SZ "MB"
228 echo $SYSTEMDATA" " $DISK"3 " $DATA_SZ "MB"
229 echo "[Extend]"" " $DISK"4"
230 echo " "$USER" " $DISK"5 " $USER_SZ "MB"
231 echo " "$MODULE" " $DISK"6 " $MODULE_SZ "MB"
232 echo " "$RAMDISK" " $DISK"7 " $RAMDISK_SZ "MB"
233 echo " "$RAMDISK_RECOVERY" " $DISK"8 " $RAMDISK_RECOVERY_SZ "MB"
234 echo " "$INFORM" " $DISK"9 " $INFORM_SZ "MB"
235 echo " "$HAL" " $DISK"10 " $HAL_SZ "MB"
236 echo " "$RESERVED2" " $DISK"11 " $RESERVED2_SZ "MB"
238 local MOUNT_LIST=`mount | grep $DISK | awk '{print $1}'`
239 for mnt in $MOUNT_LIST
244 echo "Remove partition table..."
245 dd if=/dev/zero of=$DISK bs=512 count=32 conv=notrunc
247 if [ $sfdisk_new == 1 ]; then
248 if [ $support_delete == 1 ]; then
249 sfdisk --delete $DISK
252 sfdisk $DISK <<-__EOF__
253 4MiB,${BOOT_SZ}MiB,0xE,*
254 8MiB,${ROOTFS_SZ}MiB,,-
255 8MiB,${DATA_SZ}MiB,,-
260 ,${RAMDISK_RECOVERY_SZ}MiB,,-
263 ,${RESERVED2_SZ}MiB,,-
266 # calculate start positions for alignment for extended partitions
267 let "USER_START = 4 + $BOOT_SZ + $ROOTFS_SZ + $DATA_SZ + 1"
268 let "MODULE_START = $USER_START + $USER_SZ + 1"
269 let "RAMDISK_START = $MODULE_START + $MODULE_SZ + 1"
270 let "RAMDISK_RECOVERY_START = $RAMDISK_START + $RAMDISK_SZ + 1"
271 let "INFORM_START = $RAMDISK_RECOVERY_START + $RAMDISK_RECOVERY_SZ + 1"
272 let "HAL_START = $INFORM_START + $INFORM_SZ + 1"
273 let "RESERVED2_START = $HAL_START + $HAL_SZ + 1"
275 sfdisk --in-order --Linux --unit M $DISK <<-__EOF__
280 $USER_START,$USER_SZ,,-
281 $MODULE_START,$MODULE_SZ,,-
282 $RAMDISK_START,$RAMDISK_SZ,,-
283 $RAMDISK_RECOVERY_START,$RAMDISK_RECOVERY_SZ,,-
284 $INFORM_START,$INFORM_SZ,,-
285 $HAL_START,$HAL_SZ,,-
286 $RESERVED2_START,$RESERVED2_SZ,,-
290 for ((idx=0;idx<$PART_TABLE_ROW;idx++)); do
291 local PART=/dev/`lsblk ${DISK} -o TYPE,KNAME | awk "/^part.*[a-z]${PART_TABLE[$idx * ${PART_TABLE_COL} + 1]}\$/ { print \\\$2 }"`
292 if [ "${PART_TABLE[$idx * ${PART_TABLE_COL} + 4]}" == "vfat" ]; then
293 mkfs.vfat -F 16 ${PART} -n ${PART_TABLE[$idx * ${PART_TABLE_COL} + 3]}
294 if [ $? -eq 1 ]; then
295 echo "Failed to format as FAT filesystem"
298 elif [ "${PART_TABLE[$idx * ${PART_TABLE_COL} + 4]}" == "ext4" ]; then
299 mkfs.ext4 -q ${PART} -L ${PART_TABLE[$idx * ${PART_TABLE_COL} + 3]} -F
301 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]}"
305 local -r PART9=/dev/`lsblk ${DISK} -o TYPE,KNAME | grep part | awk '{ print $2 }' | grep -G "[a-z]9\$"`
306 mkfs.ext4 -q ${PART9} -L $INFORM -F
308 # create "reboot-param.bin" file in inform partition for passing reboot parameter
309 # It should be done only once upon partition format.
310 if [ -d mnt_tmp ]; then
311 echo "Remove the existing mnt_tmp directory!!"
315 mount -t ext4 ${PART9} ./mnt_tmp
316 touch ./mnt_tmp/reboot-param.bin
321 local -r PART11=/dev/`lsblk ${DISK} -o TYPE,KNAME | grep part | awk '{ print $2 }' | grep -G "[a-z]11\$"`
322 mkfs.ext4 -q ${PART11} -L $RESERVED2 -F
325 function show_usage () {
327 echo " sudo ./sd_fusing*.sh -d <device> [-b <path> <path> ..] [--format]"
330 function check_partition_format () {
331 if [ "$FORMAT" != "2" ]; then
332 echo "-----------------------"
333 echo "Skip $DEVICE format"
334 echo "-----------------------"
338 echo "-------------------------------"
339 echo "Start $DEVICE format"
342 echo "End $DEVICE format"
343 echo "-------------------------------"
347 function check_args () {
348 if [ "$DEVICE" == "" ]; then
349 echo "$(tput setaf 1)$(tput bold)- Device node is empty!"
355 if [ "$DEVICE" != "" ]; then
356 echo "Device: $DEVICE"
359 if [ "$FUSING_BINARY_NUM" != 0 ]; then
360 echo "Fusing binary: "
361 for ((bid = 0 ; bid < $FUSING_BINARY_NUM ; bid++))
363 echo " ${FUSING_BINARY_ARRAY[bid]}"
368 if [ "$FORMAT" == "1" ]; then
370 echo -n "$(tput setaf 3)$(tput bold)$DEVICE will be formatted, Is it OK? [y/<n>] "
373 if [ "$input" == "y" ] || [ "$input" == "Y" ]; then
381 function check_device () {
382 if [ ! -b "$DEVICE" ]; then
383 echo "No such device: $DEVICE"
387 DEVICE=/dev/`lsblk $DEVICE -o TYPE,KNAME | awk "/^disk/ { print \\\$2 }"`
389 local REMOVABLE=`lsblk $DEVICE -nd -o RM | grep 1 | wc -l`
390 if [ "$REMOVABLE" == "0" ]; then
392 echo "$(tput setaf 3)$(tput bold)$DEVICE is not a removable disk, Is it OK? [y/<n>]"
395 if [ "$input" != "y" ] && [ "$input" != "Y" ]; then
400 if [ ! -w "$DEVICE" ]; then
401 echo "Write not permitted: $DEVICE"
406 function print_logo () {
408 echo "Only Raspberry Pi3 downloader, version 2.2.2"
414 function add_fusing_binary() {
415 local declare binary_name=$1
417 if [ "$binary_name" != "" ]; then
418 if [ -f "$binary_name" ]; then
419 FUSING_BINARY_ARRAY[$FUSING_BINARY_NUM]=$binary_name
421 FUSING_BINARY_NUM=$((FUSING_BINARY_NUM + 1))
423 echo "No such file: $binary_name"
429 declare -i binary_option=0
431 while test $# -ne 0; do
451 if [ $binary_option == 1 ];then
452 add_fusing_binary $option
454 echo "Unkown command: $option"
463 check_partition_format