#!/usr/bin/env bash
#
#   Script name: ubiso
#   Description: Script for build iso UBLinux
#   GitLab: https://gitlab.ublinux.ru/
#   Author: asmeron@ublinux.ru
#   Contributors: asmeron@ublinux.ru
#
#   Copyright (c) 2021-2022 UBLinux Development Team <support@ublinux.ru>
#
#   This program 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 2 of the License, or
#   (at your option) any later version.
#
#   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

VERSION_SCRIPT="1.1"

# Exit Immediately if a command fails
#set -o errexit

#################################
###   :::   C O L O R S   :::   #
#################################
set_color() {
#http://abload.de/img/bash-color-chartmxjbp.png
    export BBC=$'\e[1;34m'
    export RBC=$'\e[1;31m'
    export WBC=$'\e[1m'
    export EC=$'\e[0m'

    export txtblk='\033[0;30m' # Black - Regular
    export txtred='\033[0;31m' # Red			# prompt: error color
    export txtgrn='\033[0;32m' # Green			# prompt: success color
    export txtylw='\033[0;33m' # Yellow			# prompt: waring color
    export txtblu='\033[0;34m' # Blue			
    export txtpur='\033[0;35m' # Purple
    export txtcyn='\033[0;36m' # Cyan			# prompt: info color
    export txtwht='\033[0;37m' # White
    export bldblk='\033[1;30m' # Black - Bold
    export bldred='\033[1;31m' # Red			# prompt: bold error color
    export bldgrn='\033[1;32m' # Green			# prompt: bold success color
    export bldylw="\033[1;33m" # Yellow                 # prompt: bold warning color
    export bldblu='\033[1;34m' # Blue				
    export bldpur='\033[1;35m' # Purple
    export bldcyn="\033[1;36m" # Cyan                   # prompt: bold info color
    export bldwht="\033[1;37m" # White			# prompt: bold default color

    export undblk='\033[4;30m' # Black - Underline
    export undred='\033[4;31m' # Red

    export bakblk='\033[40m'   # Black - Background
    export bakred='\033[41m'   # Red
    export badgrn='\033[42m'   # Green

    export txtrst='\033[0m'    # Text Reset		# prompt: default color
}


#######################################
###   :::   F U N C T I O N S   :::   #
#######################################

check_root() {
    if [[ ${EUID:-$(id -u)} > 0 ]]; then
        prompt -wq "Please run as root!"
    fi
}

# Check command availability
has_command() { command -v $1 &> /dev/null; }

# echo like ... with flag type and display message colors
prompt() {
    [[ -n ${QUIET} ]] && return
    case ${1} in
	-s  | --success)	echo -e "${bldgrn}${@/#-s/}${txtrst}" ;;    			# print success message
	-sq | --success-quit)	echo -e "${bldgrn}${@/#-sq/}${txtrst}" && exit 1 ;;    		# print success message
	-e  | --error)   	echo -e "${bldred}ERROR:${@/#-e/}${txtrst}" ;;   		# print error message
	-eq | --error-quit)   	echo -e "${bldred}ERROR:${@/#-eq/}${txtrst}" && exit 1 ;;	# print error message
	-w  | --warning) 	echo -e "${bldylw}WARNING:${bldwht}${@/#-w/}${txtrst}" ;; 	# print warning message
	-wq | --warning-quit) 	echo -e "${bldylw}WARNING:${bldwht}${@/#-wq/}${txtrst}" && exit 1 ;; # print warning message
	-i  | --info)    	echo -e "${bldcyn}INFO:${txtcyn}${@/#-i/}${txtrst}" ;;    	# print info message
	-iq | --info-quit)    	echo -e "${bldcyn}INFO:${txtcyn}${@/#-iq/}${txtrst}" && exit 1 ;;  # print info message
	*)    			echo -e "$@" ;;							# print all message
    esac
}


usage() {
    printf "%s  %s\n" "${0##*/}" "version: ${VERSION_SCRIPT}"
    cat <<EOF
Build iso image UBLinux

Usage: ${0##*/} {COMMAND} [OPTIONS...] ...

Meta Commands:
  help          	Show this help

OPTIONS:
  -p, --path=PATH  	Path to the ISO
			Without PATH for command 'create' PATH="./"
  -m, --manual		Manual build. Not take the current system settings and modules
			Include --nokernel --nosign --noskel --nomodules
  -n, --nokernel	Don't copy kernel vmlinuz and initrd to iso /ublinux/
      --nosign		Don't update signature file
      --noskel		Don't update ublinux and ublinux-data skeleton
      --nomodules	Don't update modules from current system
  -c, --noclean		Don't clean source build
  -s, --sign-key	Signing key for ISO file
  -u, --sign-user	User signing ISO file
      --sign-password   Password for sign user
      --ram		Build ISO in RAM
  -q, --quiet		Quiet mode
  -h, --help		Show this help
  -V, --version		Show package version


OPTIONS update:
Examples:
${0##*/} --
${0##*/} -qp /home/iso
EOF
    exit 0
}

arguments() {
# Pre-process options to:
# - expand -xyz into -x -y -z
# - expand --longopt=arg into --longopt arg
    local ARGV=()
    local END_OF_OPT=
    while [[ $# -gt 0 ]]; do
	arg="$1"; shift
	case "${END_OF_OPT}${arg}" in
	    --) ARGV+=("$arg"); END_OF_OPT=1 ;;
	    --*=*)ARGV+=("${arg%%=*}" "${arg#*=}") ;;
	    --*) ARGV+=("$arg") ;;
	    -*) for i in $(seq 2 ${#arg}); do ARGV+=("-${arg:i-1:1}"); done ;;
	    *) ARGV+=("$arg") ;;
	esac
    done
# Apply pre-processed options
    set -- "${ARGV[@]}"
# Parse options
    local END_OF_OPT=
    local POSITIONAL_ARGS=()
    [[ -z $@ ]] && usage && exit 0
    while [[ $# -gt 0 ]]; do
	case "${END_OF_OPT}${1}" in
	    -h | --help | help)	usage ;;
	    -p | --path)	shift; PATH_WORK=$(realpath "$1"); mkdir -p "${PATH_WORK}" ;;
	    -m | --manual)  	MANUAL=1 ;;
	    -n | --nokernel)   	NO_KERNEL=1 ;;
		 --nosign)	NO_SIGN=1 ;;
		 --noskel)	NO_SKEL=1 ;;
		 --nomodules)	NO_MODULES=1 ;;
	    -c | --noclean)	NO_CLEAN=1 ;;
	    -r | --osrelease)	OSRELEASE=1 ;;
	    -s | --sign-key)	shift; SIGN_KEY=$1 ;;
	    -u | --sign-user)	shift; SIGN_USER=$1 ;;
		 --sign-password) shift; SIGN_PASSWORD=$1 ;;
	         --ram)		BUILD_RAM=1 ;;
	    -q | --quiet)     	QUIET=1; QUIET_ARG="-q" ;;
	    -V | --version)	echo "Version: ${VERSION_SCRIPT}"; exit 0 ;;
	    --stdin)        	READ_STDIN=1 ;;
	    --)             	END_OF_OPT=1 ;;
	    -*|--*)         	echo "WARNING: Unrecognized argument, skiped: $1" >&2  ;;
	    *)              	POSITIONAL_ARGS+=("$1") ;;
	esac
	shift
    done
# Restore positional parameters
    set -- "${POSITIONAL_ARGS[@]}"
    [[ ${OSRELEASE} ]] && OS_RELEASE_PRETTY_NAME="$@"
}

detect_osrelease() {
    if [[ -z ${OS_RELEASE_PRETTY_NAME} ]]; then
	if [[ -n ${MANUAL} ]] && ls "${PATH_SRC_ISO}"/ublinux/VERSION_* &> /dev/null; then
	    OS_RELEASE_PRETTY_NAME="$(cat ${PATH_SRC_ISO}/ublinux/VERSION_* | head -1)"
	elif [[ -f /usr/lib/os-release ]]; then
	    OS_RELEASE_PRETTY_NAME="$(cat /usr/lib/os-release | grep "PRETTY_NAME=" | cut -d= -f2 | sed 's/"//g')"
	elif ls "${PATH_SRC_ISO}"/ublinux/VERSION_* &> /dev/null; then
	    OS_RELEASE_PRETTY_NAME="$(cat ${PATH_SRC_ISO}/ublinux/VERSION_* | head -1)"
	else
	    OS_RELEASE_PRETTY_NAME="UBLinux 0000 Unknown (x)"
	fi
    fi
    DISTRIB_NAME="$(${PATH_LIB_UBBOOT}/ubdistconv -n ${OS_RELEASE_PRETTY_NAME})"
    DISTRIB_CODENAME="$(${PATH_LIB_UBBOOT}/ubdistconv -d ${OS_RELEASE_PRETTY_NAME})"
    DISTRIB_VERSION="$(${PATH_LIB_UBBOOT}/ubdistconv -v ${OS_RELEASE_PRETTY_NAME})"
    prompt -i "OS detected: ${OS_RELEASE_PRETTY_NAME}"
}

prepare_structure() {
    local FILE_EFI_GRUB=$(cat <<'EOF'
if [ -e /boot/grub/grub.cfg ]; then
    set prefix=($root)/boot/grub
    configfile ($root)/boot/grub/grub.cfg
else
    search.file /grub.cfg root
    set prefix=($root)
    configfile ($root)/grub.cfg
fi
EOF
)
    local FILE_BOOT_GRUB=$(cat <<'EOF'
# Trying to remove embedded chainloader module and insert patched module with internal PE loader if it's exists
if test -f /boot/grub/mmod/chain.mod; then rmmod chain; insmod /boot/grub/mmod/chain.mod; fi

# Now trying to start unsigned grub*.efi (secure boot isn't enabled)
#chainloader /boot/grub/ublinux/grubx64.efi
#boot
#chainloader /boot/grub/ublinux/grubia32.efi
#boot

# In case when grubx64.efi wasn't started (secure boot is enabled)

configfile /boot/grub/ublinux/grub.cfg
EOF
)
    trim_src_iso() {
	find ${PATH_SRC_ISO} -name "*~" -delete 2>/dev/null
    }
    prepare_skel() {
	if [[ -z ${NO_SKEL} ]]; then
	    if [[ -d /usr/lib/grub  && -f ${PATH_LIB_UBBOOT}/ubboot-skel ]]; then
    		prompt -i "start update skeleton ublinux, ublinux-data, grub, grub-theme"
		rm -rdf "${PATH_SRC_ISO}/boot" "${PATH_SRC_ISO}/EFI"
		${PATH_LIB_UBBOOT}/ubboot-skel create ${QUIET_ARG} -sct "${DISTRIB_CODENAME}" -p "${PATH_SRC_ISO}" || prompt -eq "skelet iso not create!"
		install -dm0400 "${PATH_SRC_ISO}/EFI/BOOT/"
		echo "${FILE_EFI_GRUB}" > ${PATH_SRC_ISO}/EFI/BOOT/grub.cfg
		echo "${FILE_BOOT_GRUB}" > ${PATH_SRC_ISO}/boot/grub/grub.cfg
		cp -rf --no-preserve=mode,ownership "${PATH_TAMPL_ISO}"/* "${PATH_SRC_ISO}"/
		rm -f ${PATH_SRC_ISO}/ublinux/VERSION_*
		echo "${OS_RELEASE_PRETTY_NAME}" > "${PATH_SRC_ISO}/ublinux/$(${PATH_LIB_UBBOOT}/ubdistconv -s ${OS_RELEASE_PRETTY_NAME})"
	    else
    		prompt -eq "depends utility grub or ubboot not found!"
	    fi   
	fi
    }
    prepare_sgn() {
	if [[ -z ${NO_SIGN} ]]; then
	    local PATH_ROOT_GRUB="${PATH_SRC_ISO}/boot/grub/ublinux"
    	    local PATH_ROOT_UBLINUX="${PATH_SRC_ISO}/ublinux"
    	    if [[ -d ${PATH_ROOT_GRUB} ]]; then
    		prompt -i "start update GRUB config for sign iso '${PATH_ROOT_GRUB}'"
    		sed -i "s/SGNFILE_UBLINUX=.*/SGNFILE_UBLINUX=ublinux-iso.sgn/" "${PATH_ROOT_GRUB}/grub_var.cfg"
    		sed -i "s/SGNFILE_UBLINUX_DATA=.*/SGNFILE_UBLINUX_DATA=ublinux-data-iso.sgn/" "${PATH_ROOT_GRUB}/grub_var.cfg"
	    else
    		prompt -eq "GRUB config path '${PATH_ROOT_GRUB}' not found"
	    fi
	    if [[ -d ${PATH_ROOT_UBLINUX} ]]; then
    		prompt -i "start update sign '${PATH_ROOT_UBLINUX}'"
    		mv -f "${PATH_ROOT_UBLINUX}/ublinux.sgn" "${PATH_ROOT_UBLINUX}/ublinux-iso.sgn" &>/dev/null
	    else
    		prompt -eq "sign path '${PATH_ROOT_UBLINUX}' not found"
	    fi
	fi
    }
    prepare_modules() {
	local PATH_CURRENTSYS_UBM="/mnt/livemedia/ublinux"
	local PATH_CURRENTSYSDATA_UBM="/mnt/livemedia/ublinux-data"
	if [[ -z ${NO_MODULES} && -d ${PATH_CURRENTSYS_UBM} ]]; then
    	    prompt -i "start copy all local modules *.ubm to '${PATH_SRC_ISO}/ublinux/{base,modules,optional,machines}'"
	    rm -rf "${PATH_SRC_ISO}/ublinux/base/*" "${PATH_SRC_ISO}/ublinux/modules/*" "${PATH_SRC_ISO}/ublinux/optional/*" \
		"${PATH_SRC_ISO}/ublinux/machines/dynamic/*" "${PATH_SRC_ISO}/ublinux/machines/static/*"
	    [[ -d ${PATH_CURRENTSYS_UBM}/base ]] && install -CDm0400 -o root -g root "${PATH_CURRENTSYS_UBM}"/base/*.ubm "${PATH_SRC_ISO}"/ublinux/base/ 2>/dev/null
	    [[ -d ${PATH_CURRENTSYS_UBM}/modules ]] && install -CDm0400 -o root -g root "${PATH_CURRENTSYS_UBM}"/modules/*.ubm "${PATH_SRC_ISO}"/ublinux/modules/ 2>/dev/null
	    [[ -d ${PATH_CURRENTSYS_UBM}/optional ]] && install -CDm0400 -o root -g root "${PATH_CURRENTSYS_UBM}"/optional/*.ubm "${PATH_SRC_ISO}"/ublinux/optional/ 2>/dev/null
	    [[ -d ${PATH_CURRENTSYS_UBM}/machines/dynamic ]] && install -CDm0400 -o root -g root "${PATH_CURRENTSYS_UBM}"/machines/dynamic/*.ubm "${PATH_SRC_ISO}"/ublinux/machines/dynamic/ 2>/dev/null
	    [[ -d ${PATH_CURRENTSYS_UBM}/machines/static ]] && install -CDm0400 -o root -g root "${PATH_CURRENTSYS_UBM}"/machines/static/*.ubm "${PATH_SRC_ISO}"/ublinux/machines/static/ 2>/dev/null
	    if [[ -d ${PATH_CURRENTSYSDATA_UBM} ]]; then
		[[ -d ${PATH_CURRENTSYSDATA_UBM}/modules ]] && install -CDm0400 -o root -g root "${PATH_CURRENTSYSDATA_UBM}"/modules/*.ubm "${PATH_SRC_ISO}"/ublinux/modules/ 2>/dev/null
		[[ -d ${PATH_CURRENTSYSDATA_UBM}/optional ]] && install -CDm0400 -o root -g root "${PATH_CURRENTSYSDATA_UBM}"/optional/*.ubm "${PATH_SRC_ISO}"/ublinux/optional/ 2>/dev/null
		[[ -d ${PATH_CURRENTSYSDATA_UBM}/machines/dynamic ]] && install -CDm0400 -o root -g root "${PATH_CURRENTSYSDATA_UBM}"/machines/dynamic/*.ubm "${PATH_SRC_ISO}"/ublinux/machines/dynamic/ 2>/dev/null
		[[ -d ${PATH_CURRENTSYSDATA_UBM}/machines/static ]] && install -CDm0400 -o root -g root "${PATH_CURRENTSYSDATA_UBM}"/machines/static/*.ubm "${PATH_SRC_ISO}"/ublinux/machines/static/ 2>/dev/null
		if [[ -f ${PATH_CURRENTSYSDATA_UBM}/ublinux.ini ]]; then 
		    local PATH_EXTRACT_UBLINUXDATA=$(mktemp -d --tmpdir ublinux.data.XXXX)
		    install -Dm0400 -o root -g root "${PATH_CURRENTSYSDATA_UBM}"/ublinux.ini "${PATH_SRC_ISO}"/ublinux/ublinux.ini 2>/dev/null
		    tar xJf ${PATH_SRC_ISO}/ublinux/ublinux-data.tar.xz -C ${PATH_EXTRACT_UBLINUXDATA}/
		    install -Dm0400 -o root -g root "${PATH_CURRENTSYSDATA_UBM}"/ublinux.ini "${PATH_EXTRACT_UBLINUXDATA}"/ublinux-data/ublinux.ini 2>/dev/null
		    cd "${PATH_EXTRACT_UBLINUXDATA}"
		    tar -cvJf "${PATH_SRC_ISO}"/ublinux/ublinux-data.tar.xz "ublinux-data" >/dev/null 2>&1
		    rm -rdf ${PATH_EXTRACT_UBLINUXDATA}
		fi
	    fi
	fi
    }
    prepare_kernel() {
        local PATH_ROOT_UBLINUX="${PATH_SRC_ISO}/ublinux"
	if [[ -z ${NO_KERNEL} ]]; then
	    local PATH_EXTRACT_KERNEL=$(mktemp -d --tmpdir ublinux.kernel.XXXX)
    	    prompt -i "start copy ublinux-*, vmlinuz-* to '${PATH_ROOT_UBLINUX}'"
	    if ls "${PATH_ROOT_UBLINUX}"/base/001-linux-*-*-*.ubm &> /dev/null; then
		unsquashfs -q -f -d "${PATH_EXTRACT_KERNEL}" "${PATH_ROOT_UBLINUX}"/base/001-linux-*-*-*.ubm "usr/lib/modules/*-ublinux/ublinux-*" "usr/lib/modules/*-ublinux/vmlinuz-*"
		mv -f "${PATH_EXTRACT_KERNEL}"/usr/lib/modules/*-ublinux/ublinux-* "${PATH_EXTRACT_KERNEL}"/usr/lib/modules/*-ublinux/vmlinuz-* "${PATH_ROOT_UBLINUX}/" \
		    || prompt -eq "kernel and initrd 'ublinux-*, vmlinuz-*' from /mnt/livemedia/ublinux/base/001-linux-*-*-*.ubm not copy!"
		prompt -i "finish copy kernel and initrd 'ublinux-*, vmlinuz-*' from /mnt/livemedia/ublinux/base/001-linux-*-*-*.ubm"
	    elif ls /usr/lib/modules/*-ublinux/ublinux-* &> /dev/null && ls /usr/lib/modules/*-ublinux/vmlinuz-* &> /dev/null; then
		cp -f /usr/lib/modules/*-ublinux/ublinux-* /usr/lib/modules/*-ublinux/vmlinuz-* "${PATH_ROOT_UBLINUX}/" \
		    || prompt -eq "kernel and initrd '/usr/lib/modules/*-ublinux/{ublinux-*,vmlinuz-*}' not copy!"
		prompt -i "finish copy kernel and initrd '/usr/lib/modules/*-ublinux/{ublinux-*,vmlinuz-*}'"
	    elif ls /mnt/livemedia/ublinux/ublinux-* &> /dev/null && ls /mnt/livemedia/ublinux/vmlinuz-* &> /dev/null; then
		cp -f /mnt/livemedia/ublinux/ublinux-* /mnt/livemedia/ublinux/vmlinuz-* "${PATH_ROOT_UBLINUX}/" \
		    || prompt -eq "kernel and initrd '/mnt/livemedia/ublinux/{ublinux-*,vmlinuz-*}' not copy!"
		prompt -i "finish copy kernel and initrd '/mnt/livemedia/ublinux/{ublinux-*,vmlinuz-*}'"
	    elif ls /mnt/livemedia/ublinux/base/001-linux-*-*-*.ubm &> /dev/null; then
		unsquashfs -q -f -d "${PATH_EXTRACT_KERNEL}" /mnt/livemedia/ublinux/base/001-linux-*-*-*.ubm "usr/lib/modules/*-ublinux/ublinux-*" "usr/lib/modules/*-ublinux/vmlinuz-*"
		mv -f "${PATH_EXTRACT_KERNEL}"/usr/lib/modules/*-ublinux/ublinux-* "${PATH_EXTRACT_KERNEL}"/usr/lib/modules/*-ublinux/vmlinuz-* "${PATH_ROOT_UBLINUX}/" \
		    || prompt -eq "kernel and initrd 'ublinux-*, vmlinuz-*' from /mnt/livemedia/ublinux/base/001-linux-*-*-*.ubm not copy!"
		prompt -i "finish copy kernel and initrd 'ublinux-*, vmlinuz-*' from /mnt/livemedia/ublinux/base/001-linux-*-*-*.ubm"
	    else 
		prompt -eq "kernel 'vmlinuz' and initrd 'ublinux' not found!"
	    fi
	    rm -rdf ${PATH_EXTRACT_KERNEL}
	fi
        chmod -f 0400 "${PATH_ROOT_UBLINUX}"/ublinux-* "${PATH_ROOT_UBLINUX}"/vmlinuz-*
    }
    if [[ -z ${MANUAL} ]]; then
	trim_src_iso
	prepare_skel
	prepare_sgn 
	prepare_modules
	prepare_kernel
    fi
}

##########################################################################################################################################################################
# Создание core.img для USB образа
# Образ для загрузочного USB, используется вместе с /usr/lib/grub/i386-pc/boot.img
# 
# boot.img (из grub2) и core.img (делается grub-mkimage) записываются в MBR флешки или диска
# core.img представляет из себя загрузчик сделанный grub-mkimage
# В таком виде результатом работы команды будет файл core.img
##########################################################################################################################################################################
make_grub_core() {
    local PATH_GRUB_CORE=$(mktemp -d --tmpdir ublinux.grub.core.XXXX)
    prompt -i "generate core.img --format=i386-pc"
    grub-mkimage    --directory=/usr/lib/grub/i386-pc --compression=none \
		    --verbose --prefix=\(hd0,msdos1\)/EFI/BOOT \
		    --output="$1" --format=i386-pc \
		    part_gpt part_msdos biosdisk disk memdisk fat ntldr lvm exfat ext2 ntfs iso9660 gzio xzio test vbe vga normal search configfile \
		    linux linux16 chain loopback echo file halt reboot ls true gfxterm gettext font &>/dev/null
    rm -rdf ${PATH_GRUB_CORE}
}

##########################################################################################################################################################################
# Создание grubx64.efi	GPT загрузки (можно использовать при загрузке с HDD и ISO)
#
# grub.eltorito представляет из себя загрузчик сделанный grub-mkimage
# В таком виде результатом работы команды будет файл grubx64.efi который потом перименовывается в bootx64.efi
#
# - ./EFI/BOOT/grub.cfg файл настроек который зашивается внутрь grubx64.efi
##########################################################################################################################################################################
make_grub_grubx64() {
    local PATH_GRUBX64=$(mktemp -d --tmpdir ublinux.grubx64.efi.XXXX)
    local FILE_GRUB_CFG="${PATH_GRUBX64}/grub.cfg"
cat <<'EOF' >${FILE_GRUB_CFG}
search.file --no-floppy --set=root /EFI/BOOT/grub.cfg
configfile /EFI/BOOT/grub.cfg
EOF
#if [ -e /EFI/BOOT/grub.cfg ]; then
#    set prefix=($root)/EFI/BOOT
#    configfile ($root)/EFI/BOOT/grub.cfg
#else
#    search.file /grub.cfg root
#    set prefix=($root)
#    configfile ($root)/grub.cfg
#fi
    prompt -i "generate bootx64.efi --format=x86_64-efi"
    grub-mkimage    --directory=/usr/lib/grub/x86_64-efi --compression=auto \
		    --config=${FILE_GRUB_CFG} --verbose --prefix=/EFI/BOOT \
		    --output="$1" --format=x86_64-efi \
		    part_gpt part_msdos disk memdisk fat exfat lvm ext2 ntfs iso9660 normal gzio xzio test search configfile linux linux16 chain \
		    loopback echo efi_gop efi_uga file halt reboot ls true gfxterm gettext font &>/dev/null
    rm -rdf ${PATH_GRUBX64}
}
##########################################################################################################################################################################
make_grub_grubia32() {
    local PATH_GRUBIA32=$(mktemp -d --tmpdir ublinux.grubia32.efi.XXXX)
    local FILE_GRUB_CFG="${PATH_GRUBIA32}/grub.cfg"
cat <<'EOF' >${FILE_GRUB_CFG}
search.file --no-floppy --set=root /EFI/BOOT/grub.cfg
configfile /EFI/BOOT/grub.cfg
EOF
    prompt -i "generate bootia32.efi --format=i386-efi"
    grub-mkimage    --directory=/usr/lib/grub/i386-efi --compression=auto \
		    --config=${FILE_GRUB_CFG} --verbose --prefix=/EFI/BOOT \
		    --output="$1" --format=i386-efi \
		    part_gpt part_msdos disk memdisk fat exfat lvm ext2 ntfs iso9660 normal gzio xzio test search configfile linux linux16 chain \
		    loopback echo efi_gop efi_uga file halt reboot ls true gfxterm gettext font &>/dev/null
    rm -rdf ${PATH_GRUBIA32}
}

##########################################################################################################################################################################
# Создание grub2.eltorito для CDROM
#
# grub2.eltorito представляет из себя загрузчик сделанный grub-mkimage
# В таком виде результатом работы команды будет файл grub2.eltorito
#
# - ./EFI/BOOT/grub.cfg файл настроек который зашивается внутрь grub2.eltorito
##########################################################################################################################################################################
make_grub_eltorito() {
    local PATH_GRUB_ELTORITO=$(mktemp -d --tmpdir ublinux.grub.eltorito.XXXX)
    local FILE_GRUB_CFG="${PATH_GRUB_ELTORITO}/grub.cfg"
    cat <<'EOF' >${FILE_GRUB_CFG}
search.file --no-floppy --set=root /EFI/BOOT/grub.cfg
configfile /EFI/BOOT/grub.cfg
EOF
    prompt -i "generate grub-eltorito --format=i386-pc-eltorito"
    grub-mkimage    --directory=/usr/lib/grub/i386-pc --compression=auto \
		    --config=${FILE_GRUB_CFG} --verbose --prefix=/EFI/BOOT \
		    --output="$1" --format=i386-pc-eltorito \
		    part_msdos biosdisk disk fat iso9660 test vbe vga normal gzio xzio search configfile linux linux16 chain loopback echo file \
		    halt reboot ls true gfxterm gettext font &>/dev/null
    rm -rdf ${PATH_GRUB_ELTORITO}
}

make_grub_eltorito_img() {
    local PATH_GRUB_ELTORITO_IMG=$(mktemp -d --tmpdir ublinux.grub-eltorito.img.XXXX)
    prompt -i "make grub-eltorito.img"
    dd if=/dev/zero of="$1" bs=1K count=2000 &> /dev/null
    mkfs.vfat -F12 -n EFI "$1" &>/dev/null
    mkdir -p ${PATH_GRUB_ELTORITO_IMG}/EFI/BOOT
    cat <<'EOF' >${PATH_GRUB_ELTORITO_IMG}/EFI/BOOT/grub.cfg
search.file --no-floppy --set=root /EFI/BOOT/grub.cfg
configfile /EFI/BOOT/grub.cfg
EOF
    cp -f "$2" "$3" ${PATH_GRUB_ELTORITO_IMG}/EFI/BOOT/
    cd ${PATH_GRUB_ELTORITO_IMG}
    find ./* -type d -exec mmd -i "$1" "::{}" \;
    find ./* -type f -exec mcopy -i "$1" "{}" "::{}" \;
    rm -rdf ${PATH_GRUB_ELTORITO_IMG}
}

##########################################################################################################################################################################
#
# ${VOLID} - переменная задает метку диска, желательно для совместимости метку задавать в ВЕРХНЕМ регистре.
# -b grub2.eltorito - файл загрузчика в формате eltorito внутри образа, в данном случае файл находится в корне образа.
# -grub2-mbr /usr/lib/grub/i386-pc/boot_hybrid.img - путь к образу mbr из состава grub2 (тоже самое по сути делает -isohybrid-mbr). Этот образ только заготовка.
# -grub2-boot-info grub2.eltorito -  пареметр имеет значение, которое задает имя загрузчика которое будет прописываться в загрузочную запись. В данном случае grub2.eltorito.
#  grub2.eltorito представляет из себя загрузчик сделанный grub-mkimage
# -append-partition 2 0xef /usr/lib/grub/efi.img - добавляет в iso образ раздел из нашего файла efi.img, тип раздела выставляется 0xef EFI.
# -eltorito-alt-boot --efi-boot EFI/BOOT/bootx64.efi - делает iso загружаемым через EFI. bootx64.efi находится внутри iso, 
#  рядом с ним можно разместить файлы конфигурации, локализации, шрифта.
#
# grub2.eltorito представляет из себя загрузчик сделанный grub-mkimage
##########################################################################################################################################################################
make_file_iso() {
    local FILE_ISO="$1/${DISTRIB_CODENAME}_${DISTRIB_VERSION}.iso"
    VOLID="${DISTRIB_CODENAME^^}_${DISTRIB_VERSION}"
    APPID="UBLinux CD"
    PUBLISHER="UBLinux <https://www.ublinux.ru>"
    PREPARER="prepared UBLinux team"
    xorriso -as mkisofs -allow-lowercase -J -D -R \
	    -appid "${APPID}" -volid "${VOLID}" -publisher "${PUBLISHER}" -preparer "${PREPARER}" \
	    -no-emul-boot -boot-load-size 4 -hide boot.catalog -boot-info-table \
	    -b grub-eltorito --grub2-mbr /usr/lib/grub/i386-pc/boot_hybrid.img \
	    -boot-info-table --grub2-boot-info "${FILE_GRUBELTORITO}" \
	    -append_partition 2 0xef "${FILE_GRUBELTORITO_IMG}" \
	    -eltorito-alt-boot --efi-boot EFI/BOOT/bootx64.efi \
	    -no-emul-boot \
	    -o ${FILE_ISO} ${PATH_SRC_ISO}
    prompt -s "FINISH: build iso: ${FILE_ISO}"
}

##########################################################################################################################################################################
# Размещение загрузчика MBR на флешке или диске
# файл boot.img - стандартный файл из комплекта grub2, это содержимое нулевого сектора диска. Есть еще файл boot_hybrid.img
# файл core.img - этот файл делается grub-mkimage, только выходной формат файла выставляется другой.
# Командой grub-bios-setup или dd, примеры (/dev/sdb заменить на свою флешку):
# grub-bios-setup -d. -b /usr/lib/grub/i386-pc/boot.img -c ./core.img /dev/sdb
# или
# dd if=/usr/lib/grub/i386-pc/boot.img of=/dev/sdb bs=446 count=1
# dd if=./core.img of=/dev/sdb bs=512 seek=1
# 
##########################################################################################################################################################################
write_mbr() {
    echo
}

generate_sums_sign() {
    local FILE_ISO="${DISTRIB_CODENAME}_${DISTRIB_VERSION}.iso"
    cd $1
    echo
    prompt -i "generate md5 sums ${FILE_ISO}"
    md5sum ${FILE_ISO} > $1/md5sums.txt &
    prompt -i "generate sha1 sums ${FILE_ISO}"
    sha1sum ${FILE_ISO} > $1/sha1sums.txt &
    prompt -i "generate sha256 sums ${FILE_ISO}"
    sha256sum ${FILE_ISO} > $1/sha256sums.txt &
    prompt -i "generate b2 sums ${FILE_ISO}"
    b2sum ${FILE_ISO} > $1/b2sums.txt &
    prompt -i "generate gost12sum ${FILE_ISO}"
    gost12sum ${FILE_ISO} > $1/gost12sum.txt &
    if [[ -n ${SIGN_KEY} ]]; then
	prompt -i "sign the ${FILE_ISO} with signature ${SIGN_KEY}"
	[[ -n ${SIGN_USER} ]] && PATH_GNU_HOME="--homedir /home/${SIGN_USER}/.gnupg"
	[[ -n ${SIGN_PASSWORD} ]] && CMD_SIGN_PASSWORD="--pinentry-mode loopback --passphrase "${SIGN_PASSWORD}""
	gpg --yes ${PATH_GNU_HOME} ${CMD_SIGN_PASSWORD} --detach-sign --use-agent -u "${SIGN_KEY}" $1/*.iso
	    #GNUPGHOME=/home/${SIGN_USER}/.gnupg gpg --yes --detach-sign --use-agent -u "${SIGN_KEY}" $1/*.iso
    fi
    wait
}

###############################
###   :::   M A I N   :::   ###
###############################

    PKGNAME=${0##*/}
    PATH_WORK=${PWD}
    set_color
    check_root

    PATH_SRC_ISO="${PATH_WORK}/src"
    PATH_TAMPL_ISO="/usr/share/ubiso/template"
    PATH_LIB_UBBOOT="/usr/lib/ubboot"
    FILE_GRUBX32="${PATH_WORK}/core.img"
    FILE_GRUBX64="${PATH_SRC_ISO}/EFI/BOOT/bootx64.efi"
    FILE_GRUBIA32="${PATH_SRC_ISO}/EFI/BOOT/bootia32.efi"
    FILE_GRUBELTORITO="${PATH_WORK}/grub-eltorito"
    FILE_GRUBELTORITO_IMG="${PATH_WORK}/grub-eltorito.img"

    arguments $@
    detect_osrelease
    prepare_structure
    make_grub_core "${FILE_GRUBX32}"
    make_grub_grubx64 "${FILE_GRUBX64}"
    make_grub_grubia32 "${FILE_GRUBIA32}"
    make_grub_eltorito "${FILE_GRUBELTORITO}"
    make_grub_eltorito_img "${FILE_GRUBELTORITO_IMG}" "${FILE_GRUBX64}" "${FILE_GRUBIA32}"

    if [[ -n ${BUILD_RAM} ]]; then
	PATH_WORK_TMP=$(mktemp -d --tmpdir ublinux.iso.XXXX)
	make_file_iso "${PATH_WORK_TMP}"
	generate_sums_sign "${PATH_WORK_TMP}"
	prompt -i "copy files ${PATH_WORK_TMP}/ to the destination directory ${PATH_WORK}/"
	rsync -a --info=progress2 "${PATH_WORK_TMP}/" "${PATH_WORK}/"
	rm -rdf "${PATH_WORK_TMP}"
    else
	make_file_iso "${PATH_WORK}"
	generate_sums_sign "${PATH_WORK}"
    fi
    
    if [[ -z ${MANUAL} && -z ${NO_SKEL} && -z ${NO_MODULES} && -z ${NO_CLEAN} ]]; then 
	prompt -i "clean sources ${PATH_SRC_ISO}"
	rm -rdf ${PATH_SRC_ISO}
	rm -f ${FILE_GRUBX32}
	rm -f ${FILE_GRUBX64}
	rm -f ${FILE_GRUBIA32}
	rm -f ${FILE_GRUBELTORITO}
	rm -f ${FILE_GRUBELTORITO_IMG}
    fi
    sync; sync; sync; echo 3 > /proc/sys/vm/drop_caches
