#!/bin/bash
#
# Copyright (c) Authors: https://www.armbian.com/authors
#
# Tool to transfer the rootfs of an already running Armbian installation from boot media
# to NAND, eMMC, SATA, NVME or USB storage. In case of eMMC it's also possible to transfer
# the bootloader to eMMC in a single step so from then on running without SD card is
# possible. In case of UEFI it's possible to install it side by side with Windows 10/11 or
# to an empty target.
#

# Import:
# DIR: path to u-boot directory
# write_uboot_platform: function to write u-boot to a block device
# write_uboot_platform_mtd:
#   function to write u-boot to a mtd (eg. SPI flash) device
#   $1 = u-boot files directory
#   $2 = first MTD device path (e.g.: /dev/mtdblock0) - this is for backward compatibility before Armbian 23.nn
#   $3 = Log file name
#   $4 = :space: separated list of all MTD device names
#        Note: MTD char device names are passed in format device_name:partition_label - e.g.: mtd0:SPL

trap "systemctl start docker >/dev/null 2>&1; exit" INT TERM
[[ $EUID != 0 ]] && exec sudo "$0" "$@"

[[ -f /usr/lib/u-boot/platform_install.sh ]] && source /usr/lib/u-boot/platform_install.sh

# ORIGINAL_SCRIPT_NAME: Must be either armbian-install or nand-sata-install
ORIGINAL_SCRIPT_NAME=$(basename $0)
# script configuration - derive from ORIGINAL_SCRIPT_NAME
CWD="/usr/lib/${ORIGINAL_SCRIPT_NAME}"
EX_LIST="${CWD}/exclude.txt"
[ ! -f ${EX_LIST} ] && echo -e "### Board installation issue: File ${EX_LIST} does not exist or is not accessible!\n" && exit 1
[ -f /etc/default/openmediavault ] && echo '/srv/*' >> "${EX_LIST}"
logfile="/var/log/${ORIGINAL_SCRIPT_NAME}.log"

# read in board info
[[ -f /etc/armbian-release ]] && source /etc/armbian-release
backtitle="Armbian for $BOARD_NAME install script, https://www.armbian.com"
title="Armbian installer v${VERSION}"

# exceptions
if grep -q 'sun4i' /proc/cpuinfo; then DEVICE_TYPE="a10";
elif grep -q 'sun5i' /proc/cpuinfo; then DEVICE_TYPE="a13";
else DEVICE_TYPE="a20"; fi
BOOTLOADER="${CWD}/${DEVICE_TYPE}/bootloader"
[ ! -d ${BOOTLOADER} ] && echo -e "### Board installation issue: Directory ${BOOTLOADER} does not exist or is not accessible!\n" && exit 1
FIRSTSECTOR=32768

#recognize_root
root_uuid=$(sed -e 's/^.*root=//' -e 's/ .*$//' < /proc/cmdline)
root_partition=$(blkid | tr -d '":' | grep "${root_uuid}" | awk '{print $1}')
root_partition_name=$(echo $root_partition | sed 's/\/dev\///g')
root_partition_device_name=$(lsblk -ndo pkname $root_partition)
root_partition_device=/dev/$root_partition_device_name

# find targets: legacy SUNXI NAND, EMMC, SATA, NVMe, MTD block and/or MTD char driven flash
[[ -b /dev/nand ]] && nandcheck=$(ls -d -1 /dev/nand* | grep -w 'nand' | awk '{print $NF}');
emmccheck=$(ls -d -1 /dev/mmcblk* 2>/dev/null | grep -w 'mmcblk[0-9]' | grep -v "$root_partition_device");
diskcheck=$(lsblk -Al | awk -F" " '/ disk / {print $1}' | grep -E '^sd|^nvme|^mmc' | grep -v "$root_partition_device_name" | grep -v boot)
# Start mtdcheck with probable MTD block device partitions:
mtdcheck=$(grep 'mtdblock' /proc/partitions | awk '{print $NF}' | xargs)
# Append mtdcheck with probable MTD char devices filtered for partition name(s)
# containing "spl" or "boot" case insensitive,
# since we are currently interested in MTD partitions for boot flashing only.
# Note: The following statement will add matching MTD char device names
#       combined with partition name (separated from devicename by a :colon:):
#       mtd0:partition0_name mtd1:partition1_name ... mtdN:partitionN_name
[[ -f /proc/mtd ]] && mtdcheck="$mtdcheck${mtdcheck:+ }$(grep -i -E '^mtd[0-9]+:.*(spl|boot).*' /proc/mtd | awk '{print $1$NF}' | sed 's/\"//g' | xargs)"

# SD card boot part - to be considered more than one entry on various platforms
# UUID=xxx...
# 1 - Lookup mmc devices excluding the mmc device probably providing the current root partition as well as a probable emmc device found above:
[[ -z $emmccheck ]] && sdblkid=$(blkid -o full /dev/mmcblk*p1 | grep -v "$root_partition_device")
[[ -n $emmccheck ]] && sdblkid=$(blkid -o full /dev/mmcblk*p1 | grep -v "$root_partition_device" | grep -v "$emmccheck")
# 2 - If there is nothing, then lookup any mmc partition matching /dev/mmcblk*p1 excluding probable emmc device found above
[[ -z $sdblkid && -z $emmccheck ]] && sdblkid=$(blkid -o full /dev/mmcblk*p1)
[[ -z $sdblkid && -n $emmccheck ]] && sdblkid=$(blkid -o full /dev/mmcblk*p1 | grep -v "$emmccheck")
# 3 - Extract the UUID=<uuid> from $sdblkid via regex without " - as e.g.: UUID=2e1d1509-a8fc-4f8b-8a51-88fb8593f8d6
sduuid=$(echo "$sdblkid" | sed -nE 's/^.*[[:space:]](UUID="[0-9a-zA-Z-]*").*/\1/p' | tr -d '"')

#recognize EFI
[[ -d /sys/firmware/efi ]] && DEVICE_TYPE="uefi"
efi_partition=$(LC_ALL=C fdisk -l "/dev/$diskcheck" 2>/dev/null | grep "EFI" | awk '{print $1}')

# define makefs and mount options
declare -A mkopts mountopts
# for ARMv7 remove 64bit feature from default mke2fs format features
if [[ $LINUXFAMILY == mvebu ]]; then
	mkopts[ext4]='-O ^64bit -qF'
else
	mkopts[ext4]='-qF'
fi
mkopts[btrfs]='-f'
mkopts[f2fs]='-f'

# @TODO source these options from one source, this is mostly defined in partioning.sh
mountopts[ext4]='defaults,noatime,commit=120,errors=remount-ro,x-gvfs-hide	0	1'
mountopts[btrfs]="defaults,commit=120,compress=lzo,x-gvfs-hide,subvol=@	0	2"
mountopts[f2fs]='defaults,noatime,x-gvfs-hide	0	2'

# Create boot and root file system #
#
# "$1" = boot
# "$2" = root (Example: create_armbian "/dev/nand1" "/dev/sda3")
# "$3" = selected UEFI root target
#
create_armbian()
{

	[[ -n "$3" ]] && diskcheck=$3

	# create mount points, mount and clean
	TempDir=$(mktemp -d /mnt/${0##*/}.XXXXXX || exit 2)
	sync &&	mkdir -p "${TempDir}"/bootfs "${TempDir}"/rootfs
	if [[ $eMMCFilesystemChoosen =~ ^(btrfs|f2fs)$ ]]; then
		[[ -n $1 ]] && mount ${1::-1}"1" "${TempDir}"/bootfs
		[[ -n $2 ]] && ( mount -o compress-force=zlib "$2" "${TempDir}"/rootfs 2> /dev/null || mount "$2" "${TempDir}"/rootfs )
	else
		[[ -n $2 ]] && ( mount -o compress-force=zlib "$2" "${TempDir}"/rootfs 2> /dev/null || mount "$2" "${TempDir}"/rootfs )
		[[ -n $1 && $1 != "mtd" ]] && mount "$1" "${TempDir}"/bootfs
	fi

	# make separate subvolume for rootfs on btrfs
	if [[ $eMMCFilesystemChoosen =~ ^(btrfs)$ ]]; then
		btrfs subvolume create "${TempDir}"/rootfs/@
		sync
		btrfs subvolume list ${TempDir}/rootfs/ | grep 'path @$' | cut -d' ' -f2 \
			| xargs -I{} btrfs subvolume set-default {} ${TempDir}/rootfs/
		umount "${TempDir}"/rootfs
		mount -o compress-force=zlib,subvol=@ "$2" "${TempDir}"/rootfs 2> /dev/null
	fi
	rm -rf "${TempDir}"/bootfs/* "${TempDir}"/rootfs/*

	# sata root part
	# UUID=xxx...
	satauuid=$(blkid -o export "$2" | grep -w UUID)

	# disable docker before start
	systemctl is-active --quiet docker && systemctl stop docker

	# write information to log
	echo -e "\nOld UUID:  ${root_uuid}" >> $logfile
	echo "SD UUID:   $sduuid" >> $logfile
	echo "SATA UUID: $satauuid" >> $logfile
	echo "eMMC UUID: $emmcuuid $eMMCFilesystemChoosen" >> $logfile
	echo "Boot: \$1 $1 $eMMCFilesystemChoosen" >> $logfile
	echo "Root: \$2 $2 $FilesystemChoosen" >> $logfile

	# calculate usage and see if it fits on destination
	USAGE=$(df -BM | grep ^/dev | head -1 | awk '{print $3}' | tr -cd '[0-9]. \n')
	DEST=$(df -BM | grep ^/dev | grep "${TempDir}"/rootfs | awk '{print $4}' | tr -cd '[0-9]. \n')
	if [[ $USAGE -gt $DEST ]]; then
		dialog --title "$title" --backtitle "$backtitle" --colors --infobox\
		"\n\Z1Partition too small.\Zn Needed: $USAGE MB Avaliable: $DEST MB" 5 60
		umount_device "$1"; umount_device "$2"
		exit 3
	fi

	if [[ $1 == *nand* ]]; then
		# creating nand boot. Copy precompiled uboot
		rsync -aqc $BOOTLOADER/* "${TempDir}"/bootfs
	fi

	# write information to log
	echo "Usage: $USAGE" >> $logfile
	echo -e "Dest: $DEST\n\n/etc/fstab:" >> $logfile
	cat /etc/fstab >> $logfile
	echo -e "\n/etc/mtab:" >> $logfile
	grep '^/dev/' /etc/mtab | grep -E -v "log2ram|folder2ram" | sort >> $logfile

	# stop running services
	echo -e "\nFiles currently open for writing:" >> $logfile
	lsof / 2>/dev/null | awk 'NR==1 || $4~/[0-9][uw]/' | grep -v "^COMMAND" >> $logfile
	echo -e "\nTrying to stop running services to minimize open files:\c" >> $logfile
	stop_running_services "nfs-|smbd|nmbd|winbind|ftpd|netatalk|monit|cron|webmin|rrdcached" >> $logfile
	stop_running_services "fail2ban|ramlog|folder2ram|postgres|mariadb|mysql|postfix|mail|nginx|apache|snmpd" >> $logfile
	pkill dhclient 2>/dev/null
	LANG=C echo -e "\n\nChecking again for open files:" >> $logfile
	lsof / 2>/dev/null | awk 'NR==1 || $4~/[0-9][uw]/' | grep -v "^COMMAND" >> $logfile

	# count files is needed for progress bar
	dialog --title " $title " --backtitle "$backtitle" --infobox "\n  Counting files ... few seconds." 5 60
	TODO=$(rsync -avx --delete --stats --exclude-from=$EX_LIST / "${TempDir}"/rootfs | grep "Number of files:"|awk '{print $4}' | tr -d '.,')
	echo -e "\nCopying ${TODO} files to $2. \c" >> $logfile

	# creating rootfs
	# Speed copy increased x10
	 # Variables for interfacing with rsync progress
	nsi_conn_path="${TempDir}/nand-sata-install"
	nsi_conn_done="${nsi_conn_path}/done"
	nsi_conn_progress="${nsi_conn_path}/progress"
	mkdir -p "${nsi_conn_path}"
	echo 0 >"${nsi_conn_progress}"
	echo no >"${nsi_conn_done}"

	 # Launch rsync in background
	{ \
	rsync -avx --delete --exclude-from=$EX_LIST / "${TempDir}"/rootfs | \
	nl | awk '{ printf "%.0f\n", 100*$1/"'"$TODO"'" }' \
	> "${nsi_conn_progress}" ;
	 # create empty persistent journal directory if it exists before install
	[ -d /var/log.hdd/journal ] && mkdir "${TempDir}"/rootfs/var/log/journal
	 # save exit code from rsync
	echo  ${PIPESTATUS[0]} >"${nsi_conn_done}"
	} &

	 # while variables
	rsync_copy_finish=0
	rsync_progress=0
	prev_progress=0
	rsync_done=""
	while [ "${rsync_copy_finish}" -eq 0 ]; do
		# Sometimes reads the progress file while writing and only partial numbers (like 1 when is 15)
		prev_progress=${rsync_progress}
		rsync_progress=$(tail -n1 "${nsi_conn_progress}")
		if [[ -z ${rsync_progress} ]]; then
			rsync_progress=${prev_progress}
		fi
		if [ ${prev_progress} -gt ${rsync_progress} ]; then
			rsync_progress=${prev_progress}
		fi
		echo "${rsync_progress}"
		# finish the while if the rsync is finished
		rsync_done=$(cat ${nsi_conn_done})
		if [[ "${rsync_done}" != "no" ]]; then
			if [[ ${rsync_done} -eq 0 ]]; then
				rm -rf "${nsi_conn_path}"
				rsync_copy_finish=1
			else
				# if rsync return error
				echo "Error: could not copy rootfs files, exiting"
				exit 4
			fi
		else
			sleep 0.5
		fi

	done | \
	dialog --backtitle "$backtitle" --title " $title " --gauge "\n\n  Transferring rootfs to $2 ($USAGE MB). \n\n \
	 This will take approximately $(( $((USAGE/300)) * 1 )) minutes to finish. Please wait!\n\n" 11 80

	# run rsync again to silently catch outstanding changes between / and "${TempDir}"/rootfs/
	dialog --title "$title" --backtitle "$backtitle" --infobox "\n               Cleaning up ... Almost done." 5 60
	rsync -avx --delete --exclude-from=$EX_LIST / "${TempDir}"/rootfs >/dev/null 2>&1

	# mark OS as transferred
	if ! grep -q "INSTALLED=true" /etc/armbian-image-release; then
	echo "INSTALLED=true" >> "${TempDir}"/rootfs/etc/armbian-image-release
	fi

	# creating fstab from scratch
	rm -f "${TempDir}"/rootfs/etc/fstab
	mkdir -p "${TempDir}"/rootfs/etc "${TempDir}"/rootfs/media/mmcboot "${TempDir}"/rootfs/media/mmcroot

	# Restore TMP and swap
	echo "# <file system>					<mount point>	<type>	<options>							<dump>	<pass>" > "${TempDir}"/rootfs/etc/fstab
	echo "tmpfs						/tmp		tmpfs	defaults,nosuid							0	0" >> "${TempDir}"/rootfs/etc/fstab
	grep swap /etc/fstab >> "${TempDir}"/rootfs/etc/fstab

	# creating fstab, kernel and boot script for NAND partition
	#
	if [[ $1 == *nand* ]]; then
		echo "Finishing installation to NAND." >> $logfile
		REMOVESDTXT="and remove SD to boot from NAND"
		# @TODO source these fstab options from one source, this is mostly defined in partioning.sh
		echo "$1 /boot vfat	defaults 0 0" >> "${TempDir}"/rootfs/etc/fstab
		echo "$2 / ext4 defaults,noatime,commit=120,errors=remount-ro 0 1" >> "${TempDir}"/rootfs/etc/fstab
		dialog --title "$title" --backtitle "$backtitle" --infobox "\nConverting kernel ... few seconds." 5 60
		mkimage -A arm -O linux -T kernel -C none -a "0x40008000" -e "0x40008000" -n "Linux kernel" -d \
			/boot/zImage "${TempDir}"/bootfs/uImage >/dev/null 2>&1
		cp /boot/script.bin "${TempDir}"/bootfs/

		if [[ $DEVICE_TYPE != a13 ]]; then
			# Note: Not using UUID based boot for NAND
			cat <<-EOF > "${TempDir}"/bootfs/uEnv.txt
			console=ttyS0,115200
			root=$2 rootwait
			extraargs="console=tty1 hdmi.audio=EDID:0 disp.screen0_output_mode=EDID:0 consoleblank=0 loglevel=1"
			EOF
		else
			# Note: Not using UUID based boot for NAND
			cat <<-EOF > "${TempDir}"/bootfs/uEnv.txt
			console=ttyS0,115200
			root=$2 rootwait
			extraargs="consoleblank=0 loglevel=1"
			EOF
		fi

		sync

		[[ $DEVICE_TYPE = a20 ]] && echo "machid=10bb" >> "${TempDir}"/bootfs/uEnv.txt
		# ugly hack becouse we don't have sources for A10 nand uboot
		if [[ $ID == Cubieboard || $BOARD_NAME == Cubieboard || $ID == "Lime A10" || $BOARD_NAME == "Lime A10" ]]; then
			cp "${TempDir}"/bootfs/uEnv.txt "${TempDir}"/rootfs/boot/uEnv.txt
			cp "${TempDir}"/bootfs/script.bin "${TempDir}"/rootfs/boot/script.bin
			cp "${TempDir}"/bootfs/uImage "${TempDir}"/rootfs/boot/uImage
		fi
		umount_device "/dev/nand"
		tune2fs -o journal_data_writeback /dev/nand2 >/dev/null 2>&1
		tune2fs -O ^has_journal /dev/nand2 >/dev/null 2>&1
		e2fsck -f /dev/nand2 >/dev/null 2>&1
	fi

	# Boot from eMMC, root = eMMC or SATA / USB
	#
	if [[ ($2 == ${emmccheck}p* || $1 == ${emmccheck}p*) && $DEVICE_TYPE != uefi ]]; then

		if [[ $2 == ${DISK_ROOT_PART} ]]; then
			local targetuuid=$satauuid
			local choosen_fs=$FilesystemChoosen
			echo "Finalizing: boot from eMMC, rootfs on USB/SATA/NVMe." >> $logfile
			if [[ $eMMCFilesystemChoosen =~ ^(btrfs|f2fs)$ ]]; then
				echo "$emmcuuid	/media/mmcroot  $eMMCFilesystemChoosen	${mountopts[$eMMCFilesystemChoosen]}" >> "${TempDir}"/rootfs/etc/fstab
			fi
		else
			local targetuuid=$emmcuuid
			local choosen_fs=$eMMCFilesystemChoosen
			echo "Finishing full install to eMMC." >> $logfile
		fi

		# fix that we can have one exlude file
		cp -R /boot "${TempDir}"/bootfs
		# old boot scripts
		[[ -f "${TempDir}"/bootfs/boot/boot.cmd ]] && sed -e 's,root='"$root_uuid"',root='"$targetuuid"',g' -i "${TempDir}"/bootfs/boot/boot.cmd
		# new boot scripts
		if [[ -f "${TempDir}"/bootfs/boot/armbianEnv.txt ]]; then
			sed -e 's,rootdev=.*,rootdev='"$targetuuid"',g' -i "${TempDir}"/bootfs/boot/armbianEnv.txt
			grep -q '^rootdev' "${TempDir}"/bootfs/boot/armbianEnv.txt || echo "rootdev=$targetuuid" >> "${TempDir}"/bootfs/boot/armbianEnv.txt
		else
			[[ -f "${TempDir}"/bootfs/boot/boot.cmd ]] && sed -e 's,setenv rootdev.*,setenv rootdev '"$targetuuid"',g' -i "${TempDir}"/bootfs/boot/boot.cmd
			[[ -f "${TempDir}"/bootfs/boot/boot.ini ]] && sed -e 's,^setenv rootdev.*$,setenv rootdev "'"$targetuuid"'",' -i "${TempDir}"/bootfs/boot/boot.ini
			[[ -f "${TempDir}"/rootfs/boot/boot.ini ]] && sed -e 's,^setenv rootdev.*$,setenv rootdev "'"$targetuuid"'",' -i "${TempDir}"/rootfs/boot/boot.ini
		fi

		if [[ -f "${TempDir}"/bootfs/boot/extlinux/extlinux.conf ]]; then
			sed -e 's,root='"$root_uuid"',root='"$targetuuid"',g' -i "${TempDir}"/bootfs/boot/extlinux/extlinux.conf
			[[ -f "${TempDir}"/bootfs/boot/boot.cmd ]] && rm "${TempDir}"/bootfs/boot/boot.cmd
		else
			mkimage -C none -A arm -T script -d "${TempDir}"/bootfs/boot/boot.cmd "${TempDir}"/bootfs/boot/boot.scr	>/dev/null 2>&1 || (echo 'Error while creating U-Boot loader image with mkimage' >&2 ; exit 5)
		fi

		# fstab adj
		if [[ "$1" != "$2" ]]; then
			echo "$emmcbootuuid	/media/mmcboot	ext4    ${mountopts[ext4]}" >> "${TempDir}"/rootfs/etc/fstab
			echo "/media/mmcboot/boot   				/boot		none	bind								0       0" >> "${TempDir}"/rootfs/etc/fstab
		fi
		# if the rootfstype is not defined as cmdline argument on armbianEnv.txt
		if ! grep -qE '^rootfstype=.*' "${TempDir}"/bootfs/boot/armbianEnv.txt; then
			# Add the line of type of the selected rootfstype to the file armbianEnv.txt
			[[ -f "${TempDir}"/bootfs/boot/armbianEnv.txt ]] && echo "rootfstype=$choosen_fs" >> "${TempDir}"/bootfs/boot/armbianEnv.txt
		fi

		if [[ $eMMCFilesystemChoosen =~ ^(btrfs|f2fs)$ ]]; then
			echo "$targetuuid	/		$choosen_fs	${mountopts[$choosen_fs]}" >> "${TempDir}"/rootfs/etc/fstab
			# swap file not supported under btrfs but we might have made a partition
			[[ -n ${emmcswapuuid} ]] && sed -e 's,/var/swap.*,'$emmcswapuuid' 	none		swap	sw								0	0,g' -i "${TempDir}"/rootfs/etc/fstab
			if [[ -f "${TempDir}"/bootfs/boot/armbianEnv.txt ]]; then
			    sed -e 's,rootfstype=.*,rootfstype='$eMMCFilesystemChoosen',g' -i "${TempDir}"/bootfs/boot/armbianEnv.txt
			else
			    echo 'rootfstype='$eMMCFilesystemChoosen >>"${TempDir}"/bootfs/boot/armbianEnv.txt
			fi
		else
			[[ -f "${TempDir}"/bootfs/boot/armbianEnv.txt ]] && sed -e 's,rootfstype=.*,rootfstype='$choosen_fs',g' -i "${TempDir}"/bootfs/boot/armbianEnv.txt
			echo "$targetuuid	/		$choosen_fs	${mountopts[$choosen_fs]}" >> "${TempDir}"/rootfs/etc/fstab
		fi

		if [[ $(type -t write_uboot_platform) != function ]]; then
			echo "Error: no u-boot package found, exiting"
			exit 6
		fi
		write_uboot_platform "$DIR" $emmccheck

	fi

	# Boot from SD card, root = SATA / USB
	#
	if [[ $2 == ${DISK_ROOT_PART} && -z $1 && $DEVICE_TYPE != uefi ]]; then
		echo -e "Finishing transfer to disk, boot from SD/eMMC" >> $logfile
		[[ -f /boot/boot.cmd ]] && sed -e 's,root='"$root_uuid"',root='"$satauuid"',g' -i /boot/boot.cmd
		[[ -f /boot/boot.ini ]] && sed -e 's,^setenv rootdev.*$,setenv rootdev "'"$satauuid"'",' -i /boot/boot.ini
		# new boot scripts
		if [[ -f /boot/armbianEnv.txt ]]; then
			sed -e 's,rootdev=.*,rootdev='"$satauuid"',g' -i /boot/armbianEnv.txt
			grep -q '^rootdev' /boot/armbianEnv.txt || echo "rootdev=$satauuid" >> /boot/armbianEnv.txt
			sed -e 's,rootfstype=.*,rootfstype='$FilesystemChoosen',g' -i /boot/armbianEnv.txt
			grep -q '^rootfstype' /boot/armbianEnv.txt || echo "rootfstype=$FilesystemChoosen" >> /boot/armbianEnv.txt
		else
			sed -e 's,setenv rootdev.*,setenv rootdev '"$satauuid"',' -i /boot/boot.cmd
			sed -e 's,setenv rootdev.*,setenv rootdev '"$satauuid"',' -i /boot/boot.ini
			sed -e 's,setenv rootfstype.*,setenv rootfstype '"$FilesystemChoosen"',' -i /boot/boot.cmd
			sed -e 's,setenv rootfstype.*,setenv rootfstype '"$FilesystemChoosen"',' -i /boot/boot.ini
		fi
		if [[ -f /bootfs/boot/extlinux/extlinux.conf ]]; then
			sed -e 's,root='"$root_uuid"',root='"$satauuid"',g' -i /boot/extlinux/extlinux.conf
			[[ -f /boot/boot.cmd ]] && rm /boot/boot.cmd
		fi
		[[ -f /boot/boot.cmd ]] && mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr >/dev/null 2>&1 || (echo 'Error while creating U-Boot loader image with mkimage' >&2 ; exit 7)
		mkdir -p "${TempDir}"/rootfs/media/mmc/boot
		echo "${sduuid}	/media/mmcboot	ext4    ${mountopts[ext4]}" >> "${TempDir}"/rootfs/etc/fstab
		echo "/media/mmcboot/boot  				/boot		none	bind								0       0" >> "${TempDir}"/rootfs/etc/fstab
		echo "$satauuid	/		$FilesystemChoosen	${mountopts[$FilesystemChoosen]}" >> "${TempDir}"/rootfs/etc/fstab
		# recreate swap file if already existing (might be missing since zram only)
		if [ -f /var/swap ]; then
			fallocate -l 128M "${TempDir}"/rootfs/var/swap || dd if=/dev/zero of="${TempDir}"/rootfs/var/swap bs=1M count=128 status=noxfer
			mkswap "${TempDir}"/rootfs/var/swap
		fi
	fi

	if [[ $2 == ${DISK_ROOT_PART} && -z $1 && $DEVICE_TYPE = uefi ]]; then

		# create swap file size of your memory so we can use it for S4
		MEM_TOTAL=$(cat /proc/meminfo | awk '/MemTotal/ {print $2}')

		# but no more then 16Gb
		[[ ${MEM_TOTAL} -gt 16107868 ]] && MEM_TOTAL=16107868
		dd if=/dev/zero of="${TempDir}"/rootfs/swapfile bs=${MEM_TOTAL} count=1024 conv=notrunc >> $logfile

		mkswap "${TempDir}"/rootfs/swapfile >> $logfile
		chmod 0600 "${TempDir}"/rootfs/swapfile
		sed -i "/^GRUB_CMDLINE_LINUX_DEFAULT=/ s/\"$/ resume=UUID=$(findmnt -no UUID -T "${TempDir}"/rootfs/swapfile) resume_offset=$(filefrag -v "${TempDir}"/rootfs/swapfile |grep " 0:"| awk '{print $4}' | cut -d"." -f1)\"/" "${TempDir}"/rootfs/etc/default/grub.d/98-armbian.cfg

		echo "GRUB_DISABLE_OS_PROBER=false" >> "${TempDir}"/rootfs/etc/default/grub.d/98-armbian.cfg

		echo "$satauuid	/		$FilesystemChoosen	${mountopts[$FilesystemChoosen]}" >> "${TempDir}"/rootfs/etc/fstab
		echo "UUID=$(lsblk -io KNAME,LABEL,UUID,PARTLABEL | grep $diskcheck | grep -i efi | awk '{print $3}')				/boot/efi		vfat	 defaults 0 2" >> "${TempDir}"/rootfs/etc/fstab
		echo "/swapfile none swap sw 0 0" >> "${TempDir}"/rootfs/etc/fstab

		cat <<-hibernatemenu >"${TempDir}"/rootfs/etc/polkit-1/localauthority/50-local.d/com.ubuntu.enable-hibernate.pkla
		[Re-enable hibernate by default in upower]
		Identity=unix-user:*
		Action=org.freedesktop.upower.hibernate
		ResultActive=yes

		[Re-enable hibernate by default in logind]
		Identity=unix-user:*
		Action=org.freedesktop.login1.hibernate;org.freedesktop.login1.handle-hibernate-key;org.freedesktop.login1;org.freedesktop.login1.hibernate-multiple-sessions;org.freedesktop.login1.hibernate-ignore-inhibit
		ResultActive=yes
		hibernatemenu

		efi_partition=$(LC_ALL=C fdisk -l "/dev/$diskcheck" 2>/dev/null | grep "EFI" | awk '{print $1}')

		echo "Install GRUB to $efi_partition"
		mkdir -p "${TempDir}"/rootfs/{dev,proc,sys}
		mount $efi_partition "${TempDir}"/rootfs/boot/efi
		mount --bind /dev "${TempDir}"/rootfs/dev
		mount --make-rslave --bind /dev/pts "${TempDir}"/rootfs/dev/pts
		mount --bind /proc "${TempDir}"/rootfs/proc
		mount --make-rslave --rbind /sys "${TempDir}"/rootfs/sys
		arch_target=$([[ $(arch) == x86_64 ]] && echo "x86_64-efi" || echo "arm64-efi")
		chroot "${TempDir}/rootfs/" /bin/bash -c "grub-install --target=$arch_target --efi-directory=/boot/efi --bootloader-id=Armbian" >> $logfile
		chroot "${TempDir}/rootfs/" /bin/bash -c "grub-mkconfig -o /boot/grub/grub.cfg" >> $logfile
		grep "${TempDir}"/rootfs/sys /proc/mounts | cut -f2 -d" " | sort -r | xargs umount -n
		umount "${TempDir}"/rootfs/proc
		umount "${TempDir}"/rootfs/dev/pts
		umount "${TempDir}"/rootfs/dev
		umount "${TempDir}"/rootfs/boot/efi
	fi




	# Boot from MTD flash, root = SATA / USB
	#
	if [[ $1 == *mtd* ]]; then
		if [[ -f "${TempDir}"/rootfs/boot/armbianEnv.txt ]]; then
			sed -e 's,rootdev=.*,rootdev='"$satauuid"',g' -i "${TempDir}"/rootfs/boot/armbianEnv.txt
		fi
		if [[ -f "${TempDir}"/rootfs/boot/extlinux/extlinux.conf ]]; then
			sed -e 's,root='"$root_uuid"',root='"$satauuid"',g' -i "${TempDir}"/rootfs/boot/extlinux/extlinux.conf
		fi
		echo "$satauuid	/		$FilesystemChoosen	${mountopts[$FilesystemChoosen]}" >> "${TempDir}"/rootfs/etc/fstab
	fi

	# recreate OMV mounts at destination if needed
	grep -q ' /srv/' /etc/fstab
	if [ $? -eq 0 -a -f /etc/default/openmediavault ]; then
		echo -e '# >>> [openmediavault]' >> "${TempDir}"/rootfs/etc/fstab
		grep ' /srv/' /etc/fstab | while read ; do
			echo "${REPLY}" >> "${TempDir}"/rootfs/etc/fstab
			mkdir -p -m700 "${TempDir}/rootfs$(awk -F" " '{print $2}' <<<"${REPLY}")"
		done
		echo -e '# <<< [openmediavault]' >> "${TempDir}"/rootfs/etc/fstab
	fi

	echo -e "\nChecking again for open files:" >> $logfile
	lsof / | awk 'NR==1 || $4~/[0-9][uw]/' | grep -v "^COMMAND" >> $logfile
	LANG=C echo -e "\n$(date): Finished\n\n" >> $logfile
	cat $logfile > "${TempDir}"/rootfs${logfile}
	sync

	umount "${TempDir}"/rootfs
	mountpoint -q "${TempDir}"/bootfs && umount "${TempDir}"/bootfs
} # create_armbian



# Accept device as parameter: for example /dev/sda unmounts all their mounts
umount_device()
{
	if [[ -n $1 ]]; then
		device="$1";
		for n in ${device}*; do
			if [[ $device != "$n" ]]; then
				if mount|grep -q "$n"; then
					umount -l "$n" >/dev/null 2>&1
				fi
			fi
		done
	fi
} # umount_device

show_nand_warning()
{
	local temp_rc=$(mktemp)
	cat <<-'EOF' > $temp_rc
	screen_color = (WHITE,RED,ON)
	EOF
	local warn_text="You are installing the system to sunxi NAND.

	This is not recommended as NAND has \Z1worse performance
	and reliability\Zn than a good SD card.

	You have been warned."

	DIALOGRC=$temp_rc dialog --title "NAND warning" --backtitle "$backtitle" --colors \
		--ok-label "I understand and agree" --msgbox "$warn_text" 10 70
}

# formatting sunxi NAND - no parameters, fixed solution.
#
format_nand()
{
	[[ ! -e /dev/nand ]] && echo '/dev/nand does not exist' >&2 && exit 8

	show_nand_warning

	dialog --title "$title" --backtitle "$backtitle" --infobox "\n            Formatting ... up to one minute." 5 60
	if [[ $DEVICE_TYPE = a20 ]]; then
		(echo y;) | sunxi-nand-part -f a20 /dev/nand 65536 'bootloader 65536' 'linux 0' >> $logfile 2>&1
	else
		(echo y;) | sunxi-nand-part -f a10 /dev/nand 65536 'bootloader 65536' 'linux 0' >> $logfile 2>&1
	fi

	mkfs.vfat /dev/nand1 >> $logfile 2>&1
	mkfs.ext4 -qF /dev/nand2 >> $logfile 2>&1
}


# formatting eMMC [device] example /dev/mmcblk1 - one can select filesystem type
#
format_emmc()
{
	# choose and create fs
	IFS=" "
	BTRFS=$(grep -o btrfs /proc/filesystems)
	FilesystemTargets="1 ext4 2 f2fs"
	[[ -n $BTRFS && ! `uname -r | grep '^3.' ` ]] && FilesystemTargets=$FilesystemTargets" 3 $BTRFS"
	FilesystemOptions=($FilesystemTargets)

	FilesystemCmd=(dialog --title "Select filesystem type for eMMC $1" --backtitle "$backtitle" --menu "\n$infos" 10 60 16)
	FilesystemChoices=$("${FilesystemCmd[@]}" "${FilesystemOptions[@]}" 2>&1 >/dev/tty)

	[[ $? -ne 0 ]] && exit 9
	eMMCFilesystemChoosen=${FilesystemOptions[(2*$FilesystemChoices)-1]}

	# deletes all partitions on eMMC drive
	dd bs=1 seek=446 count=64 if=/dev/zero of="$1" >/dev/null 2>&1
	# calculate capacity and reserve some unused space to ease cloning of the installation
	# to other media 'of the same size' (one sector less and cloning will fail)
	QUOTED_DEVICE=$(echo "$1" | sed 's:/:\\\/:g')
	CAPACITY=$(parted "$1" unit s print -sm | awk -F":" "/^${QUOTED_DEVICE}/ {printf (\"%0d\", \$2 / ( 1024 / \$4 ))}")

	# We use 16MiB to align partitions which may overestimate the erase block
	# size of a NAND device. Overestimating is harmless. (512 byte
	# sectors, so we use 32768 as divider and substract 1)
	if [[ $CAPACITY -lt 4000000 ]]; then
		# Leave 2 percent unpartitioned when eMMC size is less than 4GB (unlikely)
		LASTSECTOR=$(( 32768 * $(parted "$1" unit s print -sm | awk -F":" "/^${QUOTED_DEVICE}/ {printf (\"%0d\", ( \$2 * 98 / 3276800))}") -1 ))
	else
		# Leave 1 percent unpartitioned
		LASTSECTOR=$(( 32768 * $(parted "$1" unit s print -sm | awk -F":" "/^${QUOTED_DEVICE}/ {printf (\"%0d\", ( \$2 * 99 / 3276800))}") -1 ))
	fi

	# get target partition table type from the root partition device
	PART_TABLE_TYPE=$(parted "$root_partition_device" print -sm | awk -F ":" -v pattern="$root_partition_device" '$0 ~ pattern {print $6}')

	parted -s "$1" -- mklabel "$PART_TABLE_TYPE"
	dialog --title "$title" --backtitle "$backtitle" --infobox "\nFormating $1 to $eMMCFilesystemChoosen ... please wait." 5 60
	# we can't boot from btrfs or f2fs
	if [[ $eMMCFilesystemChoosen =~ ^(btrfs|f2fs)$ ]]; then
		local partedFsType="${eMMCFilesystemChoosen}"
		if [[ $eMMCFilesystemChoosen == "f2fs" ]]; then
			partedFsType=''
		fi

		# default boot partition size, in MiB
		DEFAULT_BOOTSIZE=512

		# (convert to sectors for partitioning)
		DEFAULT_BOOTSIZE_SECTORS=$(((${DEFAULT_BOOTSIZE} * 1024 * 1024) / 512))

		# check if the filesystem tools are actually installed
		if ! command -v mkfs.${eMMCFilesystemChoosen} >/dev/null 2>&1; then
			echo "Error: Filesystem tools for ${eMMCFilesystemChoosen} not installed, exiting"
			exit 9
		fi

		# check whether swap is currently defined and a new swap partition is needed
		grep -q swap /etc/fstab
		case $? in
			0)
				parted -s "$1" -- mkpart primary $partedFsType ${FIRSTSECTOR}s $(( ${FIRSTSECTOR} + ${DEFAULT_BOOTSIZE_SECTORS} - 1 ))s
				parted -s "$1" -- mkpart primary $partedFsType $(( ${FIRSTSECTOR} + ${DEFAULT_BOOTSIZE_SECTORS} ))s $(( ${FIRSTSECTOR} + 393215 ))s
				parted -s "$1" -- mkpart primary $partedFsType $(( ${FIRSTSECTOR} + 393216 ))s ${LASTSECTOR}s
				partprobe "$1"
				mkfs.ext4 ${mkopts[ext4]} "$1"'p1' >> $logfile 2>&1
				mkswap "$1"'p2' >> $logfile 2>&1
				mkfs.${eMMCFilesystemChoosen} "$1"'p3' ${mkopts[$eMMCFilesystemChoosen]} >> $logfile 2>&1
				emmcbootuuid=$(blkid -o export "$1"'p1' | grep -w UUID)
				emmcswapuuid=$(blkid -o export "$1"'p2' | grep -w UUID)
				emmcuuid=$(blkid -o export "$1"'p3' | grep -w UUID)
				dest_root=$emmccheck'p3'
				;;
			*)
				parted -s "$1" -- mkpart primary $partedFsType ${FIRSTSECTOR}s $(( ${FIRSTSECTOR} + ${DEFAULT_BOOTSIZE_SECTORS} - 1 ))s
				parted -s "$1" -- mkpart primary $partedFsType $(( ${FIRSTSECTOR} + ${DEFAULT_BOOTSIZE_SECTORS} ))s ${LASTSECTOR}s
				partprobe "$1"
				mkfs.ext4 ${mkopts[ext4]} "$1"'p1' >> $logfile 2>&1
				mkfs.${eMMCFilesystemChoosen} "$1"'p2' ${mkopts[$eMMCFilesystemChoosen]} >> $logfile 2>&1
				emmcbootuuid=$(blkid -o export "$1"'p1' | grep -w UUID)
				emmcuuid=$(blkid -o export "$1"'p2' | grep -w UUID)
				dest_root=$emmccheck'p2'
				;;
		esac
	else
		parted -s "$1" -- mkpart primary $eMMCFilesystemChoosen ${FIRSTSECTOR}s ${LASTSECTOR}s
		partprobe "$1"
		mkfs.${eMMCFilesystemChoosen} ${mkopts[$eMMCFilesystemChoosen]} "$1"'p1' >> $logfile 2>&1
		emmcuuid=$(blkid -o export "$1"'p1' | grep -w UUID)
		emmcbootuuid=$emmcuuid
	fi
}


# formatting SATA/USB/NVMe partition, examples: /dev/sda3 or /dev/nvme0n1p1
#
format_disk()
{
	# choose and create fs
	IFS=" "
	ROOTFSTYPE=$(lsblk -o MOUNTPOINT,FSTYPE | awk -F" " '/^\/\ / {print $2}')
	case ${ROOTFSTYPE} in
		btrfs)
			FilesystemTargets='1 btrfs'
			;;
		*)
			BTRFS=$(grep -o btrfs /proc/filesystems)
			FilesystemTargets='1 ext4'
			[[ -n $BTRFS && ! `uname -r | grep '^3.' ` && $choice != 6 ]] && FilesystemTargets=$FilesystemTargets" 2 $BTRFS"
			;;
	esac
	FilesystemOptions=($FilesystemTargets)

	FilesystemCmd=(dialog --title "Select filesystem type for $1" --backtitle "$backtitle" --menu "\n$infos" 10 60 16)
	FilesystemChoices=$("${FilesystemCmd[@]}" "${FilesystemOptions[@]}" 2>&1 >/dev/tty)

	[[ $? -ne 0 ]] && exit 10
	FilesystemChoosen=${FilesystemOptions[(2*$FilesystemChoices)-1]}

	dialog --title "$title" --backtitle "$backtitle" --infobox "\nFormating $1 to $FilesystemChoosen ... please wait." 5 60
	mkfs.${FilesystemChoosen} ${mkopts[$FilesystemChoosen]} "$1" >> $logfile 2>&1
}


# choose target SATA/USB/NVMe partition.
check_partitions()
{
	IFS=" "
	[[ -n "$1" ]] && EXCLUDE=" | grep -v $1"
	[[ -n "$2" ]] && INCLUDE=" | grep $2" && diskcheck=$2
	CMD="lsblk -io KNAME,FSTYPE,SIZE,TYPE,MOUNTPOINT | grep -v -w $root_partition_name $INCLUDE $EXCLUDE | grep -E '^sd|^nvme|^md|^mmc' | awk -F\" \" '/ part | raid..? / {print \$1}'"
	AvailablePartitions=$(eval $CMD)

	FREE_SPACE=$(sfdisk --list-free /dev/$diskcheck | grep G | tail -1 | awk '{print $4}' | sed "s/G//")

	dialog --yes-label "Proceed" --no-label 'Skip' --title "$title" --backtitle "$backtitle" --yesno "\nIt is highly recommended to wipe all partitions on the destination disk\n \n/dev/$diskcheck\n\nand leave installer to make them!" 10 75

	# wiping destination to make sure we don't run into issues
	if [[ $? -eq 0 ]]; then
		exec 3>&1
			ACKNOWLEDGEMENT=$(dialog --colors --nocancel --backtitle "$BACKTITLE" --no-collapse --title " Warning " \
			--clear \--radiolist "\nTHIS OPERATION WILL WIPE ALL DATA ON DRIVE:\n\n/dev/$diskcheck\n " 0 56 4 "Yes, I understand" "" off       2>&1 1>&3)
		exec 3>&-
		if [[ "${ACKNOWLEDGEMENT}" == "Yes, I understand" ]]; then
			dd if=/dev/zero of=/dev/${diskcheck} bs=1M count=10 >> $logfile 2>&1
			partprobe -s "/dev/${diskcheck}" >> $logfile 2>&1
			# only make one ext4 partition if we don't have UEFI
			if [[ "$DEVICE_TYPE" != uefi ]]; then
				echo -e 'mktable gpt\nmkpart primary ext4 0% 100%\nquit' | sudo parted "/dev/${diskcheck}" >> $logfile 2>&1
				sudo partprobe -s "/dev/${diskcheck}" >> $logfile 2>&1
				sleep 2
			fi
		fi
	fi

	if [[ -z $AvailablePartitions ]] || [[ "${FREE_SPACE%.*}" -gt 4 ]]; then
		# Consider brand new devices or devices with a wiped partition table
		if [[ -z $(blkid /dev/$diskcheck) ]]; then
			# There is not yet any partition table on the disk device.
			# => we have to calc the size in GB directly from the device.
			FREE_SPACE=$(echo "scale=0; $(blockdev --getsize64 /dev/$diskcheck)/1024^3" | bc -l)
		else
			# The device has an initial partition table
			FREE_SPACE=$(parted /dev/$diskcheck unit GB print free | awk '/Free Space/{c++; sum += $3; print sum}' | tail -1)
		fi
		# Logic for auto created partitions:
		#  1. Check for a minimum free space of 4GB for a partition
		#  2. Ask user to proceed with auto-created partition(s) or not
		#  3. Distinguish between UEFI and non UEFI device
		#  4. Create partition of full free size for a non UEFI device
		#
		if [[ "${FREE_SPACE%.*}" -lt 4 ]]; then
			dialog --ok-label 'Exit' --title ' Warning ' --backtitle "$backtitle" --colors --no-collapse --msgbox "\n\Z1There is not enough free capacity on /dev/$diskcheck. Please check your device.\Zn" 7 52
			exit 11
		fi
		dialog --yes-label "Proceed" --no-label 'Exit' --title "$title" --backtitle "$backtitle" --yesno "\nDestination $diskcheck has ${FREE_SPACE}GB of available space. \n\nAutomated install will generate needed partition(s)!" 9 55
		[[ $? -ne 0 ]] && exit 11
		if [[ "$DEVICE_TYPE" == uefi ]]; then
			if [[ -z "$efi_partition" ]]; then
				wipefs -aq /dev/$diskcheck
				# create EFI partition
				{
					echo n; echo ; echo ; echo ; echo +200M;
					echo t; echo EF; echo w;
				} | fdisk /dev/$diskcheck &> /dev/null || true
				yes | mkfs.vfat /dev/${diskcheck}p1 &> /dev/null || true
				fatlabel /dev/${diskcheck}p1 EFI
			fi
			{
				echo n; echo ; echo ; echo ; echo
				echo w
			} | fdisk /dev/$diskcheck &> /dev/null || true
			yes | mkfs.ext4 /dev/${diskcheck}p2 &> /dev/null || true

			# re-read
			emmccheck=$(ls -d -1 /dev/mmcblk* 2>/dev/null | grep -w 'mmcblk[0-9]' | grep -v "$root_partition_device");
			efi_partition=$(LC_ALL=C fdisk -l "/dev/$diskcheck" 2>/dev/null | grep "EFI" | awk '{print $1}')
		else
			# Create new partition of max free size
			{
				echo n; echo ; echo ; echo ; echo
				echo w
			} | fdisk /dev/$diskcheck &> /dev/null || true
		fi
	fi
	CMD="lsblk -io KNAME,FSTYPE,SIZE,TYPE,MOUNTPOINT,PARTTYPENAME | grep -v -w $root_partition_name $INCLUDE $EXCLUDE | grep Linux | grep -E '^sd|^nvme|^md|^mmc' | awk -F\" \" '/ part | raid..? / {print \$1}' | uniq | sed 's|^|/dev/|' | nl | xargs echo -n"
	partprobe
	AvailablePartitions=$(eval $CMD)
	PartitionOptions=($AvailablePartitions)

	PartitionCmd=(dialog --title 'Select the destination:' --backtitle "$backtitle" --menu "\n$infos" 10 60 16)
	PartitionChoices=$("${PartitionCmd[@]}" "${PartitionOptions[@]}" 2>&1 >/dev/tty)

	[[ $? -ne 0 ]] && exit 11
	DISK_ROOT_PART=${PartitionOptions[(2*$PartitionChoices)-1]}
}

# build and update new bootscript
update_bootscript()
{
	if [ -f /boot/boot.cmd.new ]; then
		mv -f /boot/boot.cmd.new /boot/boot.cmd >/dev/null 2>&1
		mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr  >/dev/null 2>&1
	elif [ -f /boot/boot.ini.new ]; then
		mv -f /boot/boot.ini.new /boot/boot.ini >/dev/null 2>&1
		rootdev=$(sed -e 's/^.*root=//' -e 's/ .*$//' < /proc/cmdline)
		rootfstype=$(sed -e 's/^.*rootfstype=//' -e 's/ .*$//' < /proc/cmdline)
		sed -i "s/setenv rootfstype.*/setenv rootfstype \"$rootfstype\"/" /boot/boot.ini
		sed -i "s/setenv rootdev.*/setenv rootdev \"$rootdev\"/" /boot/boot.ini
	fi
}

# show warning [TEXT]
show_warning()
{
	dialog --title "$title" --backtitle "$backtitle" --cr-wrap --colors --yesno " \Z1$(toilet -W -f ascii9 ' WARNING')\Zn\n$1" 16 67
	[[ $? -ne 0 ]] && exit 13
}

# try to stop running services
stop_running_services()
{
	systemctl --state=running | awk -F" " '/.service/ {print $1}' | sort -r | \
		grep -E -e "$1" | while read ; do
		echo -e "\nStopping ${REPLY} \c"
		systemctl stop ${REPLY} 2>&1
	done
}

# show warning and write u-boot to MTD device(s)
#  $1 = u-boot files directory
#  $2 = space separated list of all MTD block and/or MTD char device partitions
write_uboot_to_mtd_flash()
{
	local DIR="$1"
	local MTD_ALL_DEVICE_PARTITIONS="$2"
	# For backward compatibility to existing implementations of function write_uboot_platform_mtd
	# we have to provide the first device as a dedicated device path:
	local MTD_DEFAULT_DEVICE_PATH="/dev/${MTD_ALL_DEVICE_PARTITIONS%% *}"
	# If the first device is a char device partition, it contains a :colon:
	# -> so we have to take the part before the colon only
	MTD_DEFAULT_DEVICE_PATH="${MTD_DEFAULT_DEVICE_PATH%%:*}"
	local MESSAGE="This script will update the bootloader on one or multiple of these MTD devices:\n[ $MTD_ALL_DEVICE_PARTITIONS ]\n\nIt may take up to a few minutes - Continue?"
	dialog --title "$title" --backtitle "$backtitle" --cr-wrap --colors --yesno " \Z1$(toilet -W -f ascii9 ' WARNING')\Zn\n$MESSAGE" 19 67
	if [[ $? -eq 0 ]]; then
		write_uboot_platform_mtd "$DIR" "$MTD_DEFAULT_DEVICE_PATH" "$logfile" "$MTD_ALL_DEVICE_PARTITIONS"
		update_bootscript
		echo 'Done'
	fi
}

main()
{
	export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

	# This tool must run under root
	if [[ $EUID -ne 0 ]]; then
		echo 'This tool must run as root. Exiting ...' >&2
		exit 14
	fi

	[ -f $logfile ] && echo -e '\n\n\n' >> $logfile
	LANG=C echo -e "$(date): Start ${0##*/}.\n" >> $logfile

	# find real mmcblk device numbered 0, 1, 2 for eMMC, SD
	# On some devices, the eMMC chip does not have a separate boot0(1) partition.
	# Use the system interface to determine the SD or eMMC memory type.
	for ret in $(find /dev -name 'mmcblk[0-2]' -and -type b)
	do
		if [ -b ${ret}boot0 ] || \
		   [ "$(cat /sys/block/${ret#/dev/}/device/type 2>/dev/null)" == "MMC" ]; then
			emmc_dev=$ret
		elif [ "$(cat /sys/block/${ret#/dev/}/device/type 2>/dev/null)" == "SD" ]; then
			sd_dev=$ret
		fi
	done

	IFS="'"
	options=()

	if [[ -n $emmccheck ]]; then
		if [[ "${emmccheck}" == "$sd_dev" ]]; then
			ichip='SD card'
		elif [[ "${emmccheck}" == "$emmc_dev" ]]; then
			ichip='eMMC'
		fi
		dest_boot=$emmccheck'p1'
		dest_root=$emmccheck'p1'
	elif [ -b /dev/nand1 ] && [ -b /dev/nand2 ]; then
		ichip='legacy SUNXI NAND'
		dest_boot='/dev/nand1'
		dest_root='/dev/nand2'
	fi

	if [[ -n $diskcheck && -d /sys/firmware/efi ]]; then

		while read line
		do
			options+=("$line" "Install UEFI system with Grub")
		done <<< "$diskcheck"

	else

		[[ -n $sduuid && -n $diskcheck ]]		&& options+=(1 'Boot from SD - system on SATA, USB or NVMe')
		[[ -n $emmccheck ]] 				&& options+=(2 "Boot from $ichip - system on $ichip")
		[[ -n $emmccheck && -n $diskcheck ]] 		&& options+=(3 "Boot from $ichip - system on SATA, USB or NVMe")
		[[ -n $mtdcheck ]] 				&& options+=(4 'Boot from MTD Flash - system on SATA, USB or NVMe')

		if [[ -n ${root_partition_device} && ${DEVICE_TYPE} != "uefi" ]]; then
			if [ "${root_partition_device}" == "$sd_dev" ]; then
				rootchip='SD card'
			elif [ "${root_partition_device}" == "$emmc_dev" ]; then
				rootchip='eMMC'
			fi
			options+=(5 "Install/Update the bootloader on $rootchip (${root_partition_device})")
                fi

		if [ -n "${emmc_dev}" ] && [ "${emmc_dev}" != "${root_partition_device}" ]; then

			options+=(6 "Install/Update the bootloader on eMMC (${emmc_dev})")
			BOOTPART=${emmc_dev}

		elif [ -n "${sd_dev}" ] && [ "${sd_dev}" != "${root_partition_device}" ]; then

			options+=(6 "Install/Update the bootloader on SD card (${sd_dev})")
			BOOTPART=${sd_dev}
		fi

		[[ -n $mtdcheck && \
		$(type -t write_uboot_platform_mtd) == function ]] 		&& options+=(7 'Install/Update the bootloader on MTD Flash')
	fi

	[[ ${#options[@]} -eq 0 || "$root_uuid" == "$emmcuuid" || "$root_uuid" == "/dev/nand2" ]] && \
	dialog --ok-label 'Cancel' --title ' Warning ' --backtitle "$backtitle" --colors --no-collapse --msgbox '\n\Z1There are no targets. Please check your drives.\Zn' 7 52
	cmd=(dialog --title 'Choose an option:' --backtitle "$backtitle" --menu "\nCurrent root: $root_uuid \n              $rootchip (${root_partition_device})\n" 14 75 7)
	choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty)
	[[ $? -ne 0 ]] && exit 16

	for choice in $choices
	do
		case $choice in
			1)
				title='MMC (SD/eMMC) boot | USB/SATA/NVMe root install'
				command='Reboot'
				check_partitions
				show_warning "This script will erase your device $DISK_ROOT_PART. Continue?"
				format_disk "$DISK_ROOT_PART"
				create_armbian "" "$DISK_ROOT_PART"
				;;
			2)
				title="$ichip install"
				command='Power off'
				show_warning "This script will erase your $ichip ($emmccheck).\n     Continue?"
				if [[ -n $emmccheck ]]; then
					umount_device "$emmccheck"
					format_emmc "$emmccheck"
				elif [ -b /dev/nand ]; then
					umount_device '/dev/nand'
					format_nand
				fi
				create_armbian "$dest_boot" "$dest_root"
				;;
			3)
				title="$ichip boot | USB/SATA/NVMe root install"
				command='Power off'
				check_partitions
				show_warning "This script will erase your ${ichip} ($emmccheck)\n    and $DISK_ROOT_PART. Continue?"
				if [[ -n $emmccheck ]]; then
					umount_device "$emmccheck"
					format_emmc "$emmccheck"
				elif [ -b /dev/nand ]; then
					umount_device '/dev/nand'
					format_nand
				fi
				umount_device "${DISK_ROOT_PART//[0-9]*/}"
				format_disk "$DISK_ROOT_PART"
				create_armbian "$dest_boot" "$DISK_ROOT_PART"
				;;
			4)
				# Espressobin has flash boot by default
				title='MTD Flash boot | USB/SATA/NVMe root install'
				command='Power off'
				# we need to copy boot
				sed -i '/boot/d' $EX_LIST
				check_partitions
				show_warning "This script will erase your device $DISK_ROOT_PART. Continue?"
				format_disk "$DISK_ROOT_PART"
				create_armbian 'mtd' "$DISK_ROOT_PART"

				if [[ $(type -t write_uboot_platform_mtd) == function ]]; then
					dialog --title "$title" --backtitle "$backtitle" --yesno \
						"Do you want to write the bootloader to MTD Flash?\n\nIt is required if you have not done it before or if you have some non-Armbian bootloader in this flash." 8 60

					if [[ $? -eq 0 ]]; then
						write_uboot_to_mtd_flash "$DIR" "$mtdcheck"
					fi
				fi
				;;
			5)
				show_warning "This script will update the bootloader on ${root_partition_device}.\n\n    Continue?"
				write_uboot_platform "$DIR" "${root_partition_device}"
				update_bootscript
				dialog --backtitle "$backtitle" --title 'Writing bootloader' --msgbox '\n          Done.' 7 30
				return
				;;
			6)
				show_warning "This script will update the bootloader on ${BOOTPART}.\n\n    Continue?"
				write_uboot_platform "$DIR" ${BOOTPART}
				echo 'Done'
				return
				;;
			7)
				write_uboot_to_mtd_flash "$DIR" "$mtdcheck"
				return
				;;

			*)
                                title='UEFI install to internal drive'
                                command='Reboot'
                                check_partitions "$root_partition_device_name" "$choice"
                                # we need to copy boot
                                sed -i '/boot/d' $EX_LIST
                                show_warning "This script will erase your device $DISK_ROOT_PART. Continue?"
                                format_disk "$DISK_ROOT_PART"
                                create_armbian "" "$DISK_ROOT_PART" "$choice"
                                ;;
		esac
	done

	dialog --title "$title" --backtitle "$backtitle" --yes-label "$command" --no-label 'Exit' --yesno "\nAll done. $command $REMOVESDTXT" 7 70
	[[ $? -eq 0 ]] && "$(echo ${command,,} | sed 's/ //')"
} # main

main "$@"
