## Authors:
##   Ajrat Makhmutov <rauty@altlinux.org>
##
## Copyright (C) 2024-2025  Basealt LLC
##
## This file is part of alterator-kopidel.
##
## alterator-kopidel is free software: you can redistribute it and/or modify it under the terms
## of the GNU General Public License as published by the Free Software Foundation,
## either version 3 of the License, or (at your option) any later version.
##
## alterator-kopidel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
## without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with alterator-kopidel.
## If not, see <https://www.gnu.org/licenses/>.

if [ -n "${__included_kopidel_steps-}" ]; then
	return 0
fi
readonly __included_kopidel_steps=1

. "${KOPIDEL_LIBDIR:-/usr/lib/alterator-kopidel}/variables"
. "$KOPIDEL_LIBDIR/percentage-handlers"
. "$KOPIDEL_LIBDIR/boot-image-methods"
. "$KOPIDEL_LIBDIR/check-incoming-parameters"
. alterator-sh-functions

declare -A STEPS
SUBSTEPS=()
run_step() (
	if [ -n "$in_workdir" ]; then
		mkdir -pv "$in_workdir"
		fast_check_in_workdir &>>"$in_workdir/build.log" || return 1
	elif [ -n "$in_exdrive" ]; then
		mkdir -pv "$EXDRIVE_WORKDIR"
		in_workdir="$EXDRIVE_WORKDIR"
		fast_check_in_exdrive &>>"$in_workdir/build.log" || return 1
	else
		echo "No input workdir or exdrive" &>>"$in_workdir/build.log"
		return 1
	fi

	step="$1"
	echo "step start: $step" >> "$in_workdir/build.log"
	echo "step_progress: 0"

	cd "$in_workdir" || return 1

	"$step" 2>&1 | tee -a "$in_workdir/build.log" | grep -Ex --line-buffered 'step_progress: [0-9]*' || true

	# ${PIPESTATUS[0]} returns step exit code.
	if [ "${PIPESTATUS[0]}" -ne 0 ]; then
		return 1
	fi

	echo "step_progress: 100"
	echo "step end: $step" >> "$in_workdir/build.log"
)

SUBSTEPS+=( prepare_workdir::create_initrd_image )
prepare_workdir::create_initrd_image() (
	pushd image || return 1

	mkdir -pv .disk
	cp -vf "$KOPIDEL_DATADIR/initrd.mk" .disk/
	cp -vf "$KOPIDEL_DATADIR/bootchain" .disk/

	mkdir -pv boot
	rm -vf boot/initrd*.img
	make-initrd --config=.disk/initrd.mk --bootdir=boot/ BOOTCHAIN_PATH=.disk -v
)

# output: $in_workdir/squashfs-files.txt
SUBSTEPS+=( prepare_workdir::create_squashfs_files_list )
prepare_workdir::create_squashfs_files_list() (
	readonly SQUASHFS_PACKAGES_LOG="${TMPDIR:-/tmp}/squashfs-packages-log.txt"

	cp -fv "$KOPIDEL_DATADIR/squashfs-files-default.txt" squashfs-files.txt
	rm -fv "$SQUASHFS_PACKAGES_LOG"
	while IFS="" read -r squashfs_package || [ -n "$squashfs_package" ]; do
		if [ -z "$(rpm -q "$squashfs_package" 2>>"$SQUASHFS_PACKAGES_LOG")" ]; then
			continue
		fi

		echo "Add the $squashfs_package to the altinst image" >> "$SQUASHFS_PACKAGES_LOG"
		rpm -ql "$squashfs_package" | while read -r squashfs_file; do
			# The file paths must be real, not through links, because
			# otherwise rsync will treat links as directories.
			if [ -L "$squashfs_file" ]; then
				dirname_link="$(dirname "$squashfs_file")"
				realpath_to_link="$(realpath "$dirname_link")"
				echo "$realpath_to_link/$(basename "$squashfs_file")" >> squashfs-files.txt
			else
				realpath "$squashfs_file" >> squashfs-files.txt
			fi
		done
	done < <(rpm -qa --qf "%{NAME}\n" | grep -E -x -f "$KOPIDEL_DATADIR/squashfs-packages-default.txt")

	find "/usr/lib/modules/$(uname -r)" >> squashfs-files.txt
)

SUBSTEPS+=( prepare_workdir::create_squashfs_altinst )
prepare_workdir::create_squashfs_altinst() (
	# This is necessary to reduce the maximum occupied space.
	pushd image || return 1

	if [ ! -r "$in_workdir/squashfs-files.txt" ]; then
		write_error 'No readable file squashfs-files.txt in workdir.'
		return 1
	fi

	rm   -rf squashfs-root
	mkdir -v squashfs-root
	rm -vf "$in_workdir/rsync-squashfs-root.log"
	expected_lines="$(rsync -avAXHW --dry-run --exclude="$in_workdir" \
		--files-from="$in_workdir/squashfs-files.txt" \
		/ "squashfs-root/" 2>&1 | wc -l)"
	rsync -avAXHW \
		--exclude="$in_workdir" \
		--files-from="$in_workdir/squashfs-files.txt" \
		/ "squashfs-root/" 2>&1 \
		| expected_percentage_handler "$expected_lines" 30 50 \
		"$in_workdir/rsync-squashfs-root.log"

	pushd squashfs-root || return 1
		rm -v usr/sbin/init
		if [ -f usr/sbin/install2-init ]; then
			mv -v usr/sbin/install2-init sbin/init
		else
			mv -v usr/libexec/install2/install2-init sbin/init
		fi

		# These folders should always be in the system, but let's be safe.
		# This is necessary for install2-init
		mkdir -pv sys mnt tmp proc
	popd || return 1

	chroot squashfs-root /usr/bin/bash -c "alternatives-validate; alternatives-update"

	rm -fv altinst
	mksquashfs squashfs-root altinst -no-recovery -comp xz -b 262144 -percentage | default_percentage_handler 50 100

	if ! test_bool "$in_lazy_cleanup"; then
		rm -rf squashfs-root
	fi
)

# Creating files that do not depend on the user's choice.
STEPS[prepare_workdir]="$(_ "Preparing the working directory")"
prepare_workdir() (
	mkdir -pv image/.disk
	rpm -qi alterator-kopidel > image/.disk/alterator-kopidel.txt

	mkdir -pv image/boot
	rm -vf image/boot/vmlinuz-*
	cp -v "/boot/vmlinuz-$(uname -r)" image/boot/

	mkdir -pv image/Metadata
	cp -vf "$KOPIDEL_DATADIR/autoinstall.scm" image/Metadata/autoinstall.scm

	echo "step_progress: 3"
	prepare_workdir::create_initrd_image
	echo "step_progress: 20"
	prepare_workdir::create_squashfs_files_list
	echo "step_progress: 30"
	prepare_workdir::create_squashfs_altinst
	echo "step_progress: 100"
)

STEPS[create_copied_fs]="$(_ "Copying the file system")"
create_copied_fs() (
	"$KOPIDEL_LIBEXECDIR/update-ignored-files.sh" "$in_ignored_files" || return 1

	mkdir -pv image/Metadata
	rm -rf copied-fs
	rm -vf image/Metadata/copied-fs.tar*
	rm -vf "$in_workdir/copied-fs-files.log"

	expected_lines="$(rsync -avAXHW --dry-run \
		--exclude="$in_workdir" \
		--exclude="$WORKDIR_NAME" \
		--exclude-from="$IGNORED_FILES" \
		/ "copied-fs/" 2>/dev/null | wc -l)"

	if test_bool "$in_compress_copied"; then
		tar cvf image/Metadata/copied-fs.tar.xz --absolute-names \
			--use-compress-program='xz -T0' \
			--exclude="$in_workdir" \
			--exclude="**/$WORKDIR_NAME" \
			--exclude-from="$IGNORED_FILES" \
			-C / / | expected_percentage_handler "$expected_lines" 0 99 \
			"$in_workdir/copied-fs-files.log"
	else
		tar cvf image/Metadata/copied-fs.tar --absolute-names \
			--exclude="$in_workdir" \
			--exclude="**/$WORKDIR_NAME" \
			--exclude-from="$IGNORED_FILES" \
			-C / / | expected_percentage_handler "$expected_lines" 0 99 \
			"$in_workdir/copied-fs-files.log"
	fi
)

# This function makes parsing easier.
print_fstab_only_spaces() {
	sed -E -e 's/\t+/ /g' -e 's/ +/ /g' /etc/fstab
}

SUBSTEPS+=( create_disk_partition_info::subvolumes_info_by_uuid )
create_disk_partition_info::subvolumes_info_by_uuid() (
	UUID="${1:?}"
	result=

	result="$(print_fstab_only_spaces | grep "^UUID=$UUID .*[, ]subvol=/" |
		while read -r line; do
			name="$(echo "$line" | sed 's@.*subvol=/@@' | sed 's@,.*@@' | sed "s@ .*@@")"
			mountpoint="$(echo "$line" | cut -d ' ' -f 2)"

			if [[ -z "$name" || -z "$mountpoint" ]]; then
				continue
			fi
			echo -n " (\"$name\" . \"$mountpoint\")"
		done)"

	if [ -n "$result" ]; then
		result="(subvols$result)"
	fi
	echo "$result"
)

SUBSTEPS+=( create_disk_partition_info::lvm_info_by_uuid )
create_disk_partition_info::lvm_info_by_uuid() (
	UUID="${1:?}"
	device= vg_name= lv_name= result=

	device="$(blkid -o device -t UUID="$UUID" 2>/dev/null)"
	if [ -z "$device" ]; then
		echo ""
		return
	fi

	vg_name="$(lvs --noheadings -o vg_name "$device" 2>/dev/null | tr -d ' ')"
	lv_name="$(lvs --noheadings -o lv_name "$device" 2>/dev/null | tr -d ' ')"

	if [ -n "$vg_name" ]; then
		result="(vg . \"$vg_name\")"
	fi
	if [ -n "$lv_name" ]; then
		[ -n "$result" ] && result+=" "
		result+="(lv . \"$lv_name\")"
	fi

	echo "$result"
)

# output: $in_workdir/image/Metadata/vm-profile.scm
STEPS[create_disk_partition_info]="$(_ "Generating disk partition information")"
create_disk_partition_info() (
	declare -A fsname_blkid_to_evms=( [ext4]="Ext4" [xfs]="XFS" [btrfs]="BtrFS" [vfat]="FAT32" [ntfs]="NTFS" [swap]="SWAPFS" )
	declare -A type_blkid_to_methods=( [part]="plain" [lvm]="lvm" )
	vm_profile=image/Metadata/vm-profile.scm

	mkdir -pv image/.disk image/Metadata
	lsblk --raw -b -o 'FSTYPE,SIZE,UUID,TYPE,FSUSED' > image/.disk/lsblk
	cp -vf /etc/fstab image/.disk/

	rm -vf "$vm_profile"
	cp -v "$KOPIDEL_DATADIR/vm-profile-start.scm" "$vm_profile"

	lsblk -n --raw -b -o 'FSTYPE,SIZE,UUID,TYPE,FSUSED' | sort -k4,4r -k2,2n | while read -r line; do
		FSTYPE="$(echo "$line" | cut -d ' ' -f 1)"
		SIZE="$(  echo "$line" | cut -d ' ' -f 2)"
		UUID="$(  echo "$line" | cut -d ' ' -f 3)"
		TYPE="$(  echo "$line" | cut -d ' ' -f 4)"
		FSUSED="$(echo "$line" | cut -d ' ' -f 5)"

		if [[ -z "$FSTYPE" || -z "$SIZE" || -z "$UUID" ]]; then
			continue
		fi

		if [[ "$FSTYPE" == "LVM2_member" || "$FSTYPE" == "exfat" ]]; then
			continue
		fi

		if ! [[ "$TYPE" == part || "$TYPE" == lvm ]]; then
			echo "Unknown TYPE: $TYPE"
			continue
		fi

		evms_FSTYPE="${fsname_blkid_to_evms["$FSTYPE"]}"
		if [ -z "$evms_FSTYPE" ]; then
			echo "Unknown FSTYPE: $FSTYPE"
			continue
		fi
		methods="${type_blkid_to_methods["$TYPE"]}"
		if [ -z "$methods" ]; then
			echo "Unknown TYPE: $TYPE"
			continue
		fi
		mountpoint="$(print_fstab_only_spaces | grep "^UUID=$UUID " | grep -v "[, ]subvol=/" | head -n 1 | cut -d ' ' -f 2)"
		subvolumes="$(create_disk_partition_info::subvolumes_info_by_uuid "$UUID")"
		if [[ -z "$mountpoint" && -z "$subvolumes" ]]; then
			echo "Mountpoint of partition with uuid $UUID not found in the /etc/fstab!"
			continue
		fi

		paths=()
		if [ -n "$mountpoint" ]; then
			paths+=( "$mountpoint" )
		fi
		if [ -n "$subvolumes" ]; then
			while read -r subvolume_mountpoint; do
				paths+=( "$subvolume_mountpoint" )
			done < <(print_fstab_only_spaces | grep "^UUID=$UUID .*[, ]subvol=/" | cut -d ' ' -f 2)
		fi

		(( max_size = SIZE / 512 ))
		if [[ "$FSTYPE" == swap || "$mountpoint" == /boot/efi ]]; then
			min_size="$max_size"
		else
			min_size="$(du -bs --exclude-from="$IGNORED_FILES" --exclude="$WORKDIR_NAME" "${paths[@]}" 2>/dev/null | tail -n 1 | cut -f 1)"
			(( min_size /= 512 ))

			if [ -z "$min_size" ]; then
				echo "WARNING: min_size of the partition with uuid $UUID is not calculated with du!" >&2
				(( min_size = max_size / 2 ))
			fi

			if [[ -n "$FSUSED" && "$min_size" -gt "$(( FSUSED / 512 ))" ]]; then
				echo "WARNING: min_size $min_size greater than FSUSED $(( FSUSED / 512 )) of the partition with uuid $UUID!" >&2
				(( min_size = FSUSED / 512 ))
			fi

			if [ "$max_size" -lt "$min_size" ]; then
				echo "ERROR: max_size $max_size less than min_size $min_size" >&2
				min_size="$max_size"
			fi
		fi

		lvm_info=""
		if [[ "$TYPE" == "lvm" ]]; then
			lvm_info="$(create_disk_partition_info::lvm_info_by_uuid "$UUID")"
		fi

		if [ -n "$lvm_info" ]; then
			methods_field="(methods ($methods $lvm_info))"
		else
			methods_field="(methods $methods)"
		fi

		echo "               (\"$mountpoint\" (size $min_size . $max_size ) (fsim . \"$evms_FSTYPE\") $methods_field $subvolumes)" >> "$vm_profile"
	done

	echo '               )))' >> "$vm_profile"

	echo "--- lsblk --raw -b ---"
	cat image/.disk/lsblk
	echo "--- blkid ---"
	blkid 2>/dev/null || true
	echo "--- vm-profile.scm ---"
	cat "$vm_profile"
	echo "--- end create_disk_partition_info ---"
)

STEPS[create_install_scripts]="$(_ "Creating installation scripts")"
create_install_scripts() (
	rm -vf image/Metadata/install-scripts.tar
	rm -rf install-scripts

	mkdir -pv \
		install-scripts/initinstall.d \
		install-scripts/postinstall.d \
		install-scripts/preinstall.d

	clear_scripts=( postinstall.d/00-remove-installer-pkgs.sh )
	clear_scripts+=( preinstall.d/00-cp-diskinfo.sh )
	clear_scripts+=( preinstall.d/05-copy-fstab )
	clear_scripts+=( preinstall.d/20-sysconfig.sh )

	install -v -m 755 "$KOPIDEL_DATADIR/90-dmsetup-remove_all.sh" install-scripts/initinstall.d/

	if test_bool "$in_oem_mode"; then
		install -v -m 755 "$KOPIDEL_DATADIR/91-alterator-setup"        install-scripts/postinstall.d/
		install -v -m 755 "$KOPIDEL_DATADIR/92-oem-remove-human-users" install-scripts/postinstall.d/
	fi

	install -v -m 755 "$KOPIDEL_DATADIR/51-kopidel-grub.sh" install-scripts/postinstall.d/
	if test_bool "$in_grub_efi_removable"; then
		sed -i "s/@GRUB_DEVICE_EFI@/efiremovable/" install-scripts/postinstall.d/51-kopidel-grub.sh
	else
		sed -i "s/@GRUB_DEVICE_EFI@/efi/" install-scripts/postinstall.d/51-kopidel-grub.sh
	fi

	install -v -m 755 "$KOPIDEL_DATADIR/00-preinstall.sh" install-scripts/postinstall.d/

	pushd install-scripts || return 1
	echo '#!/bin/sh' | tee ${clear_scripts[*]} > /dev/null
	chmod 755 ${clear_scripts[*]}
	popd || return 1

	mkdir -pv image/Metadata
	tar cf image/Metadata/install-scripts.tar -C install-scripts .

	if ! test_bool "$in_lazy_cleanup"; then
		rm -rf install-scripts
	fi
)

SUBSTEPS+=( create_razlivochniy_mountpoint::mount_razlivochniy )
create_razlivochniy_mountpoint::mount_razlivochniy() (
	if [ -n "$in_exdrive" ]; then
		dev="$in_exdrive"
	else
		dev="$(losetup -j razlivochniy.img | head -n 1 | cut -d ':' -f 1)"
		if [ -z "$dev" ]; then
			dev="$(losetup --show -Pf razlivochniy.img)"
		fi
	fi

	while read -r line; do
		NAME="$(echo "$line" | cut -d ' ' -f 1)"
		PARTLABEL="$(echo "$line" | cut -d ' ' -f 2)"

		case "$PARTLABEL" in
		"BIOS")
			bios_pdev="$NAME"
		;;
		"ESP")
			efi_pdev="$NAME"
		;;
		"ROOT")
			root_pdev="$NAME"
		;;
		esac
	done < <(lsblk --paths -n --raw -b -o 'NAME,PARTLABEL' "$dev")

	mkdir -pv image
	mount "$root_pdev" image
	if [ -n "$efi_pdev" ]; then
		mkdir -pv image/boot/efi
		mount "$efi_pdev" image/boot/efi
	fi
)

STEPS[create_razlivochniy_mountpoint]="$(_ "Creating partitions and mount points")"
create_razlivochniy_mountpoint() (
	umount_razlivochniy || true
	rm -rf image
	mkdir -pv image

	if [ -n "$in_exdrive" ]; then
		lsblk --paths --raw -n -o 'MOUNTPOINT' "$in_exdrive" | while read -r mnt; do
			# /run/media/*: Automounted, mounted by user not system drives in GNOME.
			if [[ -n "$mnt" && "$mnt" != /run/media/* ]]; then
				echo "ERROR: mountpoint of exdrive $in_exdrive was found: $mnt." >&2
				return 1
			fi
		done
		umount "$in_exdrive"*
		pdev="$in_exdrive"
	else
		rm -fv razlivochniy.img razlivochniy.iso
		if test_bool "$in_compress_copied"; then
			if [ ! -d ready-to-use-image ]; then
				echo "Incorrect using create_razlivochniy_mountpoint step with compressing:" >&2
				echo "razlivochniy.img should be created after creating image compressing copied fs" >&2
				echo "with ready to use installer files. This is necessary to" >&2
				echo "create the minimal size razlivochniy.img." >&2
				return 1
			fi
			img_size="$(du -sm ready-to-use-image | cut -f 1)"
		else
			img_size="$("$KOPIDEL_LIBEXECDIR/required-space.sh")"
			# Convert to megabytes.
			(( img_size /= 1024 * 1024 ))
			# 1 gigabyte: required space for squashfs altinst and other installer files.
			(( img_size += 1024 ))
		fi
		# Ext4 overhead clusters 5%.
		(( img_size += img_size / 20 ))
		if is_img_efi_bootable; then
			(( img_size += ESP_SIZE_MB ))
		fi

		dd if=/dev/zero of=razlivochniy.img bs=1M count="$img_size" &
		dd_pid="$!"
		dd_percentage_handler 0 90 "$dd_pid" razlivochniy.img "$(( img_size * 1024 * 1024 ))"

		pdev=razlivochniy.img
	fi

	parted "$pdev" --script mklabel gpt
	START_NEW_PART_MB=1
	NEW_PART_NUM=1

	if rpm -q grub-pc &>/dev/null; then
		parted "$pdev" --script mkpart non-fs "${START_NEW_PART_MB}MiB" 2MiB
		parted "$pdev" --script name "$NEW_PART_NUM" "BIOS"
		parted "$pdev" --script set "$NEW_PART_NUM" bios_grub on
		(( START_NEW_PART_MB += 1 ))
		(( NEW_PART_NUM += 1 ))
	fi

	if rpm -q grub-efi &>/dev/null; then
		parted "$pdev" --script mkpart primary fat32 "${START_NEW_PART_MB}MiB" "$(( ESP_SIZE_MB + START_NEW_PART_MB ))MiB"
		parted "$pdev" --script name "$NEW_PART_NUM" "ESP"
		parted "$pdev" --script set "$NEW_PART_NUM" esp on
		(( START_NEW_PART_MB += ESP_SIZE_MB ))
		(( NEW_PART_NUM += 1 ))
	fi

	parted "$pdev" --script mkpart primary ext4 "${START_NEW_PART_MB}MiB" 100%
	parted "$pdev" --script name "$NEW_PART_NUM" "ROOT"

	if [ -n "$in_exdrive" ]; then
		dev="$in_exdrive"
	else
		dev="$(losetup --show -Pf razlivochniy.img)"
	fi

	# lsblk gets info from sysfs and udev, so we must update udev for accurate results
	partprobe "$dev"
	if ! udevadm wait --timeout=30 --settle "$dev"; then
		echo "WARNING: udev events for $dev didn't settle in 30 seconds" >&2
	fi

	while read -r line; do
		NAME="$(echo "$line" | cut -d ' ' -f 1)"
		PARTLABEL="$(echo "$line" | cut -d ' ' -f 2)"

		case "$PARTLABEL" in
		"BIOS")
			bios_pdev="$NAME"
		;;
		"ESP")
			efi_pdev="$NAME"
		;;
		"ROOT")
			root_pdev="$NAME"
		;;
		esac
	done < <(lsblk --paths -n --raw -b -o 'NAME,PARTLABEL' "$dev")

	echo "bios_pdev=$bios_pdev"
	echo "efi_pdev=$efi_pdev"
	echo "root_pdev=$root_pdev"

	# Completely disable the reserve because it is not needed for read-only images.
	mkfs.ext4 -m 0 "$root_pdev"
	if [ -n "$efi_pdev" ]; then
		mkfs.vfat -F32 "$efi_pdev"
	fi

	create_razlivochniy_mountpoint::mount_razlivochniy
)

STEPS[save_ready_to_use_image]="$(_ "Moving ready-to-use files into an image")"
save_ready_to_use_image() (
	if ! [[ -f image/altinst ||
		-f image/Metadata/copied-fs.tar.xz ||
		-f image/Metadata/vm-profile.scm ]]; then
		echo "create_ready_to_use_image: error: not ready to use image." >&2
	fi
	rm -rf ready-to-use-image
	mv image ready-to-use-image
)

STEPS[use_ready_to_use_image]="$(_ "Moving ready-to-use files into an image")"
use_ready_to_use_image() (
	if [ ! -d image ]; then
		echo "use_ready_to_use_image: error: no image dir." >&2
	fi
	cp -RT ready-to-use-image image
	if ! test_bool "$in_lazy_cleanup"; then
		rm -rf ready-to-use-image
	fi
)

STEPS[install_grub]="$(_ "Installing GRUB")"
install_grub() (
	if [ -n "$in_exdrive" ]; then
		dev="$in_exdrive"
	else
		dev="$(losetup -j razlivochniy.img | head -n 1 | cut -d ':' -f 1)"
	fi
	root_pdev="$(lsblk --paths -n --raw -b -o 'NAME,PARTLABEL' "$dev" | grep -m1 ' ROOT$' | sed 's/ ROOT//')"
	root_pdev_uuid="$(blkid -s UUID -o value "$root_pdev")"

	modules="linux normal iso9660 f2fs ext2 fat exfat ntfs ntfscomp part_gpt search font configfile gfxterm"

	if is_img_legacy_bootable; then
		grub-install \
			--target=i386-pc \
			--boot-directory="image/boot" \
			--install-modules="$modules biosdisk tar ls minicmd reboot halt cat" \
			--modules="$modules biosdisk" \
			--locales="" \
			--fonts="unicode" \
			"$dev" || echo "Legacy BIOS GRUB installation failed" >&2
	fi

	if is_img_efi_bootable; then
		if command -v grub-efi-install > /dev/null 2>&1; then
			grub-efi-install \
				--boot-directory="image/boot" \
				--efi-directory="image/boot/efi" \
				--removable \
				-- \
				--install-modules="$modules tar ls minicmd reboot halt cat" \
				--modules="$modules" \
				--locales="" \
				--fonts="unicode"
		else
			case "$(uname -m)" in
			x86_64)       grub_efi_target=x86_64-efi ;;
			i?86)         grub_efi_target=i386-efi ;;
			aarch64)      grub_efi_target=arm64-efi ;;
			loongarch64)  grub_efi_target=loongarch64-efi ;;
			riscv64)      grub_efi_target=riscv64-efi ;;
			esac
			grub-install \
				--target="$grub_efi_target" \
				--boot-directory="image/boot" \
				--efi-directory="image/boot/efi" \
				--install-modules="$modules tar ls minicmd reboot halt cat" \
				--modules="$modules" \
				--locales="" \
				--fonts="unicode" \
				--removable \
				"$dev"
		fi
	fi

	pushd image || return 1

	cp  -f "$KOPIDEL_DATADIR/grub.cfg"  boot/grub/grub.cfg

	sed -i "s/@KFLAVOUR@/$(uname -r)/g" boot/grub/grub.cfg
	sed -i "s/@UUID@/$root_pdev_uuid/g" boot/grub/grub.cfg

	menuentry_install="$(_ 'Install a "razlivochniy obraz".')"
	sed -i "s/@MENUENTRY_INSTALL@/$menuentry_install/g" boot/grub/grub.cfg

	popd
)

STEPS[umount_razlivochniy]="$(_ "Unmounting an image")"
umount_razlivochniy() (
	sync
	if [ -n "$in_exdrive" ]; then
		umount "$in_exdrive"*
	else
		if [ ! -f razlivochniy.img ]; then
			echo "No razlivochniy.img for umount" >&2
			return 1
		fi
		LOOP_DEV="$(losetup -j razlivochniy.img | head -n 1 | cut -d ':' -f 1)"
		if [ -e "$LOOP_DEV" ]; then
			umount "$LOOP_DEV"*
			losetup -d "$LOOP_DEV"
		fi
	fi
)
