#!/bin/bash
#  vim:sw=8:noet
# SPDX-License-Identifier:  GPL-2.0-or-later
#
# rootfs installer for ALT Linux
# Current version
VERSION=0.7.2

# Variable
EXT4=0FC63DAF-8483-4772-8E79-3D69D8477DE4
DEFAULT_EXT4_OPTIONS="-m 5 -b 4096 -i 8192 -I 256"
TMPROOT=
[ -n "$TMP" ] || TMP=/tmp
PROGNAME="${0##*/}"
unset ROOTPART_UID

# one Mebibyte = 2^20
MB=1048576

# usage message
usage() {
	echo "
Usage: $PROGNAME --target=TARGET <--rootfs=ROOTFS | --image-in=IMAGE> <--media=DEVICE | --image-out=FILE> [options]

Options:
    --target=TARGET      - target board
    --extra-options      - path to file with extra options (see extra-options)
    --efi                - add EFI partition, set partition table gpt
    --efi-mbr            - add EFI partition, set partition table msdos
    --bootpart           - add boot partition
    --root-fstype=TYPE   - specify root partition filesystem
    --root-fs-opt=OPTSTR - root filesystem options
    --vnc=1              - enable vnc mode for alterator-setup
    --vnc=0              - disable vnc mode for alterator-setup

    --rootfs=ROOTFS      - archive rootfs file name
    --image-in=IMAGE     - image file name (img|img.xz)

    --media=DEVICE       - media device file (/dev/[sdX|mmcblkX])
    --image-out=FILE     - out image file

    --luks               - encrypt root partition
    --luks-opt=OPTSTR    - options for luks creation

    --addconsole         - Add system serial console

    --image-size=SIZE    - size out image file (MiB)
    --resize             - Resize ROOT partition
    --supported          - List of supported hardware
    --version            - Display version and exit
    --stdout             - Don't use log file, put everything to stdout
    --log=FILE           - Log file (default $LOG_FILE)
    -y                   - Assumes yes, will not wait for confirmation

Example: $PROGNAME --rootfs=regular-lxqt-20190213-aarch64.tar.xz --target=orangepi_prime --media=/dev/mmcblk0

Update U-Boot for another Target
Update to a new u-boot from a local host install.

Example: $PROGNAME --target=orangepi_prime --media=/dev/mmcblk0

" >&2
}

pre_exit() {
	local rc=$?
	trap - EXIT
	sync

	unmount_chroot
	unmount_partition

	if [ -n "$IMAGE_OUT" -a -n "$MEDIA" ]; then
		kpartx -d -s "$MEDIA" || {
			sleep 10
			kpartx -d -s -v "$MEDIA"
		}
		losetup --detach "$MEDIA"
	fi
	exit $rc
}

final_exit() {
	printn 'Installation Complete!'
	if [ -n "$IMAGE_OUT" ]; then
		printn 'Image created successfully.'
	else
		printn 'Insert into your device and try boot.'
		printn 'Good luck!!!'
	fi
	exit 0
}

DIR="$(dirname $0)"
. shell-error 2>/dev/null || . $DIR/shell-error 2>/dev/null
. shell-terminfo 2>/dev/null || . $DIR/shell-terminfo 2>/dev/null
. shell-config 2>/dev/null || . $DIR/shell-config 2>/dev/null

# Set some global variables for the command directory, target board directory,
# and valid targets.
[ -d "${DIR}/boards.d" ] ||
	DIR=/usr/share/alt-rootfs-installer
[ -d "${DIR}/boards.d" ] ||
	fatal "error: directory boards.d not exist"
BOARDDIR="${DIR}/boards.d"
SOCSDIR="${DIR}/socs.d"

# missing or wrongs arguments
[ $# -ge 1 ] &&
TMPARGS="$(getopt -n "$0" -o hy -l addconsole,debug,help,\
efi,efi-mbr,bootpart,root-fstype:,root-fs-opt:,target:,rootfs:,\
media:,image-in:,image-out:,luks,luks-opt:,image-size:,resize,supported,\
version,stdout,log:,vnc,\
extra-options: -- "$@")"
if [ $? -ne 0 ]; then
	usage
	exit 1
fi

eval set -- "$TMPARGS"
# check the args
while :; do
	case $1 in
		--)
			shift; break
			;;
		--addconsole)
			CONSOLE=1
			;;
		--debug)
			set -x
			;;
		-h|--help)
			usage; exit 0
			;;
		--target)
			shift; TARGET="$1"
			;;
		--extra-options)
			shift; EXTRA_OPTIONS="$1"
			;;
		--efi)
			EFI="1"
			MEDIATABLE=gpt
			;;
		--efi-mbr)
			EFI="1"
			MEDIATABLE=msdos
			;;
		--luks-opt)
			shift; LUKS_OPT="$1"
			;;
		--luks)
			LUKS="1"
			;;
		--bootpart)
			ADD_BOOTPART="1"
			;;
		--root-fstype)
			shift; ROOT_FSTYPE="$1"
			;;
		--root-fs-opt)
			shift; ROOT_FS_OPT="$1"
			;;
		--vnc)
			shift; VNC="$1"
			;;
		--rootfs)
			shift; ROOTFS="$1"
			;;
		--image-in)
			shift; IMAGE="$1"
			;;
		--media)
			shift; MEDIA="$1"
			;;
		--image-out)
			shift; IMAGE_OUT="$1"
			;;
		--image-size)
			shift; IMAGE_SIZE="$1"
			;;
		--resize)
			RESIZE="1"
			;;
		--supported)
			cat "$DIR/SUPPORTED-BOARDS"
			exit 0
			;;
		--version)
			echo "$PROGNAME-$VERSION"
			exit 0
			;;
		--log)
			shift
			LOG_FILE="$(readlink -f "$1")"
			;;
		--stdout)
			LOG_MODE="con"
			;;
		-y)
			NOASK=1
			;;
		*)
			echo "Invalid argument $1"
			usage
			exit 1
			;;
	esac
	shift
done

if [ -n "$TARGET" ]; then
	# check board script target
	if [ ! -s  "$BOARDDIR/$TARGET" ]; then
		fatal "error: $TARGET is not supported"
	fi
fi

if [ -z $ROOT_FSTYPE ]; then
	ROOT_FSTYPE=ext4
fi

if [ -z "$ROOT_FS_OPT" ]; then
	if [ "$ROOT_FSTYPE" = ext4 ]; then
		ROOT_FS_OPT=$DEFAULT_EXT4_OPTIONS
	fi
fi

if [ $ROOT_FSTYPE = "f2fs" ]; then
	# U-Boot doesn't support f2fs, so /boot
	# with compatible filesystem is needed.
	ADD_BOOTPART="1"
	# Force overwrite existing filesystem
	ROOT_FS_OPT=$ROOT_FS_OPT" -f"
fi

if [ -n "$EXTRA_OPTIONS" ]; then
	[ -s "$EXTRA_OPTIONS" ] || fatal "error: file $EXTRA_OPTIONS does not exist!!!"
	DEFAULT_KERNEL="$(shell_config_get "$EXTRA_OPTIONS" "DEFAULT_KERNEL")"
	FAST_BOOT="$(shell_config_get "$EXTRA_OPTIONS" "FAST_BOOT")"
	BOOT_TIMEOUT="$(shell_config_get "$EXTRA_OPTIONS" "BOOT_TIMEOUT")"
	RPM_INSTALL="$(shell_config_get "$EXTRA_OPTIONS" "RPM_INSTALL")"
	ROOT_PASSWD="$(shell_config_get "$EXTRA_OPTIONS" "ROOT_PASSWD")"
	USER_PASSWD="$(shell_config_get "$EXTRA_OPTIONS" "USER_PASSWD")"
	USER_NAME="$(shell_config_get "$EXTRA_OPTIONS" "USER_NAME")"
	INITRD_OEM="$(shell_config_get "$EXTRA_OPTIONS" "INITRD_OEM")"
	UBOOT="$(shell_config_get "$EXTRA_OPTIONS" "UBOOT")"
	ADDON="$(shell_config_get "$EXTRA_OPTIONS" ADDON)"
	SYSCON="$(shell_config_get "$EXTRA_OPTIONS" "SYSCON")"
	DTB_FILE="$(shell_config_get "$EXTRA_OPTIONS" "DTB_FILE")"
	DTB_VENDOR="$(shell_config_get "$EXTRA_OPTIONS" "DTB_VENDOR")"
	DTB_KVER="$(shell_config_get "$EXTRA_OPTIONS" "DTB_KVER")"
fi

# getting full PATH
[ -n "$ROOTFS" ] && ROOTFS_PATH="$(readlink -f "$ROOTFS")"
[ -n "$IMAGE" ] && IMAGE_PATH="$(readlink -f "$IMAGE")"
[ -n "$ROOT_PASSWD" ] && ROOT_PASSWD_PATH="$(readlink -f "$ROOT_PASSWD")"
[ -n "$USER_PASSWD" ] && USER_PASSWD_PATH="$(readlink -f "$USER_PASSWD")"
[ -n "$ADDON" ] && ADDON_PATH="$(readlink -f "$ADDON")"
[ -n "$UBOOT" ] && UBOOT_PATH="$(readlink -f "$UBOOT")"
[ -n "$RPM_INSTALL" ] && RPM_INSTALL_PATH="$(readlink -f "$RPM_INSTALL")"
[ -n "$DTB_FILE" ] && DTB_FILE_PATH="$(readlink -f "$DTB_FILE")"

# checking files existing
if [ -n "$ROOTFS" ]; then
	[ -f "$ROOTFS_PATH" ] || fatal "error: ROOTFS does not exist"
	ROOTFS="$ROOTFS_PATH"
fi
if [ -n "$IMAGE" ]; then
	[ -f "$IMAGE_PATH" ] || fatal "error: IMAGE does not exist"
	IMAGE="$IMAGE_PATH"
fi
if [ -n "$ROOT_PASSWD" ]; then
	[ -f "$ROOT_PASSWD_PATH" ] || fatal "error: file $ROOT_PASSWD does not exist"
	ROOT_PASSWD="$ROOT_PASSWD_PATH"
fi
if [ -n "$USER_PASSWD" ]; then
	[ -f "$USER_PASSWD_PATH" ] || fatal "error: file $USER_PASSWD does not exist"
	USER_PASSWD="$USER_PASSWD_PATH"
fi
if [ -n "$ADDON" ]; then
	[ -f "$ADDON_PATH" ] || fatal "error: file $ADDON does not exist"
	ADDON="$ADDON_PATH"
fi
if [ -n "$UBOOT" ]; then
	[ -d "$UBOOT" ] || fatal "error: u-boot directory $UBOOT does not exist"
fi
if [ -n "$RPM_INSTALL" ]; then
	[ -d "$RPM_INSTALL" ] || fatal "error: rpm directory $RPM_INSTALL does not exist"
fi
if [ -n "$DTB_FILE" ]; then
	[ -f "$DTB_FILE_PATH" ] || fatal "error: file $DTB_FILE does not exist"
	DTB_FILE="$DTB_FILE_PATH"
fi

# checking the entered value --image-size
if [ -n "${IMAGE_SIZE-}" ]; then
	[[ "$IMAGE_SIZE" =~ [^0-9]+ ]] && fatal "error: bad image size"
fi

# ensure sudo user
if [ "$(whoami)" != "root" ]; then
	fatal "error: this script requires 'sudo' privileges in order to write to disk & mount media"
fi

if [ -z "$IMAGE_OUT" -a -z "$MEDIA" ]; then
	fatal "error: one of the options must be defined: --media or --image-out"
fi

if [ -n "$IMAGE_OUT" -a -n "$MEDIA" ]; then
	fatal "error: At the same time, mutually exclusive options are indicated: --media and --image-out"
fi

if [ -n "$IMAGE" -a -n "$ROOTFS" ]; then
	fatal "error: At the same time, mutually exclusive options are indicated: --image-in and --rootfs"
fi

if [ -n "$IMAGE" -a -n "$IMAGE_OUT" ]; then
	fatal "error: At the same time, mutually exclusive options are indicated: --image-in and --image-out"
fi


if [ -n "$MEDIA" ] && [[ "$(readlink -f /dev/root)" ==  "$MEDIA"* ]]; then
	fatal "error: $MEDIA is a device contains a host system rootfs"
fi

# rootfs exists
if [ -n "$ROOTFS" -a ! -f "$ROOTFS" ]; then
	fatal "error: $ROOTFS not found! Please choose an existing rootfs"
fi

# image exists
if [ -n "$IMAGE" -a ! -f "$IMAGE" ]; then
	fatal "error: $IMAGE not found! Please choose an existing image"
fi

# device exists
if [ -z "$IMAGE_OUT" -a ! -e "$MEDIA" ]; then
	fatal "error: $MEDIA not found! Please choose an existing device"
fi

# target board exists
if [ -n "$TARGET" -a ! -e "${BOARDDIR}/${TARGET}" ]; then
	fatal "error: $TARGET is not a supported board"
fi

if [ -n "$ADDON" ]; then
	case "$ADDON" in
		*.tar) ;;
		*) fatal "error: $ADDON is not a tar archive!!!";;
	esac
	[ -s "$ADDON" ] || fatal "error: $ADDON does not exist!!!"
fi

if [ -n "$DTB_FILE" ] || [ -n "$DTB_VENDOR" ] || [ -n "$DTB_KVER" ]; then
	[ -z "$DTB_FILE" ] && fatal "error: DTB_FILE is unset"
	[ -z "$DTB_VENDOR" ] && fatal "error: DTB_VENDOR is unset"
	[ -z "$DTB_KVER" ] && fatal "error: DTB_KVER is unset"
fi

# check image format
if [ -n "$IMAGE" ]; then
	case "$IMAGE" in
		*.img)
			CAT='cat'
			;;
		*.img.xz)
			CAT='xzcat'
			;;
		*) fatal "error: unknown image format"
			;;
	esac
	# NOTE: We assume there is no arch names containing '-' or '.'
	ARCH="${IMAGE##*-}"
	ARCH="${ARCH%%.*}"
fi

# output current status of tar to /dev/tty every 512 records (5 Mb)
# with default blocking factor 20 (1 record = 20*512 bytes)
TAR='tar --checkpoint=500 --checkpoint-action=ttyout=%s:%{}T\r'
# definition of the rootfs archive format and ARCH
if [ -n "$ROOTFS" ]; then
	case "$ROOTFS" in
		*.tar)
			TAR="$TAR -xf"
			let "TAR_SIZE = $(stat -Lc %s "$ROOTFS") / $MB"
			;;
		*.tar.gz)
			TAR="$TAR -zxf"
			let "TAR_SIZE = $(gzip --list "$ROOTFS" | awk 'END{print $2}') / $MB"
			;;
		*.tar.xz)
			TAR="$TAR -Jxf"
			let "TAR_SIZE = $(xz --robot --list "$ROOTFS" | awk '/^totals/{print $5}') / $MB"
			;;
		*) fatal "error: unknown rootfs archive format"
			;;
	esac
	# NOTE: We assume there is no arch names containing '-' or '.'
	ARCH="${ROOTFS##*-}"
	ARCH="${ARCH%%.*}"
fi

case "$MEDIA" in
	/dev/mmcblk*|/dev/loop*|/dev/nvme*)
		partsuffix="p"
		;;
	*)
		unset partsuffix
		;;
esac

### include logging
. $DIR/log

log_init

# Source common shell functions
. $DIR/functions

# Source board specific shell script
if [ -n "$TARGET" ]; then
	. "$BOARDDIR/$TARGET"
else
	. "$SOCSDIR/unknown-soc.sh"
fi

[ -z "$FAST_BOOT" ] || BOOT_TIMEOUT=0

# Add default system console
if [ -n "$CONSOLE" ] && [ -z "$SYSCON" ]; then
	SYSCON=ttyS0,115200n8
fi

# Add EFI Partitions
if [ -n "$EFI" -a -n "$ROOTFS" ]; then
	if [ -z "$FIRMPART_NUM" ]; then
		FIRMPART_NUM="${ROOTPART_NUM}"
		let ROOTPART_NUM=${FIRMPART_NUM}+1
	fi
fi

# Add a boot partition
if [ -n "$ADD_BOOTPART" ]; then
	if [ -z "$BOOTPART_NUM" ]; then
		BOOTPART_NUM="${ROOTPART_NUM}"
		let ROOTPART_NUM=${BOOTPART_NUM}+1
	fi
fi

if [ -z "$ROOTFS" -a -z "$IMAGE" ]; then
	find_firmware_partition
fi

# default size of partitions (MiB)
[ -z "$FIRMPART_NUM" ] || FIRMPART_SIZE=128
[ -z "$BOOTPART_NUM" ] || BOOTPART_SIZE=512

change_partition

# Image size calculation
if [ -n "$ROOTFS" -a -n "$IMAGE_OUT" ]; then
	# Increase size by 10% which is reserved by FS, take into account i-node ratio and reserved 32Mb.
	# Add 1 just in case.
	IMAGE_SIZE_MIN="$(awk -vTS="$TAR_SIZE" -vM="$MB" 'BEGIN{ printf ("%d", ((TS+512+32)*(1+1024/8192)*1.1+1)) }')"
	[ -z "$FIRMPART_SIZE" ] || let IMAGE_SIZE_MIN=$IMAGE_SIZE_MIN+$FIRMPART_SIZE
	[ -z "$BOOTPART_SIZE" ] || let IMAGE_SIZE_MIN=$IMAGE_SIZE_MIN+$BOOTPART_SIZE
	# Change image size
	if [ -z "${IMAGE_SIZE-}" ] || [ "$IMAGE_SIZE_MIN" -ge "$IMAGE_SIZE" ]; then
		IMAGE_SIZE="$IMAGE_SIZE_MIN"
	fi
	let "END_SECTOR = $IMAGE_SIZE - 1"
	END_SECTOR="$END_SECTOR"MiB
fi

# Last chance to back out
if [ -n "$IMAGE_OUT" -a -n "$IMAGE_SIZE" ]; then
	printx 'Image out: '; printn "$IMAGE_OUT" green 20
	printx 'Image size: '; printn "$IMAGE_SIZE MiB" green 20
else
	printx 'Selected Media: '; printn "$MEDIA" green 20
fi
# target hardware ARCH
if [ -n "$TARGET" ]; then
	printx 'Target: '; printn "$TARGET" green 20
fi
# rootfs if included
if [ -n "$ROOTFS" ]; then
	printx 'Selected rootfs: '; printn "$ROOTFS" green 20
fi
# image-in if included
if [ -n "$IMAGE" ]; then
	printx 'Selected image: '; printn "$IMAGE" green 20
fi
# addon
if [ -n "$ADDON" ]; then
	printx 'Addon: '; printn "$ADDON" green 20
fi
if [ -n "$UBOOT" ]; then
	printx 'U-boot directory: '; printn "$UBOOT" green 20
fi
if [ -n "$RPM_INSTALL" ]; then
	printx 'RPM directory: '; printn "$RPM_INSTALL" green 20
fi
if [ -n "$DTB_FILE" ]; then
	printx 'DTB file: '; printn "$DTB_FILE" green 20
fi
if [ -n "$DTB_VENDOR" ]; then
	printx 'DTB vendor: '; printn "$DTB_VENDOR" green 20
fi
if [ -n "$DTB_KVER" ]; then
	printx 'DTB kernel version: '; printn "$DTB_KVER" green 20
fi
if [ -n "$DEFAULT_KERNEL" ]; then
	printx 'Default kernel: '; printn "$DEFAULT_KERNEL" green 20
fi
# addconsole if included
if [ -n "$CONSOLE" ]; then
	printx 'System console: '; printn "$SYSCON" green 20
fi
if [ "$INITRD_OEM" = 1 ]; then
	printx 'Initrd OEM config: '; printn "Enabled" green 20
fi
if [ -n "$FAST_BOOT" ]; then
	printx 'Fast boot: '; printn "Enabled" green 20
fi
if [ -n "$BOOT_TIMEOUT" ]; then
	printx 'Boot timeout: '; printn "$BOOT_TIMEOUT" green 20
fi
if [ -n "$ROOT_PASSWD" ]; then
	printx 'root password: '; printn "$ROOT_PASSWD" green 20
fi
if [ -n "$USER_NAME" ] && [ -n "$USER_PASSWD" ]; then
	printx 'User: '; printn "$USER_NAME" green 20
	printx 'User password: '; printn "$USER_PASSWD" green 20
fi

if [ -n "$LOG_FILE" ]; then
	printx 'Log file: '; printn "$LOG_FILE" green 20
fi

case "$VNC" in
	1)
		printx 'VNC: '; printn "enabled" green 20
	;;
	0)
		printx 'VNC: '; printn "disabled" red 20
	;;
esac

if [ -z "$IMAGE_OUT" ]; then
	if [ -n "$IMAGE" -o -n "$ROOTFS" ]; then
		printn "WARNING! ALL DATA WILL BE DESTROYED" red
	else
		printn "WARNING! BOOTLOADER WILL BE OVERWRITTEN" red
	fi
fi

if [ "$NOASK" != 1 ]; then
	# Ask user before start
	printn "Would you like to continue? [Yes/No] " bold
	read PROCEED
	case "$PROCEED" in
		[Yy][Ee][Ss])
			;;
		*)
			printn "User exit, no rootfs written."
			exit 0
			;;
	esac
fi

trap pre_exit EXIT HUP PIPE INT QUIT TERM

# Check to make image file
if [ -n "$IMAGE_OUT" ]; then
	MEDIA="$(losetup --find)"
	[ -n "$MEDIA" ] || fatal_error "/dev/loop* is not allowed!!!"
fi

# Prepare media
[ -z "${MEDIA-}" ] || prepare_media

# Write image file to the media device
if [ -n "$IMAGE" ]; then
	image_to_media
	find_firmware_partition
	change_partition
fi

if [ -n "$ROOTFS" ]; then
	[ -z "${IMAGE_OUT-}" ] || prepare_image
	create_disklabel
	create_partition
	sync_partitions
	format_partition
	mount_partition
	write_rootfs
	setup_fstab	
	update_cmdline_txt
fi

soc_write_bootloader

# Setup boot flag
set_bootflag

# Update boot configs
BOOTCONF="${TMPROOT-}/boot/extlinux/extlinux.conf"
if [ -s "$BOOTCONF" ]; then
	# Change system console
	if [ -n "$CONSOLE" ]; then
		sed -i -e '/append/ s/[[:space:]]console=[a-zA-Z0-9,]*//g' \
		    -e "/append/ s/$/ console=tty0 console=$SYSCON/g" \
		    -e "/append/ s/ quiet//g" \
		    "$BOOTCONF"
	fi
	# Change fast boot
	if [ -n "$FAST_BOOT" ]; then
		sed -i "/^prompt .*/d;s/^menu \(.*\)/menu \1\nprompt 0/" "$BOOTCONF"
	fi
	# Change menu timeout
	if [ -n "$BOOT_TIMEOUT" ]; then
		sed -i "/^timeout .*/d;s/^menu \(.*\)/menu \1\ntimeout $BOOT_TIMEOUT/" "$BOOTCONF"
	fi
fi
BOOTCONF="${TMPROOT-}/boot/grub/grub.cfg"
if [ -s "$BOOTCONF" ]; then
	if [ -n "$CONSOLE" ]; then
		sed -i -e '/[[:space:]]linux/ s/[[:space:]]console=[a-zA-Z0-9,]*//g' \
		    -e "/[[:space:]]linux/ s/$/ console=tty0 console=$SYSCON/g" \
		    -e "/[[:space:]]linux/ s/ quiet//g" \
		    "$BOOTCONF"
	fi
	# Change menu timeout
	if [ -n "$BOOT_TIMEOUT" ]; then
		sed -i "s/set timeout=.*/set timeout=$BOOT_TIMEOUT/" "$BOOTCONF"
	fi
fi
BOOTCONF="${TMPROOT-}/etc/sysconfig/grub2"
if [ -s "$BOOTCONF" ]; then
	if [ -n "$CONSOLE" ]; then
		sed -i -e '/GRUB_CMDLINE_LINUX/ s/[[:space:]]console=[a-zA-Z0-9,]*//g' \
		    -e "/GRUB_CMDLINE_LINUX/ s/'$/ console=tty0 console=$SYSCON'/g" \
		    -e "/GRUB_CMDLINE_LINUX/ s/ quiet / /g;s/ quiet'/'/g" \
		    "$BOOTCONF"
	fi
	# Change menu timeout
	if [ -n "$BOOT_TIMEOUT" ]; then
		shell_config_set "$BOOTCONF" GRUB_TIMEOUT "$BOOT_TIMEOUT"
	fi
fi
unset BOOTCONF

# Enable vnc mode for alterator-setup
ALTERATOR_SETUP_CONF=${TMPROOT-}/etc/alterator-setup/config
if [ -f "$ALTERATOR_SETUP_CONF" ]; then
	case "$VNC" in
		1)
			sed '/ALTERATOR_SETUP_VNC=/d' -i "$ALTERATOR_SETUP_CONF"
			echo 'ALTERATOR_SETUP_VNC=1' >> "$ALTERATOR_SETUP_CONF"
		;;
		0)
			sed '/^ALTERATOR_SETUP_VNC=/s/^/#/' -i "$ALTERATOR_SETUP_CONF"
		;;
	esac
fi

# extract addon.tar
if [ -n "$ADDON" ]; then
	print_message "Extract archive $ADDON to rootfs..."
	tar -x -C "$TMPROOT" -f "$ADDON" ||
		fatal_error "Extract $ADDON failed!!!"
	print_done
fi

# use /etc/initrd.mk.oem in rootfs
if [ "$INITRD_OEM" = 1 ]; then
	print_message "Copying initrd.mk.oem to initrd.mk ..."
	cp $TMPROOT/etc/initrd.mk{.oem,}
	print_done
fi

# mount chroot if needed
if [ -n "$RPM_INSTALL" ] || [ -n "$ROOT_PASSWD" ] ||
   [ -n "$USER_NAME" ] || [ -n "$USER_PASSWD" ] ||
   [ -n "$DEFAULT_KERNEL" ] || [ -n "$EFI" ]; then
	print_message "Mount chroot ..."
	mount_chroot || fatal_error "Mount chroot failed!!!"
	print_done
fi

# install additions packages
if [ -n "$RPM_INSTALL" ]; then
	print_message "Install additions rpm packages ..."
	rpm_install "$RPM_INSTALL" ||
		fatal_error "Failed install rpm packages!!!"
	print_done
fi

if [ -n "$DEFAULT_KERNEL" ]; then
	print_message "Set default kernel: $DEFAULT_KERNEL ..."
	exec_chroot installkernel --keep-initrd -u "$DEFAULT_KERNEL" ||
		fatal_error "Failed to set default kernel!!!"
	print_done
fi

if [ -n "$ROOT_PASSWD" ]; then
	print_message "Set root password ..."
	exec_chroot usermod -p "$(head -n1 "$ROOT_PASSWD")" "root" ||
		fatal_error "Failed to set root password!!!"
	print_done
fi

if [ -n "$USER_NAME" ] && [ -n "$USER_PASSWD" ]; then
	print_message "Create user \"$USER_NAME\" ..."
	exec_chroot useradd -m "$USER_NAME" ||
		fatal_error "Failed to add user \"${USER_NAME}\"!!!"
	print_done
	print_message "Set password for user \"$USER_NAME\" ..."
	exec_chroot usermod -p "$(head -n1 "$USER_PASSWD")" "$USER_NAME" ||
		fatal_error "Failed to set $USER_NAME password!!!"
	print_done
fi

if [ -n "$DTB_FILE" ] && [ -n "$DTB_VENDOR" ] && [ -n "$DTB_KVER" ]; then
	print_message "Install external dtb ..."
	add_dtb || fatal_error "Failed to install vendor dtb!!!"
	print_done
fi

# grub-efi install
if [ -n "$EFI" ] && [ -n "$FIRMPART_NUM" ] && [ -f "$TMPROOT"/etc/sysconfig/grub2 ]; then
	print_message "Trying grub-efi install..."
	case "$(exec_chroot arch)" in
		x86_64) exec_chroot grub-install --target=x86_64-efi --recheck --removable \
			--uefi-secure-boot || fatal_error "grub-install x86_64-efi failed!!!"
		;;
		aarch64) exec_chroot grub-install --target=arm64-efi --recheck --removable \
			--uefi-secure-boot || fatal_error "grub-install arm64-efi failed!!!"
		;;
		riscv64) exec_chroot grub-install --target=riscv64-efi --recheck --removable \
			--uefi-secure-boot || fatal_error "grub-install riscv64-efi failed!!!"
		;;
		loongarch64) exec_chroot grub-install --target=loongarch64-efi --recheck --removable \
			--uefi-secure-boot || fatal_error "grub-install loongarch64-efi failed!!!"
		;;
		*) fatal_error "Unknown ARCH!!!"
		;;
	esac
	exec_chroot update-grub || fatal_error "update-grub failed!!!"
	print_done
fi

final_exit
