#!/bin/bash

# Maintainer: Dmitry Razumov <http://ublinux.ru>

# Functions library :: for Linux Live Kit scripts & UIRD init
# Author: Tomas M. <http://www.linux-live.org>
#
# Author: Mikhail Zaripov <http://magos-linux.ru>
# Author: Anton Goroshkin <http://magos-linux.ru>
# Author: Alexander Betkher <http://magos-linux.ru>

# Colors text
#Black        0;30     Dark Gray     1;30
#Blue         0;34     Light Blue    1;34
#Green        0;32     Light Green   1;32
#Cyan         0;36     Light Cyan    1;36
#Red          0;31     Light Red     1;31
#Purple       0;35     Light Purple  1;35
#Brown/Orange 0;33     Yellow        1;33
#Light Gray   0;37     White         1;37
	
	black='\033[0;30m'
	red='\033[0;31m'
	green='\033[0;32m'
	yellow='\033[1;33m'
	brown='\033[0;33m'
	blue='\033[0;34m'
	light_blue='\033[1;34m'
	magenta='\033[1;35m'
	cyan='\033[0;36m'
	white='\033[0;37m'
	purple='\033[0;35m'
	default='\033[0m'

# BINARY
BIN_BTFS=/sbin/btfs
BIN_RSYNC=/sbin/rsync
BIN_HTTPFS=/sbin/httpfs
BIN_CURLFTPFS=/sbin/curlftpfs
BIN_SSHFS=/sbin/sshfs
BIN_GETTEXT=/sbin/gettext
BIN_NTFSFIX=/sbin/ntfsfix
BIN_FSCK=/sbin/fsck
BIN_BTRFSCK=/sbin/btrfsck
BIN_BLKID=/sbin/blkid.real
BIN_LOSETUP=/sbin/losetup.real

[ -f $BIN_GETTEXT ] && GETTEXT=gettext || GETTEXT=f_gettext

FSCHECKED=""
MOUNTBINDS=""
LOGFILE=/var/log/initrd.dbg.log

f_gettext() {
	local TEXT='' STR
	STR="$(echo $1 | sed 's#\/#\\/#g')"
	TDOMAIN=${TEXTDOMAINDIR}/$(echo $LANG | sed 's/_.*$//')/LC_MESSAGES/${TEXTDOMAIN}.po
	[ -f $TDOMAIN ] && TEXT="$(cat $TDOMAIN | sed -ne "/\"$STR\"/{n;p;}" | sed -e 's/^msgstr\ *\"//' -e 's/\"$//')"
	if [ -n "$TEXT" ]; then
		echo -n $TEXT
	else
		echo -n $1
	fi
}

# Messages
INIT_UNION=$($GETTEXT "Initializing filesystem")
INIT_LAYER=$($GETTEXT "Initializing:")
BINDING_TO_UNION=$($GETTEXT "Binding to union rootfs")

MOUNT_DATA_SOURCE=$($GETTEXT "Searching and initializing source:")
MOUNT_DATA_SOURCE_USING="    "$($GETTEXT "using source:")
MOUNT_DATA_SOURCE_NOT_FOUND="    "$($GETTEXT "source not found or not initialized")
MOUNT_DATA_SOURCE_ASK="    "$($GETTEXT "[S]hutdown, [R]eboot, [C]ontinue, [T]ry again ?")

TESTING_FOR_POSIX=$($GETTEXT "Testing filesystem for POSIX compatibility")
POSIX_NOT_COMPATIBLE="    "$($GETTEXT "POSIX not available, using POSIXOVL")
POSIX_TEST=$($GETTEXT "Writing is not available, using RAM")

SETUP_CONFIG=$($GETTEXT "Searching and initializing configuration file:")
SETUP_CONFIG_USING="  "$($GETTEXT "using configuration file:")
SETUP_CONFIG_NOTFOUND="  "$($GETTEXT "configuration file not found, using default parameters")
SETUP_CHANGES=$($GETTEXT "Initializing source for persistent changes:")
SETUP_CHANGES_USING="  "$($GETTEXT "using for changes:")
SETUP_MACHINES=$($GETTEXT "Initializing source for machine-depended changes:")
SETUP_MACHINES_MOD=$($GETTEXT "Searching bundle for machine-depended changes:")
SETUP_MACHINES_UNPACKING=$($GETTEXT "unpacking")
SETUP_MACHINES_TO_RAM=$($GETTEXT "to RAM")
SETUP_HOMES=$($GETTEXT "Mounting sources for homes directories:")

SETUP_SWAP=$($GETTEXT "Trying to enable SWAP")
RESIZE_TMPFS=$($GETTEXT "Resizing TMPFS to -")
SETUP_SYSCP=$($GETTEXT "Copying some files to system")

INIT_IFCFG=$($GETTEXT "Initializing network services")
PREPARING_BUNDLES=$($GETTEXT "Preparing layers for")
COPY_TO_RAM=$($GETTEXT "Copy data to RAM, this may take a long time, waiting...")
COPY_TO_CACHE=$($GETTEXT "Copy data to CACHE, this may take a long time, waiting...")

FIND_DATA=" - "$($GETTEXT "waiting, it is searching and mounting source\r")
FSCK_DEVICE=$($GETTEXT "Checking filesystem:")
EXPAND_DEVICE=$($GETTEXT "Expand partition:")
MOUNT_DEVICE_ENC=$($GETTEXT "Mounting encrypted filesystem:")
NOT_ENOUGH_MEMORY=$($GETTEXT "not enough memory.")

INITIALIZE=$($GETTEXT "Initializing")
FREE_SPACE_LESS_THEN_CHECK="    $($GETTEXT "Free space less then CHECKSPASE")"
FREE_SPACE_LESS_THEN_CHECK_ASK="    $($GETTEXT "[S]hutdown, [R]eboot, [C]ontinue, [E]rase-and-continue ?")"

ENC_PASS=$($GETTEXT "Password for encrypted FS:")
LUKS_PASS=$($GETTEXT "Password for LUKS partition:")

TRY_CREATE=$($GETTEXT "Trying to create")
NOT_FOUND_CREATE=$($GETTEXT "was not found, create it?")
ENTER_FS_TYPE=$($GETTEXT "enter FS type")
ENTER_SIZE=$($GETTEXT "enter new image size Mb")
ENTER_PASSWORD=$($GETTEXT "enter password")

# text for shutdown
REMOUNT_FOR_SAVES=$($GETTEXT "Remounting media for saves...")
REMOUNT_COMPLETE=$($GETTEXT "Remount complete")
NO_FILE=$($GETTEXT "no such file!")
READY_TO_SAVE=$($GETTEXT "The system is ready to save changes to the")
SAVE_CHANGES=$($GETTEXT "Saving changes...")
MERGING=$($GETTEXT "Merging old module and session "changes", it may take a long time")
SHTD_STARTED=$($GETTEXT "Initrd shutdown started!")
UMOUNT=$($GETTEXT "Umount")
PASSWD_ENTER=$($GETTEXT "Please enter password for LUKS partition")
WAITING_FOR=$($GETTEXT "Waiting for")
LUKS_ERROR=$($GETTEXT "Luks setup - error!, try again")
COMPLETE=$($GETTEXT "Complete!")
OLD_MODULE_EXISTS=$($GETTEXT "Old module exists...")
PREPARING_EXCLUDES=$($GETTEXT "Please wait. Preparing excludes for module")
SAVING_CHANGES=$($GETTEXT "Please wait. Saving changes to module")
WAS_NOT_SAVED=$($GETTEXT "System changes was not saved to")
NO_DIR=$($GETTEXT "No such directory:")
REMOUNT_RO=$($GETTEXT "Remount RO:")

##### UIRD cmdline parameters aliases

# uird.basecfg=              - расположение базового конфигурационного файла basecfg.ini
# uird.config=               - расположение конфигурационного файла системы ublinux.ini
# uird.sgnfiles[+]=          - перечисление файлов-маркеров для поиска источников указанных в uird.from= в соответствии с их порядком перечисления
# uird.ro[+]=                - фильтр для модулей, которые монтируются в режиме RO
# uird.rw[+]=                - фильтр для модулей, которые монтируются в режиме RW
# uird.cp[+]=                - фильтр для модулей, содержимое которых копируется в корень
# uird.copy2ram[+]=          - фильтр для модулей, которые копируются в RAM
# uird.copy2cache[+]=        - фильтр для модулей, которые копируются в КЭШ
# устаревший: uird.ramsize=  - размер RAM
# uird.ip=                   - IP:GW:MASK , если не указан, то используется DHCP
# uird.netfsopt[+]=          - дополнительные опции монтирования сетевых ФС: sshfs,nfs,curlftpfs,cifs
# uird.load[+]=              - фильтр для модулей, которые необходимо подключить на этапе загрузки
# uird.noload[+]=            - фильтр для модулей, которые необходимо пропустить во время загрузки
# uird.from[+]=              - источники, где лежат модули для системы
# uird.cache[+]=             - источники, в которые стоит синхронизировать модули
# uird.homes[+]=             - источники, где хранятся домашние директории пользователей
# uird.home=                 - источник, где хранится домашняя директория пользователей
# uird.changes=              - источник, где хранить персистентные изменения
# uird.mode=                 - режим работы с сохрананиями
# uird.mounts[+]=            - источники, которые необходимо примонтировать
# uird.find_params[+]=       - параметры для утилиты find при поиске модулей
# uird.help                  - печатает подсказку по параметрам UIRD
# uird.break=                - остановка загрузки на определенном этапе и включение режима отладки
# uird.syscp[+]=             - список файлов (каталогов) для копирования из UIRD в систему /путь/файл::/путь/каталог
# uird.parallel              - параллельное монтирование модулей
# uird.run[+]=               - запуск внешних исполняемых файлов
# устаревший: uird.zram      - использовать zram вместо tmpfs
# uird.rootfs=               - zram/tmpfs тип фс для /memory
# uird.preinit               - обработка ини файла задданного в uird.config
# uird.shutdown              - создание /run/initramfs
# quickshell, qs             - консоль на начальном этапе работы uird-init
# qse                        - консоль в конце работы uird-init
# debug                      - подробный вывод и приостановка uird-init на нескольких этапах работы
# uird.silent                - no output
# uird.hide                  - не перемонтировать $SYSMNT из rootfs initrd в системный rootfs
# uird.mntlinks              - coздавать ссылки live, livemedia, livedata в /mnt

[ -f "/uird_configs/uird_aliases" ] && . /uird_configs/uird_aliases
[ -z $UIRD_BASECFG ] && UIRD_BASECFG=uird.basecfg
[ -z $UIRD_CONFIG ] && UIRD_CONFIG=uird.config
[ -z $UIRD_SGNFILES ] && UIRD_SGNFILES=uird.sgnfiles
[ -z $UIRD_RO ] && UIRD_RO=uird.ro
[ -z $UIRD_RW ] && UIRD_RW=uird.rw
[ -z $UIRD_CP ] && UIRD_CP=uird.cp
[ -z $UIRD_RUN ] && UIRD_RUN=uird.run
[ -z $UIRD_COPY2RAM ] && UIRD_COPY2RAM=uird.copy2ram
[ -z $UIRD_COPY2CACHE ] && UIRD_COPY2CACHE=uird.copy2cache
[ -z $UIRD_RAMSIZE ] && UIRD_RAMSIZE=uird.ramsize
[ -z $UIRD_IP ] && UIRD_IP=uird.ip
[ -z $UIRD_NETFSOPT ] && UIRD_NETFSOPT=uird.netfsopt
[ -z $UIRD_LOAD ] && UIRD_LOAD=uird.load
[ -z $UIRD_NOLOAD ] && UIRD_NOLOAD=uird.noload
[ -z $UIRD_FROM ] && UIRD_FROM=uird.from
[ -z $UIRD_CACHE ] && UIRD_CACHE=uird.cache
[ -z $UIRD_HOMES ] && UIRD_HOMES=uird.homes
[ -z $UIRD_HOME ] && UIRD_HOME=uird.home
[ -z $UIRD_CHANGES ] && UIRD_CHANGES=uird.changes
[ -z $UIRD_MOUNTS ] && UIRD_MOUNTS=uird.mounts
[ -z $UIRD_FIND_PARAMS ] && UIRD_FIND_PARAMS=uird.find_params
[ -z $UIRD_HELP ] && UIRD_HELP=uird.help
[ -z $UIRD_BREAK ] && UIRD_BREAK=uird.break
[ -z $UIRD_SCAN ] && UIRD_SCAN=uird.scan
[ -z $UIRD_SWAP ] && UIRD_SWAP=uird.swap
[ -z $UIRD_MODE ] && UIRD_MODE=uird.mode
[ -z $UIRD_SYSCP ] && UIRD_SYSCP=uird.syscp
[ -z $UIRD_ARIA2RAM ] && UIRD_ARIA2RAM=uird.aria2ram
[ -z $UIRD_FORCE ] && UIRD_FORCE=uird.force
[ -z $UIRD_ZRAM ] && UIRD_ZRAM=uird.zram
[ -z $UIRD_FREEMEDIA ] && UIRD_FREEMEDIA=uird.freemedia
[ -z $UIRD_PARALLEL ] && UIRD_PARALLEL=uird.parallel
[ -z $UIRD_UNION ] && UIRD_UNION=uird.union
[ -z $UIRD_SHUTDOWN ] && UIRD_SHUTDOWN=uird.shutdown
[ -z $UIRD_PREINIT ] && UIRD_PREINIT=uird.preinit
[ -z $UIRD_ROOTFS ] && UIRD_ROOTFS=uird.rootfs
[ -z $UIRD_SILENT ] && UIRD_SILENT=uird.silent
[ -z $UIRD_HIDE ] && UIRD_HIDE=uird.hide
[ -z $UIRD_MNTLINKS ] && UIRD_MNTLINKS=uird.mntlinks

# =================================================================
# debug and output functions
# =================================================================
debug_start() {
	# global variable
	DEBUG_IS_ENABLED=$(sed s/$/" "/ /proc/cmdline 2>/dev/null | grep " debug ")
}

debug_log() {
	if [ "$DEBUG_IS_ENABLED" ]; then
		echo "- debug: $*" >&2
		log "- debug: $*"
	fi
}

# header
# $1 = text to show
#
header() {
	if ! getpar $UIRD_SILENT >/dev/null; then
		echo ''
		echolog "\\033[0;1m""$@""\\033[0;0m"
		echo ''
	fi
}

# echo green star
#
echo_green_star() {
	if ! getpar $UIRD_SILENT >/dev/null; then
		echo -ne $green"* "$default >/dev/console 2>/dev/console
	fi
}

echo_blue_star() {
	if ! getpar $UIRD_SILENT >/dev/null; then
		echo -ne $blue"  * "$default >/dev/console 2>/dev/console
	fi
}

# log - store given text in /var/log/initrd.dbg.log
log() {
	echo "$@" 2>/dev/null >>$LOGFILE
}

echolog() {
	local text
	text="$(echo "$@" | sed 's:\\\033\[[[:digit:]];*[[:digit:]]*m::g')"
	log "$text"
	if ! getpar $UIRD_SILENT >/dev/null; then
		if plymouth --ping 2>/dev/null; then
			plymouth display-message --text="$text"
		else
			echo -e "$@" >/dev/console 2>&1
		fi
	fi
}

# show information about the debug shell
show_debug_banner() {
	echo
	echo "====="
	echo ": Debugging started. Here is the root shell for you."
	echo ": Type your desired commands or hit Ctrl+D to continue booting."
	echo
}

# debug_shell
# executed when debug boot parameter is present
#
debug_shell() {
	if [ "$DEBUG_IS_ENABLED" ]; then
		[[ -f /bin/plymouth ]] && plymouth quit
		show_debug_banner
		setsid sh -c 'exec sh < /dev/tty1 >/dev/tty1 2>&1'
		echo
	fi
}
# start shell
# if $1==help then start shell
shell_cmd() {
	[ "$SECLEVEL" -gt 2 ] && return
	[[ -f /bin/plymouth ]] && plymouth --ping >/dev/null 2>&1 && plymouth quit 2>/dev/null
	ln -s /root/bashrc /root/.bashrc 2>/dev/null
	ln -s /root/bash_profile /root/.bash_profile 2>/dev/null
	echo
	if [ "$1" = "shell" ]; then
		echo "============== SHELL MODE ============="
		setsid bash -c 'exec bash autologin < /dev/tty1 >/dev/tty1 2>&1'
		echo
	elif [ "$1" = "help" ]; then
		echo "============== HELP SHELL MODE ============="
		setsid bash -c 'exec bash autologin < /dev/tty1 >/dev/tty1 2>&1'
		reboot -f
	elif [ "$1" = "break" ]; then
		echo "============== BREAK SHELL MODE ============="
		DEBUG_IS_ENABLED=1
		setsid bash -c 'exec bash autologin < /dev/tty1 >/dev/tty1 2>&1'
		echo
	fi
}

# start quickshell
start_quickshell() {
	if getpar qs >/dev/null; then
		[ "$SECLEVEL" -gt 2 ] && return
		[[ -f /usr/bin/plymouth ]] && plymouth --ping >/dev/null 2>&1 && plymouth quit
		ln -s /root/bashrc /root/.bashrc
		ln -s /root/bash_profile /root/.bash_profile
		mkdir -p /mnt
		automount
		clear
		cat /usr/share/uird.help/${LANG}/uird.quickshell.help 2>/dev/null || cat /usr/share/uird.help/uird.quickshell.help
		shell_cmd shell
		cd /
		umount /mnt/*
		echo "continue...."
	fi
}

# Resume from swsuspend
resume_from_suspend() {
	if ! getpar noresume >/dev/null; then
		RESUME_DEV=$($BIN_BLKID | grep -m1 swsuspend | awk -F: '{print $1}')
		[ -z "$RESUME_DEV" ] || resume $RESUME_DEV
	fi
}

fatal() {
	echolog
	header "Fatal error occured - $1"
	echolog "Something went wrong and we can't continue. This should never happen."
	echolog "Please reboot your computer with Ctrl+Alt+Delete ..."
	echolog
	setsid sh -c 'exec sh < /dev/tty1 >/dev/tty1 2>&1'
}

#============================================================
# UBLinux debug functions
#============================================================
# enabling logging mode for script by DEBUG_IS_ENABLED=yes
# or for all scripts by "debug" cmdline parametr
debug_mode() {
	if [ "$DEBUG_IS_ENABLED" -o "$DEBUGMODE" == "yes" ]; then
		name=$(basename $0)
		slash="/"
		[ "$(pwd)" == "/union" ] && slash=""
		if ! test -f ${slash}var/log/ublinux/${name}.log; then
			echo "$0 --  debug mode enabled"
			test -d ${slash}var/log/ublinux || mkdir -p ${slash}var/log/ublinux
			echo $(date) >${slash}var/log/ublinux/${name}.log || echo "can not create log file"
			$0 "$@" 2>&1 | tee -a ${slash}var/log/ublinux/${name}.log
			exit 0
		fi
	fi
}

# echo $1 text, only if debug is enabled by DEBUG_IS_ENABLED=yes or "debug" cmdline parametr
# if $2 exists execute it
# if $3 and other paramenrs exists add them like params to $2
# echodebug "text" sleep 5 (echo "text", and wait 5 sec, time to read)
# echodebug "text" read aaa (echo "text", and wait to push ENTER)
echodebug() {
	[ "$DEBUG_IS_ENABLED" -o "$DEBUGMODE" == "yes" ] && echo "$1"
	if [ -n "$2" ]; then
		command=$2
		shift
		shift
		if [ -z $1 ]; then
			$command
		else
			$command "$@"
		fi
	fi
}

cfg_parser_pre() {
	getcmdline >/tmp/cmdline
	if [ "$SECLEVEL" -gt 0 ]; then
		echo $(cat /proc/cmdline /tmp/cmdline 2>/dev/null | sed 's/(.*)//' | tr -s ";" ",") >/tmp/cmdline #'
	else
		eval echo $(cat /proc/cmdline /tmp/cmdline 2>/dev/null | sed 's/(.*)//' | tr -s ";" ",") >/tmp/cmdline #'
	fi
	BASECFG=$(echo -n " " | cat - /tmp/cmdline 2>/dev/null | grep -E -m1 -o "(^|[[:space:]])$UIRD_BASECFG=[^[:space:]]+" | cut -d "=" -f 2- | head -n1) #"
	[ -f "$BASECFG" -o "$BASECFG" == "help" ] || BASECFG=/uird_configs/$BASECFG
	if ! [ -f "$BASECFG" -o "$BASECFG" == "help" ]; then
		echo "$BASECFG is not correct $UIRD_BASECFG value"
		shell_cmd "help"
	fi
	echo $(cat $BASECFG | grep -v "^[[:space:]]*\#" 2>/dev/null | tr -s ";" ",") >/tmp/basecfg
	echo '' >>/tmp/basecfg
	[ "$SECLEVEL" -lt 5 ] && echo $(cat /tmp/cmdline | tr -s ";" "," | sed 's/ /\n/g' | sort -u) >>/tmp/basecfg
	echo '' >>/tmp/basecfg
	cfg_parser
}

cfg_parser() {
    for par in $(cat /tmp/basecfg); do
	echo $par | grep -q "^-" && continue
	if echo "$par" | grep -q "+="; then
	    parDir=$(echo "$par" | cut -d "+" -f1)
	    separ="+="
	else
	    parDir=$(echo "$par" | cut -d "=" -f1)
	    rm -rf /tmp/parameters/$parDir 2>/dev/null
	    separ="="
	fi
	mkdir -p /tmp/parameters/$parDir
	NUM_PAR=$(( $(ls -1 /tmp/parameters/$parDir | wc -l) +1 ))
	set -f
	if echo $par | grep -q "="; then
	    for val in $(echo "$par" | sed "s/${parDir}${separ}//" | tr -s ";," " "); do
	        echo "$val" | grep -q ^\{.*}$ && val="$(echo "$val" | sed 's/[\{,\}]//g')::FORCE=yes"
		for value in $(echo "$val" | sed 's/::/ /g'); do
		    [ ! -e /tmp/parameters/$parDir/$NUM_PAR ] && value=$(uuid_label_to_dev "$value")
	            echo "$value" >> /tmp/parameters/$parDir/$NUM_PAR
		done
	        NUM_PAR=$((NUM_PAR + 1))
	    done
		
	echo "$par" | sed -re 's/^([^=]*)\.([^=]*\=.*)$/\1_\2/' -e 's/^([[:digit:]].*)$/_&/' >> /etc/initvars
	else
	    : > /tmp/parameters/$parDir/enabled
	    echo "${par}=enabled" | sed -re 's/^(.*)\.(.*\=.*)$/\1_\2/' -e 's/^([[:digit:]].*)$/_&/' >> /etc/initvars
	fi
	set +f
    done
#tar -czf $SYSMNT/parameters.tar.gz /tmp/parameters &
}

old_pars_compat() {
	local sgn par str
	for par in $UIRD_FROM $UIRD_HOME $UIRD_MOUNTS; do
		for file in $(getpar $par); do
			getpar $par $file "2,$" | while read str; do
			    if echo $str | grep -q ^/[[:alnum:]]?*.*$; then
			        echo "MNT=$str" >> /tmp/parameters/$par/$file
			        continue
			    fi
			    echo $str | grep -q ^[[:alnum:]].*=.*$ && continue
			    echo "MNT_OPTS=$str" >> /tmp/parameters/$par/$file
			done
		done
	done
	for sgn in $(getpar $UIRD_SGNFILES); do
		echo "SGN=$(getpar $UIRD_SGNFILES $sgn 1)" >> /tmp/parameters/$UIRD_FROM/$sgn
	done
	if ! getpar $UIRD_ROOTFS >/dev/null; then
	    mkdir -p /tmp/parameters/$UIRD_ROOTFS
	    if getpar $UIRD_ZRAM >/dev/null; then
	        echo zram > /tmp/parameters/$UIRD_ROOTFS/1
	    else
	        echo tmpfs > /tmp/parameters/$UIRD_ROOTFS/1
	    fi
	    echo $(getpar UIRD_RAMSIZE 1 1) >> /tmp/parameters/$UIRD_ROOTFS/1
	fi
}

short_pars_compat() {
	[ "$SECLEVEL" -gt 4 ] && return
	local par
	cat /proc/cmdline | grep -Eq " -|^-" || return
	for par in $(cat /proc/cmdline | sed 's/^.* -//' | cut -d " " -f 1 | fold -w 1); do
	    case $par in
		q)      mkdir -p /tmp/parameters/qs && : >/tmp/parameters/qs/enabled ;;
		Q)      mkdir -p /tmp/parameters/qse && : >/tmp/parameters/qse/enabled ;;
		p)      mkdir -p /tmp/parameters/$UIRD_PREINIT && : >/tmp/parameters/$UIRD_PREINIT/enabled ;;
		S)      mkdir -p /tmp/parameters/$UIRD_SHUTDOWN && : >/tmp/parameters/$UIRD_SHUTDOWN/enabled ;;
		C)      mkdir -p /tmp/parameters/$UIRD_COPY2RAM && : >/tmp/parameters/$UIRD_COPY2RAM/enabled ;;
		F)      mkdir -p /tmp/parameters/$UIRD_FREEMEDIA && : >/tmp/parameters/$UIRD_FREEMEDIA/enabled ;;
		f)      mkdir -p /tmp/parameters/$UIRD_FORCE && : >/tmp/parameters/$UIRD_FORCE/enabled ;;
		z)      mkdir -p /tmp/parameters/$UIRD_ROOTFS && echo zram >/tmp/parameters/$UIRD_ROOTFS/1 ;;
		s)      mkdir -p /tmp/parameters/$UIRD_SWAP && rm -f /tmp/parameters/$UIRD_SWAP/* && echo auto >/tmp/parameters/$UIRD_SWAP/1 ;;
		o)      mkdir -p /tmp/parameters/$UIRD_UNION && echo overlay >/tmp/parameters/$UIRD_UNION/1 ;;
                c)      mkdir -p /tmp/parameters/$UIRD_MODE && echo clean >/tmp/parameters/$UIRD_MODE/1 ;;
                L)      mkdir -p /tmp/parameters/$UIRD_SILENT && : >/tmp/parameters/$UIRD_SILENT/enabled ;;
		esac
	done
}

#$1 - uird.par
#$2 - number of value
#$3 - number of field
# getpar $UIRD_PAR  для флага &&  exitcode 0, stdout "enabled" || exitcode 1
# getpar $UIRD_PAR  для параметра && exitcode 0, stdout: "список подпараметров $UIRD_PAR" || exitcode 1
# getpar $UIRD_PAR N && exitcode 0, stdout: все поля подпараметра N || exitcode 2
# getpar $UIRD_PAR [[:digit:]] && exitcode 0, stdout: все поля всех подпараметров || exitcode 2
# getpar $UIRD_PAR N M  && exitcode 0, stdout: поле М подпараметра N || exitcode 3
# getpar $UIRD_PAR N '2,4' && exitcode 0, stdout: поля с 2 по 4 подпараметра N || exitcode 3
getpar() {
	[ "$1" == "$BREAKSTEP" -a "$DEBUG_IS_ENABLED" != "1" ] && shell_cmd "break"
	tdir=/tmp/parameters
	if [ $3 ]; then
		cat $tdir/$1/$2 2>/dev/null | sed -n "${3}p" && return
		return 3
	elif [ $2 ]; then
		cat $tdir/$1/$2 2>/dev/null && return
		return 2
	else
		if [ -f "$tdir/$1/enabled" ]; then
			echo "enabled" && return
		elif [ -f "$tdir/$1/1" ]; then
			ls "$tdir/$1" && return
		fi
		return 1
	fi
}

# test if the script is started by root user. If not, exit
#
allow_only_root() {
	if [ "0$UID" -ne 0 ]; then
		echolog "Only root can run" "$(basename $0)"
		exit 1
	fi
}

# Create bundle
# call mksquashfs with apropriate arguments
# $1 = directory which will be compressed to squashfs bundle
# $2 = output file
# $3..$9 = optional arguments like -keep-as-directory or -b 123456789
#
create_bundle() {
	debug_log "create_module" "$*"
	rm -f "$2" # overwrite, never append to existing file
	mksquashfs "$1" "$2" -comp xz -b 512K $3 $4 $5 $6 $7 $8 $9 >/dev/null
}

# Move entire initramfs tree to tmpfs mount.
# It's a bit tricky but is necessray to enable pivot_root
# even for initramfs boot image
#
transfer_initramfs() {
	if [ ! -r /lib/initramfs_escaped ]; then
		echo "switch root from initramfs to ramfs"
		SWITCH=/m # one letter directory
		mkdir -p $SWITCH
		mount -t tmpfs -o size="100%" tmpfs $SWITCH
		cp -a /??* $SWITCH 2>/dev/null # only copy two-and-more-letter directories
		cd $SWITCH
		echo "This file indicates that we successfully escaped initramfs" >$SWITCH/lib/initramfs_escaped
		exec switch_root -c /dev/console . $0
	fi
}

# mount virtual filesystems like proc etc
#
init_proc_sysfs() {
	debug_log "init_proc_sysfs" "$*"
	mkdir -p /proc /sys /etc $MEMORY
	mount -n -t proc proc /proc
	echo "0" >/proc/sys/kernel/printk
	mount -n -t sysfs sysfs /sys
	mount -n -o remount,rw rootfs /
	ln -sf /proc/mounts /etc/mtab
}

# make sure some devices are there
init_devs() {
	debug_log "init_devs" "$*"
	#echo /sbin/mdev > /proc/sys/kernel/hotplug
	mdev -s
	modprobe loop 2>/dev/null
	modprobe squashfs 2>/dev/null
	modprobe fuse 2>/dev/null
}

# Activate zram (auto-compression of RAM)
init_zram_swap() {
	local ALG='none' SIZE='0'
	if [ "$1" != "yes" ]; then
		for str in $(getpar $UIRD_SWAP $1 '2,$p'); do
			local | grep -q "$(echo $str | cut -f1 -d=)=" && eval $str
		done
	fi
	[ $SIZE == 0 ] && SIZE=70
	[ $ALG != 'none' ] && modprobe -q $ALG 2>/dev/null
	memtotal=$(grep MemTotal /proc/meminfo | awk ' { print $2 } ')
	memzram=$(($memtotal * ${SIZE} / 100 * 1024))
	modprobe -q zram num_devices=2 2>/dev/null
	[ $ALG != 'none' ] && echo $ALG >/sys/block/zram0/comp_algorithm 2>/dev/null
	ALG=$(cat /sys/block/zram0/comp_algorithm | sed -e 's/^.*\[//' -e 's/\].*$//')
	echo $memzram >/sys/block/zram0/disksize
	mkswap /dev/zram0 >/dev/null
	swapon -p 100 /dev/zram0
	[ $? == 0 ] && echo_green_star && echolog "$INITIALIZE zram swap. Alg: $ALG, size: ${SIZE}%"
}

init_zswap() {
	#echo lz4 >/sys/module/zswap/parameters/compressor
	echo 1 >/sys/module/zswap/parameters/enabled
	echo_green_star && echolog "$INITIALIZE Zswap"
}

# Mount squashfs filesystem bundles to aufs/ovelray union fs
# LBASE = directory where to search for bundles
# LBANDLES = directory where to mount bundles
# LUNION = directory where union is mounted
# LCP2RAM = directory where copy2ram
# LCACHE = directory where layer-cache
# LCHANGES = changes directory (ramfs or persistent changes)
init_union() {
	debug_log "init_union" "$*"
	local BUN MOD RW RO CP FS OPTIONS PRESERVE MID_BUN BUNDLE
	local LBASE='' LBUNDLES='' LUNION='' LCP2RAM='' LCACHE='' LCHANGES='' LOWER_DIRS=''
	for par in $@; do
		local | grep -q "$(echo $par | cut -f1 -d=)" && eval $par
	done
	RW=$(echo $(getpar $UIRD_RW [[:digit:]]) | sed -r 's/\?/./g' | sed -r 's/\*/.\*/g' | sed -r 's/ /|/g')
	RO=$(echo $(getpar $UIRD_RO [[:digit:]]) | sed -r 's/\?/./g' | sed -r 's/\*/.\*/g' | sed -r 's/ /|/g')
	CP=$(echo $(getpar $UIRD_CP [[:digit:]]) | sed -r 's/\?/./g' | sed -r 's/\*/.\*/g' | sed -r 's/ /|/g')
	[ "$SECLEVEL" -lt 2 ] && RUN=$(echo $(getpar $UIRD_RUN [[:digit:]]) | sed -r 's/\?/./g' | sed -r 's/\*/.\*/g' | sed -r 's/ /|/g')
	if [ "$UNION_FS" = "overlay" ]; then
		mkdir -p "$OVERLAY/workdir" "$OVERLAY/changes"
		CPDEST="$OVERLAY/changes"
	elif [ "$UNION_FS" = "aufs" ]; then
		CPDEST="$LCHANGES"
	fi

	echo_green_star
	echolog "${PREPARING_BUNDLES}: $UNION_FS" $brown$LUNION$default

	add_bundle() {
		local BUNDLE MODE BUN MID_BUN
		BUNDLE="$1"
		BUN="$(basename "$BUNDLE")"
		mkdir -p "$LBUNDLES/$BUN"
		if ismountpoint "$LBUNDLES/$BUN"; then
			echolog "  $blue-->" $purple"$BUNDLE"$red" - has alredy been procesed! "$default
			return
		fi
		if [ "$2" ]; then
			MODE="$2"
		else
			MID_BUN=${BUNDLE#*$LBASE}
			[ -e "$LCACHE/$MID_BUN" -a "$(getpar $UIRD_COPY2CACHE 1 1)$(getpar $UIRD_COPY2CACHE 1 1)" ] && BUNDLE="$LCACHE/$MID_BUN"
			[ -e "$LCP2RAM/$MID_BUN" ] && BUNDLE="$LCP2RAM/$MID_BUN"
		fi

		FS="$(device_bestfs "$BUNDLE")"
		OPTIONS="$(fs_options $FS mount)"

		[ "$OPTIONS" = "bind" -a -f "$BUNDLE" ] && continue

		if [ "$CP" -a "$(echo $BUNDLE | grep -E -i "$CP")" -o "$MODE" == "copy" ]; then
			echolog "  $blue-->" $purple"$BUNDLE"$green" [CP mode] "$default
			mount -o $OPTIONS $FS "$BUNDLE" "$LBUNDLES/$BUN"
			cp -a "$LBUNDLES/$BUN"/. "${CPDEST}/" 2>/dev/null
			umount "$LBUNDLES/$BUN" && rmdir "$LBUNDLES/$BUN" # it need to freemedia
			return
		elif [ "$RUN" -a "$(echo $BUNDLE | grep -E -i "$RUN")" ]; then
			echolog "  $blue-->" $purple"$BUNDLE"$yellow" [RUN mode] "$default
			[ -x $BUNDLE ] && $BUNDLE
			return
		elif [ "$RW" -a "$(echo $BUNDLE | grep -E -i "$RW")" ]; then
			MOD=rw+wh
		else
			MOD=ro+wh
		fi
		echolog "  $blue-->" $purple"$BUNDLE"$default
		mount -o $OPTIONS $FS "$BUNDLE" "$LBUNDLES/$BUN"
		if [ "$UNION_FS" = "overlay" ]; then
			LOWER_DIRS="$LBUNDLES/$BUN:$LOWER_DIRS"
		elif [ "$UNION_FS" = "aufs" ]; then
			LOWER_DIRS="$LBUNDLES/$BUN=$MOD:$LOWER_DIRS"
		fi
		LOWER_DIRS=$(echo $LOWER_DIRS | sed 's/\:[[:space:]]*$//')
	}

	for BUNDLE in $(list_modules "$LBASE"); do
		add_bundle $BUNDLE
	done
	if [ -f /tmp/toxzm_modules ]; then
		for BUNDLE_MODE in $(cat /tmp/toxzm_modules); do
			add_bundle $(echo "$BUNDLE_MODE" | cut -f1 -d '#') $(echo "$BUNDLE_MODE" | cut -f2 -d '#')
		done
	fi
	echo_green_star
	echolog "${INIT_UNION}: $UNION_FS"
	log "lowerdir - $LOWER_DIRS"
	if [ "$UNION_FS" = "overlay" ]; then
		log "mount -t overlay -o redirect_dir=on,metacopy=off,index=on,lowerdir=${LOWER_DIRS},upperdir=${OVERLAY}/changes,workdir=${OVERLAY}/workdir overlay $LUNION"
		mount -t overlay -o redirect_dir=on,metacopy=off,index=on,lowerdir=${LOWER_DIRS},upperdir=${OVERLAY}/changes,workdir=${OVERLAY}/workdir overlay $LUNION
		mount --bind ${OVERLAY}/changes $LCHANGES
	elif [ "$UNION_FS" = "aufs" ]; then
		log "mount -t aufs -o nowarn_perm,xino=$MEMORY/.xino_union,trunc_xino,br=${LCHANGES}:${LOWER_DIRS} aufs $LUNION"
		mount -t aufs -o nowarn_perm,xino=$MEMORY/.xino_union,trunc_xino,br=${LCHANGES}:${LOWER_DIRS} aufs $LUNION
	fi
}

# Make sure the part of a script after 'mutex_lock' call is atomic,
# that means the 'locked' part of the script can never be execuetd
# from several processes at the same time, in parallel.
# Every script waits until it gathers the lock.
# The lock directory is saved in /dev instead of /tmp, because /tmp may be
# readonly at the time when the lock is needed (eg. when udev is starting)
# $1 = name of the lock
#
mutex_lock() {
	debug_log "mutex_lock" "$*"
	while ! mkdir "/dev/ll-mutex-lock-$1" 2>/dev/null; do
		usleep 100000
	done
}

# Unlock the lock so another waiting process can reusse it and continue
# $1 = name of the lock
#
mutex_unlock() {
	debug_log "mutex_unlock" "$*"
	rmdir "/dev/ll-mutex-lock-$1" 2>/dev/null
}

# modprobe module $1, including all dependencies, suppress all messages
# This was own function, because modprobe in busybox didn't support
# neither gzipped modules nor dependencies. Seems to be fixed now, though.
# $1 = module name, eg. ehci-hcd
# $* = optional arguments
#
modprobe_module() {
	debug_log "modprobe_module" "$*"
	local MODULE

	MODULE="$1"
	shift

	if [ ! "$MODULE" ]; then return 1; fi
	modprobe "$MODULE" $* 2>/dev/null
}

# mknod next loop device
# - find biggest loop device in /dev/loop/, assume it to be used
# - preallocate (mknod) 20 more loop devices in one round
mknod_next_loop_dev() {
	debug_log "mknod_next_loop_dev" "$*"
	local i NR END PFX

	mutex_lock mknod_next_loop_dev

	if [ -d /dev/loop ]; then
		NR=$(find /dev/loop/ -maxdepth 1 | sed -r 's/[^0-9]+//' | sort -n | tail -n 1)
		PFX="/"
	else
		NR=$(find /dev/ -maxdepth 1 | grep loop | sed -r 's/[^0-9]+//' | sort -n | tail -n 1)
		PFX=""
	fi
	NR=$(expr 0$NR + 1)
	END=$(expr 0$NR + 20)
	for i in $(seq $NR $END); do
		mknod /dev/loop$PFX$i b 7 $i 2>/dev/null
	done
	echo /dev/loop$PFX$NR

	mutex_unlock mknod_next_loop_dev
}

# List all CD-ROMs
# by using /proc entries
#
list_cdrom_devices() {
	debug_log "list_cdrom_devices" "$*"
	local CDDEVICE

	for CDDEVICE in $(cat /proc/sys/dev/cdrom/info 2>/dev/null | head -n 3 | tail -n 1 | cut -d ":" -f 2); do
		echo "/dev/$CDDEVICE"
	done
}

# List all mounted directories
#
list_mounted_directories() {
	debug_log "list_mounted_directories" "$*"
	find $SYSMNT -maxdepth 3 -mindepth 2 -type d | while read DIR; do
		ismountpoint $DIR && echo $DIR
	done | tac
}

# List all devices with filesystems
# Return empty result when nohd parameter was given.
#
list_partition_devices() {
	debug_log "list_partition_devices" "$*"
	if [ "$(getpar nohd)" == "enabled" ]; then return 1; fi
	MOUNTED=$(cat /proc/mounts | grep -E '/dev/(sd|nbd).*[[:digit:]]' | cut -d " " -f 1 | sort -u)
	#not mounted
	for DEV in $MOUNTED $(grep -Ev 'ram|loop|major|sr|^$| [0-9] [a-z]' /proc/partitions | grep [0-9] | sed -r "s:^[0-9 ]+:/dev/:"); do
		$BIN_BLKID -s TYPE "$DEV" | grep -q "crypto_LUKS" || echo $DEV
	done | sort | uniq -u
	if [ -e /dev/mapper/control ]; then # list LVM partitions if available
		ls -1 /dev/mapper/ | grep -v "^control\$" | sed -r "s:^:/dev/mapper/:"
	fi
	#mounted
	for DEV in $MOUNTED; do echo $DEV; done
}
# THIS FUNCTION IS NEVER USED
# List all disk devices
list_disk_devices() {
	debug_log "list_disk_devices" "$*"
	list_partition_devices | grep -v [0-9]
}

# List all partitions marked as Linux Swap
#
list_swap_devices() {
	debug_log "list_swap_devices" "$*"
	if [ "$(getpar nohd)" == "enabled" -o "$(getpar noswap)" == "enabled" ]; then return 1; fi
	$BIN_BLKID -t TYPE="swap" -o device
}

# List all block devices
#
list_block_devices() {
	debug_log "list_block_devices" "$*"
	list_partition_devices
	getpar nocd || list_cdrom_devices
}

#using /uird.scan script to configure UIRD
uird_scan() {
	if [ "$(getpar $UIRD_SCAN)" == "enabled" ]; then
		/uird.scan
		shell_cmd help
	else
		if [ "$(getpar $UIRD_SCAN 1 1)" == "legacy" ]; then
			/uird.scan --legacy $(getpar $UIRD_SCAN 1 '2,$') || shell_cmd "help"
		elif [ "$(getpar $UIRD_SCAN 1 1)" == "modules" ]; then
			/uird.scan --modules || shell_cmd "help"
		else
			echolog "$(getpar $UIRD_SCAN 1 1)"
			return
		fi
	fi
}

# discover filesystem used on the given device
# Use vfat for msdos filesystem. Use ntfs-3g for ntfs if ntfsmount exists.
# $1 = device, eg. /dev/hda1
#
device_filesystem() {
	debug_log "device_filesystem" "$*"
	local NTFS

	if [ -e /bin/ntfsmount ]; then NTFS="ntfs-3g"; else NTFS="ntfs"; fi
	$BIN_BLKID -s TYPE "$1" -o value | sed "s/msdos/vfat/" | sed "s/ntfs/$NTFS/"
}

# tell us if the given filesystem is supported
# (eg. it's in /proc/filesystems or we know it)
# $1 = filesystem name
#
is_supported_filesystem() {
	debug_log "is_supported_filesystem" "$*"

	if [ -e /bin/ntfsmount -a "$1" = "ntfs-3g" ]; then
		return 0
	fi

	# the following command will set the return value
	grep -Eq "[[:space:]]$1\$" /proc/filesystems
}

# Check device on demand. Only block devices and *.img loop files  can be checked
# $1 = /dev device, eg. /dev/hda1, or loop file
# $2 = optional filesystem name, in order to skip autodetection
fsck_device() {
	local FS
	debug_log "fsck_device" "$*"
	echo $FSCHECKED | grep -q "$1" && return
	[ -b "$1" -o -f "$1" ] || return
	if [ -f "$1" ]; then
		echo $1 | grep -q ".img$" || return
	fi
	echo_green_star
	echolog "$FSCK_DEVICE" $green"$1 $2"$default >/dev/console 2>/dev/console
	FS=
	if [ "$2" = "ntfs" ]; then
		$BIN_NTFSFIX "$1" </dev/console >/dev/console 2>/dev/console
	elif [ "$2" = "btrfs" ]; then
		$BIN_BTRFSCK "$1" </dev/console >/dev/console 2>/dev/console
	else
		$BIN_FSCK -a $([ "$2" ] && echo "-t $2") $1 </dev/console >/dev/console 2>/dev/console
	fi
	echo_green_star
	echolog "FS $1 was checked,  exitcode  - $?"
	FSCHECKED="$FSCHECKED $1"
}

# unmount all parameters. If the parameter is not mountpoint but
# it's a file or directory, umount the device where the file/dir is stored.
#
# First try normal umount, if that fails then remount read-only
# If -l parameter is specified, do lazy-umount when normal umount fails
# $1..$n = files/directories/devices to be unmounted
#
fumount() {
	debug_log "fumount" "$*"
	local TARGET LAZY LOOPDEVICE

	while [ "$1" ]; do
		if [ "$1" = "-l" ]; then
			LAZY="yes"
			shift
		fi
		TARGET=$(readlink -f "$1")
		if ! ismountpoint "$TARGET"; then
			if [ -f "$TARGET" -o -d "$TARGET" ]; then
				TARGET=$(df "$TARGET" | tail -n 1 | tr -s " " | cut -d " " -f 6)
			fi
		fi

		if [ "$TARGET" != "" ]; then
			LOOPDEVICE=$(grep '/dev/loop.* '"$TARGET " /proc/mounts | awk '{print $1}')
			umount -n "$TARGET" >/dev/null 2>&1
			if [ $? -ne 0 ]; then
				mount -n -o remount,ro -t ignored ignored "$TARGET" >/dev/null 2>&1
				if [ "$LAZY" ]; then umount -n -l "$TARGET" >/dev/null 2>&1; fi
			fi
			[ "$LOOPDEVICE" = "" ] || losetup -d "$LOOPDEVICE"
		fi
		shift
	done
}

# Mount device $1 to $2
# If the device is using vfat or ntfs filesystem, use iocharset as a mount option
# $1 = /dev device to mount, eg. /dev/hda1, or loop file, or directory
# $2 = mountpoint, eg. /mnt/hda1
# $3 = optional mount options, for example "ro", or "remount,rw"
# $4 = optional filesystem name, in order to skip autodetection
# $5 = file with extended parameters
mount_device() {
	debug_log "mount_device" "$*"
	local FS DEV LOOPDEV OPTIONS FILESYSTEM ERR OPTIONS LUKS_DEV KEY="" FSCK="no" PASS=""
	# make sure we have enough arguments
	if [ "$2" = "" ]; then return 1; fi
	if [ "$1" = "" ]; then
		rmdir "$2" 2>/dev/null
		return 1
	fi
	getpar fsck >/dev/null && FSCK="yes"
	FPARS=$5
	if [ "$FPARS" ]; then
		for str in $(cat $FPARS | sed -n '2,$p'); do
			local | grep -q "$(echo $str | cut -f1 -d=)" && eval $str
		done
	fi
	# skipping MBR
	echo $(basename $1) | grep -q [a-z]$ && grep -q $(basename $1)[0-9] /proc/partitions && return 1
	mkdir -p "$2"
	DEV="$1"
	if [ "$4" != "" ]; then FS="$4"; else FS=$(device_filesystem "$1"); fi
	if [ "$FS" ]; then
		OPTIONS=$(fs_options $FS mount)
		FS="-t $FS"
	fi
	if [ "$OPTIONS" ]; then OPTIONS="$OPTIONS"; else OPTIONS=""; fi
	if [ -f "$DEV" ]; then OPTIONS="$OPTIONS,loop"; fi
	if [ -d "$DEV" ]; then OPTIONS="$OPTIONS,rbind"; fi
	if [ "$3" ]; then OPTIONS="$OPTIONS,$(echo $3 | tr -s "+" ",")"; fi
	OPTIONS=$(echo "$OPTIONS" | sed -r "s/^,+//")
	if [ "$FS" = "-t ntfs-3g" ]; then
		[ $FSCK == "yes" ] && fsck_device "$DEV" ntfs
		ntfsmount "$DEV" "$2" -o $OPTIONS >>$LOGFILE 2>&1
		ERR=$?
	else
		if [ $FSCK == "yes" ]; then
			FS_T=$(echo $FS | sed "s/-t //" | tr -d " ")
			if [ "$FS_T" == "ext2" -o "$FS_T" == "ext3" -o "$FS_T" == "ext4" -o "$FS_T" == "btrfs" -o "$FS_T" == "vfat" -o "$FS_T" == "exfat" -o "$FS_T" == "xfs" ]; then
				fsck_device "$DEV" $FS_T
			fi
		fi
		log "mount -n -o $OPTIONS $FS "$DEV" "$2" "
		mount -n -o $OPTIONS $FS "$DEV" "$2" >>$LOGFILE 2>&1
		ERR=$?
	fi
	if [ -f ${2}/EXPAND_ME ]; then
		umount $2
		expand_part $DEV
		mount -n -o $OPTIONS $FS "$DEV" "$2" #>>$LOGFILE 2>&1
		ERR=$?
	fi
        #LOOPAES####################################################
	if [ $ERR -ne 0 ] && [ -f "$DEV" ] && echo "$DEV" | grep -q .enc$; then
		echolog "$MOUNT_DEVICE_ENC" $green"$DEV"$default
		OPTIONS=$(echo "$OPTIONS" | sed -r "s/,loop//g")
		for a in $(seq 0 254); do
			[ -f /dev/mapper/uirdencdev$a -o -b /dev/mapper/uirdencdev$a ] && continue
			LOOPDEV=uirdencdev$a
			AESKEY=/tmp/aeskey$a
			break
		done
		times=3
		if [ -n "$KEY" -a ! -f "$KEY" ]; then
			echo_blue_star
			echolog "find key:  $KEY"
			KEY=$(find_data "$KEY" "$AESKEY")
		fi
		echo_blue_star
		while [ $times -gt 0 ]; do
			if [ -f "$KEY" ]; then
				echolog "Found keyfile:  $KEY "
				cryptsetup open --type loopaes "$DEV" "$LOOPDEV" --key-file "$KEY" >>$LOGFILE 2>&1
			else
				echo "$ENC_PASS" >/dev/console
				PASS=$(ask_pass "$ENC_PASS")
				echo $PASS | cryptsetup open --type loopaes "$DEV" "$LOOPDEV" --key-file -
			fi

			if [ -b "/dev/mapper/$LOOPDEV" ]; then
				echolog "accepted!"
				getpar fsck && fsck_device "/dev/mapper/$LOOPDEV"
				mount_device "/dev/mapper/$LOOPDEV" "$2" "$3" "$4" "$5" >>$LOGFILE 2>&1
				ERR=$?
				[ "$?" -eq 0 ] && break
			fi
			echolog "Mounting ecrypted contaner - ERROR, try again"
			cryptsetup close "$LOOPDEV" >>$LOGFILE 2>&1
			unset PASS
			times=$(($times - 1))
		done
		grep -q "/dev/mapper/$LOOPDEV" /proc/mounts && ERR=0
	fi

	#LUKS####################################################
	if [ $ERR -ne 0 ] && [ -b "$DEV" ] && $BIN_BLKID "$DEV" -s TYPE | grep -q crypto_LUKS; then
		LUKS_DEV=$(echo $DEV | sed 's:/dev/::')
		times=3
		while [ $times -gt 0 ]; do
			if ! [ -e "/dev/mapper/$LUKS_DEV" ]; then
				log "Initialization luks partition $LUKS_DEV"
				if [ "$KEY"_ != "_" ]; then
					if ! [ -f $KEY ]; then
						KEY=$(find_data "$KEY" "/tmp/lukskey")
					fi
				elif [ "$PASS"_ != "_" ]; then
					[ "$PASS" == '//hardware//' ] && PASS=$(busybox lspci | md5sum | cut -f1 -d ' ')
				fi
				echolog "$MOUNT_DEVICE_ENC" "LUKS" $green"$DEV"$default
				if [ -f "$KEY" ]; then
					cryptsetup -d $KEY luksOpen "$DEV" "$LUKS_DEV" >>$LOGFILE 2>&1
					log "$(umount /tmp/lukskey 2>&1)"
				else
					if [ "$PASS"_ == "_" ]; then
						echo "$LUKS_PASS" >/dev/console
						PASS=$(ask_pass "$LUKS_PASS")
					fi
					echo "$PASS" | cryptsetup luksOpen "$DEV" "$LUKS_DEV" >>$LOGFILE 2>&1
				fi
			fi
			if [ -b "/dev/mapper/$LUKS_DEV" ]; then
				echolog accepted!
				unset PASS KEY
				getpar fsck && fsck_device "/dev/mapper/$LUKS_DEV"
				mount_device "/dev/mapper/$LUKS_DEV" "$2" "$3" "$4" "$5" >>$LOGFILE 2>&1
				[ "$?" -eq 0 ] && break
			fi
			echolog "Mount - error!, try again"
			unset PASS
			umount $2 2>/dev/null
			cryptsetup luksClose "$LUKS_DEV" >>$LOGFILE 2>&1
			times=$(($times - 1))

		done
		grep -q "/dev/mapper/$LUKS_DEV" /proc/mounts && ERR=0
	fi
	#########################################################

	# not enough loop devices? try to create one.
	if [ $ERR -eq 2 ]; then
		LOOPDEV=$(mknod_next_loop_dev)
		OPTIONS=$(echo "$OPTIONS" | sed -r "s/,loop//g")
		losetup "$LOOPDEV" "$DEV" 2>/dev/null # busybox's losetup doesn't support -r
		if [ $? -ne 0 ]; then
			losetup -r "$LOOPDEV" "$DEV" 2>/dev/null # force read-only in case of error
		fi
		mount -n -o $OPTIONS $FS "$LOOPDEV" "$2" >/dev/null 2>&1
		ERR=$?
	fi

	# if nothing works, try to force read-only mount
	if [ $ERR -ne 0 ]; then
		mount -n -r -o $OPTIONS $FS "$DEV" "$2" >/dev/null 2>&1
		ERR=$?
	fi

	if [ $ERR -ne 0 ]; then rmdir $2 2>/dev/null; fi
	return $ERR
}

# Mount http filesystem from the given server
# $1 = magnet link
# $2 = mountdir
#
mount_btfs() {
	debug_log "mount_btfs" "$*"
	mkdir -p $2
	$BIN_BTFS "$1" "$2" 1>&2 || return
	if [ -f $2/$(basename $1) ]; then
		echo $2/$(basename $1)
	else
		echo $2
	fi
}

# Mount http filesystem from the given server
# $1 = server
# $2 = mountdir
#
mount_httpfs() {
	debug_log "mount_httpfs" "$*"
	mkdir -p $2 1>&2
	$BIN_HTTPFS $1 $2 1>&2 || return
	if [ -f $2/$(basename $1) ]; then
		echo $2/$(basename $1)
	else
		echo $2
	fi
}

# Mount curlftpfs filesystem from the given server
# $1 = server
# $2 = mountdir
#
mount_curlftpfs() {
	local OPTIONS
	debug_log "mount_curlftpfs" "$*"
	OPTIONS=
	getpar $UIRD_NETFSOPT >/dev/null && OPTIONS="-o $(getpar $UIRD_NETFSOPT 1 1)"

	mkdir -p $2
	$BIN_CURLFTPFS $OPTIONS $1 $2 </dev/console >/dev/console 2>/dev/console || return
	if [ -f $2/$(basename $1) ]; then
		echo $2/$(basename $1)
	else
		echo $2
	fi
}

# Mount sshfs filesystem from the given server
# $1 = server
# $2 = mountdir
#
mount_sshfs() {
	local OPTIONS ERR
	debug_log "mount_sshfs" "$*"
	OPTIONS=
	getpar $UIRD_NETFSOPT >/dev/null && OPTIONS="-o $(getpar $UIRD_NETFSOPT 1 1)"
	mkdir -p $2
	times=3
	while [ $times -gt 0 ]; do
		$BIN_SSHFS ${1/ssh:??/} $2 $OPTIONS </dev/console >/dev/console 2>/dev/console
		ERR=$?
		[ $ERR -eq 0 ] && break
		# is not tested, just guess ############
		$BIN_SSHFS $(dirname ${1/ssh:??/}) $2 $OPTIONS </dev/console >/dev/console 2>/dev/console
		ERR=$?
		[ $ERR -eq 0 ] && break
		########################################
		times=$(expr $times - 1)
	done
	[ $ERR -eq 0 ] || return
	if [ -f $2/$(basename $1) ]; then
		echo $2/$(basename $1)
	else
		echo $2
	fi
}

# Mount via 9p
# $1 - 9p mount tag
# $2 - mountdir
mount_9p() {
	local TAG ERR OPTIONS
	TAG=$(echo $1 | sed 's#^9p://##')
	OPTIONS="trans=virtio,msize=100000000"
	[ $3 ] && OPTIONS=$3
	debug_log "mount_9p" "$*"
	times=2
	mkdir -p $2
	while [ $times -gt 0 ]; do
		echo "mount -t 9p -o $OPTIONS $TAG $2" 1>&2
		mount -t 9p -o $OPTIONS $TAG $2
		ERR=$?
		[ $ERR -eq 0 ] && break
		times=$(expr $times - 1)
	done
	[ $ERR -eq 0 ] || return
	echo $2
}

# Mount nfs filesystem from the given server
# $1 = server
# $2 = mountdir
#
mount_nfs() {
	local OPTIONS
	debug_log "mount_nfs" "$*"
	OPTIONS="nolock,rsize=4096,wsize=4096"
	getpar $UIRD_NETFSOPT >/dev/null && OPTIONS="$OPTIONS,$(getpar $UIRD_NETFSOPT 1 1)"
	mkdir -p $2
	modprobe nfs
	local SHARE=$(echo $1 | sed s-^nfs://--)
	if mount -t nfs $SHARE $2 -o $OPTIONS 2>/dev/null; then
		echo $2
	elif mount -t nfs $(dirname $SHARE) $2 -o $OPTIONS 2>/dev/null; then
		echo $2/$(basename $SHARE)
	fi
}
# Mount cifs filesystem from the given server
# $1 = server
# $2 = mountdir
#
mount_cifs() {
	local OPTIONS SHARE
	debug_log "mount_cifs" "$*"
	OPTIONS=""
	[ $3 ] && OPTIONS=$3
	getpar $UIRD_NETFSOPT >/dev/null && OPTIONS="$(getpar $UIRD_NETFSOPT 1 1)"
	mkdir -p $2
	modprobe cifs 1>&2
	SHARE=$(echo $1 | sed s-^cifs://--)
	if mount -t cifs $SHARE $2 -o $OPTIONS 2>/dev/null 1>&2; then
		echo $2
	elif mount -t cifs $(dirname $SHARE) $2 -o $OPTIONS 2>/dev/null 1>&2; then
		echo $2/$(basename $SHARE)
	fi
}
# Mount rsync filesystem from the given server
# $1 = server
# $2 = mountdir
#
mount_rsync() {
	debug_log "mount_rsync" "$*"
	OPTIONS="--progress -a"
	[ $3 ] && OPTIONS="$3"
	getpar $UIRD_NETFSOPT >/dev/null && OPTIONS="$(getpar $UIRD_NETFSOPT)"
	mkdir -p $2
	$BIN_RSYNC $OPTIONS $1/* $2/ 1>&2 && echo $2
}

# Format mountdir for device. This function used to append _cdrom or _removable
# suffix to the directory name so KDE was able to assign a nice icon for evey
# device, but this should be done using HAL in KDE nowadays, so we do not
# support these stupid suffixes anymore. Many people will be happy :)
# $1 = device full path, eg. /dev/hda1
#
device_mountdir() {
	debug_log "device_mountdir" "$*"
	if ! [ -b "$1" ]; then
		echo "$1" | tr -s /
	else
		if grep "^$1 " /proc/mounts | grep -qv subvol; then
			grep "^$1 " /proc/mounts | awk '{print $2}' | head -1 | tr -s /
		elif grep -q "^${1}.*,subvol=/ " /proc/mounts; then
			grep "^${1}.*,subvol=/ " /proc/mounts | head -1 | awk '{print $2}' | tr -s /
		else
			if [ "$2" = "" ]; then
				echo "/$MOUNTDIR/$(basename "$1")" | tr -s /
			else
				echo "$2" | tr -s /
			fi
		fi
	fi
}

# ismountpoint exits with 0 if $1 is mountpoint, else exits with 1
# $1 = directory or loop_file
#
ismountpoint() {
	debug_log "ismountpoint" "$*"
	local MDIR

	MDIR=$(readlink -f "$1")
	cat /proc/mounts | cut -d " " -f 2 | grep -E "^$MDIR\$" >/dev/null 2>&1
}

# Find file-path on given device
# First it mounts the device read-only. If then the 'path' is found,
# then remount without RO flag (causes it to be mounted read-write if possible)
# and return the path, else unmount and exit.
# If the device/dev_directory is already mounted, preserve it mounted
# $1 = device
# $2 = path/filename
# $3 = device mountpoint
# $4 = extended pars from file
find_filepath() {
	debug_log "find_filepath" "$*"
	local DIR FOUND PRESERVE SGN="" MNTOPTS=""
	FPARS=$4
	if [ "$FPARS" ]; then
		for str in $(cat $FPARS | sed -n '2,$p'); do
			local | grep -q "$(echo $str | cut -f1 -d=)=" && eval $str
		done
	fi
	MNT_OPTS="$(echo $MNT_OPTS | sed 's/+/,/')"
	DIR=$(device_mountdir $1 $3)

	ismountpoint $DIR
	if [ $? -eq 0 ]; then
		PRESERVE="true"
	else
		log "mount_device $1 $DIR ro "" $FPARS"
		mount_device "$1" "$DIR" "ro" "" "$FPARS"
		if [ $? -ne 0 ]; then
			rmdir $DIR 2>/dev/null
			return 1
		fi
		PRESERVE=""
	fi

	FOUND=$(ls -A1d $DIR/$2 2>/dev/null | head -n 1 | tr -s '/')
	if [ "$SGN"_ != "_" ]; then
		if [ -f "$DIR/$2/$SGN" ]; then
			FOUND=$FOUND
		else
			[ "$SGN" ] && FOUND=""
		fi
	fi
	if [ "$FOUND" = "" ]; then
		if [ "$PRESERVE" != "true" ]; then
			fumount $DIR
			rmdir $DIR 2>/dev/null
		fi
		return 1
	else
		# remount without the 'ro' option now, so use rw or defaults
		# Only in the case it was not mounted already before.
		if [ "$PRESERVE" != "true" ]; then
			fumount $DIR
			log "$1" "$DIR" "rw,$MNT_OPTS" "" "$FPARS"
			mount_device "$1" "$DIR" "rw,$MNT_OPTS" "" "$FPARS"
			if [ $? -ne 0 ]; then
				rmdir $DIR 2>/dev/null
				return 2
			fi
		fi
		log "RETURNFOUND=$FOUND"
		echo "$FOUND"
		return 0
	fi
}

#convert UUID@/path and LABEL@/path to /dev/sd??/path
# $1 = LABEL@/path/to/file
uuid_label_to_dev() {
	local DEV DEVPATH TIMEOUT=""
	if ! echo $1 | grep -q ^.*@[\ ,/]; then
		echo $1
		return
	fi
	DEV=$($BIN_BLKID | grep -m1 $(echo $1 | sed 's:@.*$::') 2>/dev/null | awk -F: '{print $1}')
	if [ -z $DEV ]; then
		[ "$TIMEOUT" ] || TIMEOUT=$(getpar scantimeout 1 1 | sed -r 's/[^0-9]*([0-9]+).*/\1/')
		[ "$TIMEOUT" = "" ] && TIMEOUT=10
		while [ $TIMEOUT -gt 0 ]; do
			echo -ne "." >&2
			sleep 1
			TIMEOUT=$((TIMEOUT - 1))
			DEV=$($BIN_BLKID | grep -m1 $(echo $1 | sed 's:@.*$::') 2>/dev/null | awk -F: '{print $1}')
			[ -z $DEV ] || break
		done
	fi
	if [ -z $DEV ]; then
		DEVPATH=$1
	else
		DEVPATH=$(echo $1 | sed "s:^.*@/\|^.*@$:${DEV}/:")
	fi
	echo $DEVPATH | tail -n1
}

# Find file in computer by mounting disks or other storage devices
# and searching for $1 in the mounted directory
# $1 = filename or device-path or devicepath/filename
# $2 = device mountpoint
# $3 = extended pars from file

find_file() {
	debug_log "find_file" "$*"
	local FIND DEVICE DEVPART PATHPART
	# allow using /mnt/... as well as /dev/...
	FIND=$(echo "$1" | sed -r "s:^/mnt/:/dev/:")

	# if parameter is just a device, echo it and exit
	#if [ -b "$FIND" -o -c "$FIND" -o "$FIND" = "" ]; then echo "$FIND"; return; fi
	if [ -b "$FIND" -o "$FIND" = "" ]; then
		echo "$FIND"
		return
	fi
	# If path doesn't start with /dev/, try to find the exact path on all devices
	# First, split DEV/PATH parts
	DEVPART=$(echo "$FIND" | grep -E -o "^/dev/[^/]+")

	if [ "$DEVPART" = "" ]; then
		# no device is specified. Search all devices for filename $FIND
		PATHPART="$FIND"
		for DEVICE in $(list_mounted_directories) $(list_block_devices); do
			if ! grep -q ":$DEVICE@$PATHPART:" /tmp/_findfile 2>/dev/null; then
				log "find_filepath "$DEVICE" "$PATHPART" "$2" "$3""
				find_filepath "$DEVICE" "$PATHPART" "$2" "$3"
				if [ $? -eq 0 ]; then return 0; fi
				echo ":$DEVICE@$PATHPART:" >>/tmp/_findfile
			fi
		done
	else
		# try to find PATHPART only on the given device
		PATHPART=$(echo "$FIND" | sed -r 's:^/dev/[^/]+(.*):\1:') #'
		[ $PATHPART ] || PATHPART="/"
		log "find_filepath "$DEVPART" "$PATHPART" "$2" "$3" "
		find_filepath "$DEVPART" "$PATHPART" "$2" "$3"
	fi
}

# Find Data
# use 'find_file' function to find the given file/dir
# if nothing found, sleep for a while to allow devices to settle and try again.
# (is there any way to find out if there are devices queued through /sys?)
# $1 = file or directory to find
# $2 = device mountpoint
# $3 = extended pars in file
find_data() {
	debug_log "find_data" "$*"
	local RESULT FPARS TIMEOUT='' NET_MOUNT
	FPARS=$3
	if [ "$FPARS" ]; then
		for str in $(cat $FPARS | sed -n '2,$p'); do
			local | grep -q "$(echo $str | cut -f1 -d=)=" && eval $str
		done
	fi
	[ "$TIMEOUT" ] || TIMEOUT=$(getpar scantimeout 1 1 | sed -r 's/[^0-9]*([0-9]+).*/\1/')
	if [ "$TIMEOUT" = "" ]; then TIMEOUT=5; fi
	log "find_file "$1" "$2" "$3" "

	while [ $TIMEOUT -gt 0 -a "$RESULT" = "" ]; do
		log "find_file "$1" "$2" "$3" "
		if echo "$1" | grep -q "9p://"; then
			RESULT=$(mount_9p $1 $2 $MNT_OPTS)
		elif echo "$1" | grep -q "://"; then
			init_ifcfg
			echo $1 | grep -iq ^"http://" && RESULT=$(mount_httpfs $1 $2 $MNT_OPTS)
			echo $1 | grep -iq ^"nfs://" && RESULT=$(mount_nfs $1 $2 $MNT_OPTS)
			echo $1 | grep -iq ^"cifs://" && RESULT=$(mount_cifs $1 $2 $MNT_OPTS)
			echo $1 | grep -iq ^"ssh://" && RESULT=$(mount_sshfs $1 $2 $MNT_OPTS)
			echo $1 | grep -iq ^"ftp://" && RESULT=$(mount_curlftpfs $1 $2 $MNT_OPTS)
			echo $1 | grep -iq ^"rsync://" && RESULT=$(mount_rsync $1 $2 $MNT_OPTS)
		else
			RESULT=$(find_file "$1" "$2" "$3")
		fi
		if [ -z "$RESULT" ]; then
			log "find_data:(${TIMEOUT}): $RESULT"
			TIMEOUT=$((TIMEOUT - 1))
			sleep 1
			echo -ne "." >&2
		fi
	done
	log "data_from RESULT - $RESULT"
	echo $RESULT
}

# Return device mounted for given directory
# $1 = directory
#
mounted_device() {
	debug_log "mounted_device" "$*"

	local MNT TARGET
	MNT="$1"
	while [ "$MNT" != "/" -a "$MNT" != "." -a "$MNT" != "" ]; do
		TARGET="$(grep -F " $MNT " /proc/mounts | cut -d " " -f 1)"
		if [ "$TARGET" != "" ]; then
			echo "$TARGET"
			return
		fi
		MNT="$(dirname "$MNT")"
	done
}

# Return mounted dir for given directory
# $1 = directory
#
mounted_dir() {
	debug_log "mounted_dir" "$*"

	local MNT
	MNT="$1"
	while [ "$MNT" != "/" -a "$MNT" != "." -a "$MNT" != "" ]; do
		if mountpoint -q "$MNT" 2>/dev/null; then
			echo "$MNT"
			return
		fi
		MNT="$(dirname "$MNT")"
	done
}

# Make sure to mount FAT12/16/32 using vfat
# in order to support long filenames
# $1 = device
#
device_bestfs() {
	debug_log "device_bestfs" "$*"
	local FS

	FS="$($BIN_BLKID "$1" | sed -r "s/.*TYPE=//" | tr -d '"' | tr [A-Z] [a-z])"
	if [ "$FS" = "msdos" -o "$FS" = "fat" -o "$FS" = "vfat" ]; then
		FS="vfat"
	elif [ "$FS" = "ntfs" ]; then
		FS="ntfs-3g"
	fi
	[ -z "$FS" ] || echo "-t $FS"
}

# Find out what iocharset to use
iocharset() {
	debug_log "iocharset" "$*"
	local CHARSET IOCHARSET

	# if iocharset is explicitly set at the boot prompt,
	# return it regardless the locale settings
	IOCHARSET=$(getpar iocharset 1 1)
	if [ "$IOCHARSET" = "" ]; then IOCHARSET=utf8; fi
	echo $IOCHARSET
	return 0
}

# Find out what codepage to use
codepage() {
	debug_log "codepage" "$*"
	local CHARSET CODEPAGE

	# if codepage is explicitly set at the boot prompt,
	# return it regardless the locale settings
	CODEPAGE=$(getpar codepage 1 1)
	if [ "$CODEPAGE" = "" ]; then CODEPAGE=866; fi
	echo $CODEPAGE
	return 0
}

# Get filesystem options
# $1 = filesystem or '-t filesystem'
# $2 = 'fstab' or 'mount' ... 'auto'/'noauto' string is enabled (fstab) or disabled (mount)
#

fs_options() {
	debug_log "fs_options" "$*"

	if [ "$1" = "-t" ]; then
		shift
	fi

	local NOAUTO IOCHARSET CODEPAGE

	NOAUTO="$(getpar noauto 2>/dev/null)"
	if [ "$NOAUTO" = "enabled" ]; then
		NOAUTO="noauto"
	else
		NOAUTO="auto"
	fi
	if [ "$2" = "fstab" ]; then echo -n "$NOAUTO,"; fi
	if [ "$1" = "swap" ]; then
		echo "defaults,pri=1"
		return 0
	fi

	if [ "$1" = "mount" ]; then
		echo -n "bind"
	elif [ "$1" != "btrfs" ]; then
		echo -n "noatime,suid,dev,exec"
	fi

	IOCHARSET=$(iocharset)
	CODEPAGE=$(codepage)

	MUID=$(getpar users 1 1 | awk -F: '{print $2}')
	[ "$MUID" = "" ] && MUID=500

	if [ "$1" = "vfat" ]; then
		echo -n ",quiet,umask=0,check=s,shortname=mixed,uid=$MUID,gid=$MUID"
		if [ "$IOCHARSET" ]; then
			echo ",codepage=$CODEPAGE,iocharset=$IOCHARSET"
		fi
	fi

	if [ "$1" = "iso9660" ]; then
		echo -n ",ro"
		if [ "$IOCHARSET" ]; then
			echo ",iocharset=$IOCHARSET"
		fi
	fi

	if [ "$1" = "ntfs" ]; then
		echo -n ",ro"
		if [ "$IOCHARSET" ]; then
			echo ",nls=$IOCHARSET"
		fi
	fi

	if [ "$1" = "ntfs-3g" ]; then
		echo ",locale=$LOCALE,uid=$MUID,gid=$MUID"
	fi

	if [ "$1" = "squashfs" ]; then
		echo -n ",ro"
	fi

}

# Modprobe network kernel modules until a working driver is found.
# These drivers are (or used to be) probed in Slackware's initrd.
# The function returns the first device found, yet it doesn't have
# to be a working one, eg. if the computer has two network interfaces
# and ethernet cable is plugged only to one of them.
#
init_network_dev() {
	debug_log "init_network_dev" "$*"
	local MODULE ETH

	for MODULE in virtio_net 3c59x acenic de4x5 e1000 e1000e e100 epic100 hp100 \
		ne2k-pci pcnet32 8139too 8139cp tulip via-rhine r8169 atl1e yellowfin \
		tg3 dl2k ns83820 atl1 b44 bnx2 skge sky2 tulip depca 3c501 3c503 \
		3c505 3c507 3c509 3c515 ac3200 at1700 cosa cs89x0 de600 de620 e2100 \
		eepro eexpress eth16i ewrk3 forcedeth hostess_sv11 hp-plus hp ni52 \
		ni65 sb1000 sealevel smc-ultra sis900 smc9194 wd; do
		modprobe $MODULE 2>/dev/null
		ETH="$(cat /proc/net/dev | grep : | grep -v lo: | cut -d : -f 1 | tr -d " " | head -n 1)"
		if [ "$ETH" != "" ]; then
			echo $ETH
			return 0
		fi
		rmmod $MODULE 2>/dev/null
	done

	# If we are here, none of the above specified modules worked.
	# As a last chance, try to modprobe everything.
	find /lib/modules/ -type f -name '*.ko.*' | while read a; do
		echo $(basename $a) | sed 's/\..*$//' | xargs modprobe
	done 2>/dev//null
	cat /proc/net/dev | grep : | grep -v lo: | cut -d : -f 1 | tr -d " " | head -n 1
}

# Setup ip address
# ip=CLIENT:GW:MASK
# or DHCP lease
# Ex.: ip=192.168.0.3:192.168.0.1:255.255.255.0
init_ifcfg() {
	debug_log "init_ifcfg" "$*"
	local CLIENT GW MASK ETH

	echo_blue_star
	echolog "$INIT_IFCFG"

	modprobe af_packet 2>/dev/null

	IP=$(getpar $UIRD_IP 1 1)
	[ "$IP" = "" ] && IP=::

	echo $IP | while IFS=":" read CLIENT GW MASK; do
		ETH=$(init_network_dev)

		# set IP address as given by boot parameter
		if [ "$CLIENT" != "" -a "$MASK" != "" ]; then
			ifconfig $ETH "$CLIENT" netmask "$MASK"
			route add default gw "$GW"
			# well known IP address of Google public DNS service
			echo nameserver 8.8.8.8 >>/etc/resolv.conf
		else
			# if client ip is unknown, try to get a DHCP lease
			ifconfig $ETH up
			udhcpc -i $ETH -f -q >/dev/null
		fi

	done
}

# Download data from tftp
# $1 = target (store downloaded files there)
#
download_data_pxe() {
	debug_log "download_data_pxe" "$*"
	local CMD CLIENT SERVER GW MASK PORT ETH PROTOCOL

	mkdir -p "$1/$LIVEKITNAME"

	getpar ip 1 1 | while IFS=":" read CLIENT SERVER GW MASK PORT; do
		echo_green_star
		echo "Downloading files from $SERVER ..."

		ETH=$(init_network_dev)
		if [ "$PORT" = "" ]; then PORT="7529"; fi

		# set IP address as given by boot paramter
		if [ "$CLIENT" != "" -a "$MASK" != "" ]; then
			ifconfig $ETH "$CLIENT" netmask "$MASK"
			route add default gw "$GW"
		else
			# if client ip is unknown, try to get a DHCP lease
			udhcpc -i $ETH -f -q
		fi

		# well known IP address of Google public DNS service
		echo nameserver 8.8.8.8 >>/etc/resolv.conf

		PROTOCOL=http
		wget -q -O "$1/PXEFILELIST" "http://$SERVER:$PORT/PXEFILELIST?$(uname -r):$(uname -m)"
		if [ $? -ne 0 ]; then
			echo "Error downloading from http://$SERVER:$PORT, trying TFTP" >&2
			PROTOCOL=tftp
			tftp -g -r PXEFILELIST -l "$1/PXEFILELIST" $SERVER
		fi

		cat "$1/PXEFILELIST" | while read FILE; do
			if [ "$PROTOCOL" = "http" ]; then
				wget -O "$1/$LIVEKITNAME/$FILE" "http://$SERVER:$PORT/$FILE"
			else
				echo "* $FILE ..." >&2
				tftp -g -r $FILE -l "$1/$LIVEKITNAME/$FILE" $SERVER
			fi
		done
	done

	echo "$1/$LIVEKITNAME"
}

# init qemu-nbd block devices
# $1 - virtual machine disk image file
init_nbd() {
	local devN maxDev
	echolog "Init block device for" $yellow"$1"$default
	devN=0
	modprobe nbd nbds_max=4 max_part=4 # sleep 1
	maxDev=$(ls -1 /dev/nbd? | wc -l)
	until qemu-nbd --connect=/dev/nbd"$devN" "$1"; do
		[ $devN -ge $maxDev ] && break
		devN=$(($devN + 1))
		debug_log "Trying to init /dev/nbd"$devN""
	done
	[ $devN -ge $maxDev ] && return 1
	partprobe /dev/nbd"$devN"
}

# mount data source to destination directory using mount point directory
# $1 = source
# $2 = destination directory
# $3 = mount point directory
# $4 = file with ext parameters
mount_data_source() {
	local SOURCE DST_DIR MNT_DIR SGN_CHECK MNT_OPTS par iPARS FPARS SRC FORCE
	local CHECKSPACE='0'
	debug_log "mount_data_source" "$*"
	MNT_OPTS=''
	FORCE=''
	SOURCE=$1
	DST_DIR=$2
	MNT_DIR=$3
	FPARS=$4
	if [ "$FPARS" ]; then
		for str in $(cat $FPARS | sed -n '2,$p'); do
			local | grep -q "$(echo $str | cut -f1 -d=)" && eval $str
		done
	fi
	MNT_OPTS="$(echo $MNT_OPTS | sed 's/+/,/')"
        echo_blue_star
	echolog "$MOUNT_DATA_SOURCE" $yellow"$SOURCE"$default

	mkdir -p $DST_DIR
	log "find_data $SOURCE $MNT_DIR  $FPARS"
	DATA_FROM=$(find_data "$SOURCE" "$MNT_DIR" "$FPARS")
	debug_log "DATA_FROM=$DATA_FROM"
	debug_shell
        ##################################################################
		if ! [ -e "$DATA_FROM" ]; then
			echo $FPARS | grep -Eq "${UIRD_HOME}|${UIRD_CHANGES}" && mkimg $SOURCE $MNT_DIR $FPARS
			log "mkimg maked DATA_FROM - $DATA_FROM"
		fi
        ##################################################################
	[ -b "$DATA_FROM" ] && mount_device "$DATA_FROM" "$DST_DIR" "$MNT_OPTS" "" "$FPARS" # mount block device
	log "DATA_FROM - $DATA_FROM"
	if [ -r "$DATA_FROM" ]; then
		log "mount_device $DATA_FROM $DST_DIR  $MNT_OPTS"
		[ -d "$DATA_FROM" ] && mount_device "$DATA_FROM" "$DST_DIR" "$MNT_OPTS" "" "$FPARS" # mount dir
		if [ -f "$DATA_FROM" ]; then
			if qemu-img info "$DATA_FROM" 2>/dev/null | grep "^file" | grep -vq "file.*raw$"; then
				init_nbd "$DATA_FROM"
				>$DST_DIR/qemu_ndb_layer
			else
				log "mount_device $DATA_FROM $DST_DIR $MNT_OPTS  ""  $FPARS # mount again, it may be loop device"
				mount_device "$DATA_FROM" "$DST_DIR" "$MNT_OPTS" "" "$FPARS" # mount again, it may be loop device
				echolog "$MOUNT_DATA_SOURCE_USING" $yellow$DATA_FROM$default
			fi
		fi
        ####################################################################
		if [ "$CHECKSPACE" -ne '0' -a "$(df $DST_DIR -m | tail -n1 | awk '{print $4}')" -lt "$CHECKSPACE" ]; then
			echolog $red"$FREE_SPACE_LESS_THEN_CHECK"$default
			echo -ne $yellow"$FREE_SPACE_LESS_THEN_CHECK_ASK"$default"  "
			ANS=$(ask_answer "${FREE_SPACE_LESS_THEN_CHECK}, $FREE_SPACE_LESS_THEN_CHECK_ASK")
			case "$ANS" in
			"S" | "s")
			        #shutdown
				poweroff -f
				;;
			"R" | "r")
				#reboot
				reboot -f
				;;
			"C" | "c")
				#continue
				;;
			"E" | "e")
				#erase
				echo -n "You have 15 seconds to power off the machine and save your data"
				for a in {0..15}; do
				    echo -n .
				    sleep 1
				done
				rm -fr ${DST_DIR}/*
				;;
			*)
				#else - SHELL
				shell_cmd "shell"
				;;
			esac
		fi
        ####################################################################
	elif [ "$(getpar $UIRD_FORCE)_" == "enabled_" -o "$FORCE" == "yes" ]; then
		rmdir $DST_DIR
		echolog $red"$MOUNT_DATA_SOURCE_NOT_FOUND"$default
		echolog $yellow"Source $SOURCE droped. Continue..."$default
	else
		rmdir $DST_DIR
		echolog $red"$MOUNT_DATA_SOURCE_NOT_FOUND"$default
		echo -ne $yellow"$MOUNT_DATA_SOURCE_ASK"$default"  "
		ANS=$(ask_answer "${MOUNT_DATA_SOURCE_NOT_FOUND}, $MOUNT_DATA_SOURCE_ASK")
		case "$ANS" in
		"S" | "s")
			#shutdown
			poweroff -f
			;;
		"R" | "r")
			#reboot
			reboot -f
			;;
		"T" | "t")
			#Try again
			echo -ne "Changing SOURCE  [ Hit enter for - ${green}${1}${default} ]: "
			SRC=$(ask_answer "Changing SOURCE  [ Hit enter for - ${1} ]")
			[ "$SRC" == "" ] && SRC="$1"
			mount_data_source "$SRC" "$2" "$3" $4 $5
			;;
		"C" | "c")
			#continue
			;;
		*)
			#else - SHELL
			shell_cmd "shell"
			;;
		esac
	fi

}

# copy files from UIRD to system
# $1 - union dir
syscp() {
	debug_log "syscp" "$*"
	echo_green_star
	echolog "$SETUP_SYSCP"
	local SYSCP ARR_SYSCP FILEFROM FILETO FILEFROMTO UNION
	ARR_SYSCP=$(echo $1 | tr -s ";," "\n" | uniq)
	for NUMPAR in $(getpar $UIRD_SYSCP); do
		FILEFROM=$(getpar $UIRD_SYSCP $NUMPAR 1)
		FILETO=$(getpar $UIRD_SYSCP $NUMPAR 2)
		mkdir -p ${1}${FILETO}
		cp -fa ${FILEFROM} ${1}${FILETO}/
		echo_blue_star
		echolog "${FILEFROM} -->  ${FILETO}"
	done
}

# Initialization layer
# $1 = data directory
# $2 = layer directory
# $3 = cmdline param name
init_layer() {
	debug_log "init_layer" "$*"
	echo_green_star
	echolog "$INIT_LAYER" $brown$(basename $2) " -> " $1$default
	local NUM_SUBL FROM CMD_PARAM DATAFROM MNT INIT DATA DATAMNTM FPARS
	NUM_SUBL=0
	CMD_PARAM=$3
	for PARNUM in $(getpar $CMD_PARAM); do
		FPARS="/tmp/parameters/$CMD_PARAM/$PARNUM"
		DATAFROM=$(getpar $CMD_PARAM $PARNUM 1)
		MNT=''
		INIT='no'
		for str in $(cat $FPARS | sed -n '2,$p'); do
			local | grep -q "$(echo $str | cut -f1 -d=)" && eval $str
		done
		if [ "$DATAFROM" ]; then
			DATA=$2/$NUM_SUBL
			DATAMNTM=$1/$NUM_SUBL
			mount_data_source "$DATAFROM" "$DATA" "$DATAMNTM" "$FPARS"
			if [ "$MNT" ]; then
				MOUNTBINDS="${MOUNTBINDS} ${DATA};${MNT};${INIT}"
				log "MOUNTBINDS: $MOUNTBINDS"
			fi
		fi
		NUM_SUBL=$((NUM_SUBL + 1))
	done
}

mount_binds() {
	local str INIT SOURCE DEST
	if [ "$MOUNTBINDS" ]; then
		echo_green_star
		echolog "${BINDING_TO_UNION}:"$default
		for str in ${MOUNTBINDS}; do
			SOURCE=$(echo $str | cut -f1 -d ";")
			DEST=${UNION}$(echo $str | cut -f2 -d ";")
			INIT=$(echo $str | cut -f3 -d ";")
			mkdir -p $DEST
			echo_blue_star
			if [ "$INIT" != 'no' -a "$(ls -1A $SOURCE | wc -l)" -eq 0 ]; then
				cp -fa ${DEST}/. ${SOURCE}/ >>$LOGFILE 2>&1
				echolog "Binding"$brown" $SOURCE --> $DEST"$yellow" --> Initialized"$default
			else
				echolog "Binding"$brown" $SOURCE --> $DEST"$default
			fi
			mount -o bind $SOURCE $DEST >>$LOGFILE 2>&1
		done
	fi
}

# Test filesystem POSIX compatible
posix_test() {
	# test if the filesystem is writable so changes can be stored to it
	touch $2/empty 2>/dev/null &&
		rm -f $2/empty 2>/dev/null
	# if changes can't be mounted or the filesystem is not writable,
	# fallback to the default: tmpfs
	if [ $? -ne 0 ]; then
		echo_blue_star
		echolog "$POSIX_TEST"
		fumount $2
		fumount $1
		mkdir -p $2 # mount_device might removed it

	else
		# So it is writable, we will keep the filesystem mounted.
		# Check if it supports links and chmod.
		# If not, overmount CHANGES using posixovl
		echo_blue_star
		echolog "$TESTING_FOR_POSIX"
		touch $2/.empty1 &&
			ln -sf $2/.empty1 $2/.empty2 2>/dev/null &&
			chmod +x $2/.empty1 2>/dev/null &&
			test -x $2/.empty1 &&
			chmod -x $2/.empty1 2>/dev/null &&
			test ! -x $2/.empty1 &&
			rm $2/.empty1 $2/.empty2 2>/dev/null

		if [ $? -ne 0 ]; then
			echolog $red"$POSIX_NOT_COMPATIBLE"$default
			rm $2/.empty1 $2/.empty2 2>/dev/null
			mkdir -p $1
			posixovl -F $1 -- -o attr_timeout=300,entry_timeout=300,negative_timeout=300,kernel_cache,allow_other
			find $1 >/dev/null 2>&1 # cache everything now
		fi
	fi

}

# Setup config
setup_config() {
	local INIFILE
	debug_log "setup config" "$*"
	INIFILE=$(getpar $UIRD_CONFIG 1 1)
	check_true $INIFILE || return
	echo_green_star
	echolog "$SETUP_CONFIG" $brown"$INIFILE"$default
	for n in $(ls -1 $LAYER_BASE | sort -r); do
		if [ -f $LAYER_BASE/$n/$INIFILE ]; then
			PATHINI="$LAYER_BASE/$n/$INIFILE"
			break
		fi
	done
	[ -z "$PATHINI" ] && echolog $red"$SETUP_CONFIG_NOTFOUND"$default || echolog "$SETUP_CONFIG_USING" $yellow"$PATHINI"$default
	[ -z "$PATHINI" ] && PATHINI=/dev/null
	echo "PATHINI=$PATHINI" >>/etc/initvars
	grep -Ev '^#|^$' "$PATHINI" | sed s-\\\\r-- | gzip >$MEMORY/$INIFILE.gz
	if grep -q '^CMDLINE=' "$PATHINI"; then
		echo '' >>/tmp/basecfg
		grep '^CMDLINE=' "$PATHINI" | sed s/^CMDLINE=// | tr -d [:cntrl:]\'\" >> /tmp/basecfg
		cfg_parser
	fi
	chmod 400 $MEMORY/$INIFILE.gz $MEMORY/cmdline 2>/dev/null
}

# Init swap
init_swap() {
	local newsize total FSWAP ASWAP DSWAP SOURCE SWAP_FROM NEEDZRAM NEEDZSWAP
	NEEDZSWAP=no
	NEEDZRAM=no
	debug_log "setting up swap"
	echo_green_star
	echolog "$SETUP_SWAP"
	FSWAP=""
	for NSWAP in $(getpar $UIRD_SWAP); do
		DSWAP=$(getpar $UIRD_SWAP $NSWAP 1)
		if [ -b "$DSWAP" ]; then
			swapon "$DSWAP"
		elif [ "$DSWAP" == "auto" ]; then
			ASWAP=$(list_swap_devices | head -n 1)
			[ -b "$ASWAP" ] && swapon $ASWAP
			if [ $(cat /proc/swaps | wc -l) -gt 1 ]; then
				[ $(getpar $UIRD_SWAP | wc -l) -eq 1 -a -z "$(getpar $UIRD_SWAP $NSWAP | grep nozswap)" ] && NEEDZSWAP=yes
			else
				[ $(getpar $UIRD_SWAP | wc -l) -eq 1 -a -z "$(getpar $UIRD_SWAP $NSWAP | grep nozram)" ] && NEEDZRAM=yes
			fi
			echo "90" > /proc/sys/vm/swappiness
		elif [ "$DSWAP" == "zram" ]; then
			NEEDZRAM=$NSWAP
		elif [ "$DSWAP" == "zswap" ]; then
			NEEDZSWAP=yes
		else
			FSWAP="$DSWAP $FSWAP"
		fi
	done
	SWAPFILES="$FSWAP"
	if [ $NEEDZRAM != "no" ]; then
		init_zram_swap $NEEDZRAM
	elif [ $NEEDZSWAP != "no" ]; then
		init_zswap
	fi
}

# $1 - swap files list
# $2 - mnt dir for swap files
init_swapfiles() {
	local SOURCE MNT_DIR SWAP_FROM swap
	MNT_DIR=$2
	echo_green_star
	echolog "setup swap files"
	for SOURCE in $1; do
		if [ "$(echo $SOURCE | grep "nfs://")" != "" ]; then
			init_ifcfg
			echo $SOURCE | grep -iq ^"nfs://" && SWAP_FROM=$(mount_nfs $SOURCE $MNT_DIR/$(basename $SOURCE))
		else
			SWAP_FROM=$(find_data $SOURCE $MNT_DIR "")
		fi
		if [ -f "$SWAP_FROM" ]; then
			file "$SWAP_FROM" 2>/dev/null | grep -iq "linux.*swap file" || mkswap "$SWAP_FROM" >/dev/null
			if swapon "$SWAP_FROM" >/dev/null 2>&1; then
				echo_green_star
				echolog "swap file $SOURCE enabled"
			else
				LOOPDEV=$(losetup -f)
				[ -z "$LOOPDEV" ] && LOOPDEV=$(mknod_next_loop_dev)
				$BIN_LOSETUP $LOOPDEV "$SWAP_FROM"
				mkswap $LOOPDEV >/dev/null
				swapon $LOOPDEV
				echo_green_star
				echolog "enable swap file: $SOURCE, setup a loop device $LOOPDEV as wrapper for it to work"
			fi
		fi
	done
	swap=$(free -m | grep -i "^swap.*:" | awk '{print $2}')
	echo_green_star
	echolog "ALL SWAPS: $swap"

}

# Setup changes
# $1 = changes mount directory
# $2 = changes directory
setup_changes() {
	local FPARS UMODE CHANGESVAL SOURCE CHANGESMNT
	debug_log "setup changes" "$*"
	UMODE="$(getpar $UIRD_MODE 1 1)"
	[ "$UMODE" != "changes" -a "$UMODE" != "clear" -a "$UMODE" != "hybrid" ] && return

	CHANGESVAL=$(getpar $UIRD_CHANGES 1 1)
	FPARS="/tmp/parameters/$UIRD_CHANGES/1"
	[ -z "$CHANGESVAL" ] && CHANGESVAL="changes"

	echo_green_star
	echolog "$SETUP_CHANGES" $brown"$2"$default

	if ! echo "$CHANGESVAL" | grep -q [XxLl][Zz][Mm]$; then
		log "mount_data_source $CHANGESVAL $2 $1  "$FPARS""
		if [ "$UNION_FS" == 'aufs' ]; then
			mount_data_source $CHANGESVAL $2 $1 "$FPARS"
		else
			mkdir -p $OVERLAY
			mount_data_source $CHANGESVAL $OVERLAY $1 "$FPARS"
		fi
	else
		echo_green_star
		echolog $SETUP_MACHINES_MOD $yellow"$CHANGESVAL"$default # text is not correct here
		SOURCE=$CHANGESVAL
		MNT_DIR=$1
		if [ "$(echo $SOURCE | grep "://")" != "" ]; then
			init_ifcfg
			echo $SOURCE | grep -iq ^"http://" && DATA_FROM=$(mount_httpfs $SOURCE $MNT_DIR)
			echo $SOURCE | grep -iq ^"nfs://" && DATA_FROM=$(mount_nfs $SOURCE $MNT_DIR)
			echo $SOURCE | grep -iq ^"cifs://" && DATA_FROM=$(mount_cifs $SOURCE $MNT_DIR)
			echo $SOURCE | grep -iq ^"ssh://" && DATA_FROM=$(mount_sshfs $SOURCE $MNT_DIR)
			echo $SOURCE | grep -iq ^"ftp://" && DATA_FROM=$(mount_curlftpfs $SOURCE $MNT_DIR)
			DATA_FROM_DIR=$DATA_FROM
		else
			DATA_FROM=$(find_data $SOURCE $MNT_DIR "$FPARS")
			DATA_FROM_DIR=$(find_data $(dirname $SOURCE) $MNT_DIR "$FPARS")
		fi

		CHANGESMNT="$DATA_FROM"

		if [ -f "$CHANGESMNT" ]; then
			echolog $default"  $SETUP_MACHINES_UNPACKING $yellow$CHANGESMNT$default $SETUP_MACHINES_TO_RAM ($2)"
			unsquashfs -f -d "$2" "$CHANGESMNT" # >/dev/null 2>&1
		elif [ "$DATA_FROM_DIR" ]; then
			CHANGESMNT="$DATA_FROM_DIR/$(basename $SOURCE)"
		fi

		if [ "$CHANGESMNT" ]; then
			echo "$CHANGESMNT" >$2/.savetomodule
			if ! getpar $UIRD_SHUTDOWN >/dev/null; then
				touch $(dirname $CHANGESMNT)/.lock
				losetup $(losetup -f) $(dirname $CHANGESMNT)/.lock
			fi
		fi
	fi
	#   posix_test $1 $2
}

# calculate machine UID
get_MUID() {
	MUID=mac-$(cat /sys/class/net/e*/address 2>/dev/null | head -1 | tr -d :)
	[ "$MUID" = "mac-" ] && MUID=mac-$(cat /sys/class/net/*/address 2>/dev/null | head -1 | tr -d :)
	[ "$MUID" = "mac-" -o "$MUID" = "mac-000000000000" ] && MUID=vga-$(lspci -mm | grep -i vga | md5sum | cut -c 1-12)
	echo "$MUID"
}

# $1 = machines directory
# $2 = machines mount directory
# $3 = changes directory
# $4 = changes mount directory
setup_machines() {
	debug_log "setup_machines" "$*"
	local CHANGESMNT MACHINES SOURCE MNT_DIR MUID
	[ "$(getpar $UIRD_MODE 1 1)" == "machines" ] || return

	MUID=$(get_MUID)

	if [ "$UNION_FS" == 'aufs' ]; then
		CHANGES_DIR=$3
	else
		mkdir -p $OVERLAY/changes
		CHANGES_DIR=$OVERLAY/changes
	fi

	# locate machines folders
	if cat /proc/cmdline | grep -q "$UIRD_CHANGES="; then
		# machine source was specified, we have to mount it
		MACHINES=$(getpar $UIRD_CHANGES 1 1)
		echo_green_star
		echolog "$SETUP_MACHINES" $yellow"$1"$default
		mount_data_source $MACHINES $1 $2 ""
	else
		# find in layers/0-1/. if module exists then use it at that layer it was placed
		MACHINES=$(find $LAYER_BASE/0/machines $LAYER_BASE/1/machines -maxdepth 2 2>/dev/null | grep -m1 /machines/.*/$MUID.xzm | sed s:/machines/.*:/machines:)
		# if module wasn't found try to use firstly layer/1
		[ -z "$MACHINES" -a -w $LAYER_BASE/1/machines ] && MACHINES=$LAYER_BASE/1/machines
		# if layer/1 is absent or not writeable then system layer/0 is a last point
		[ -z "$MACHINES" ] && MACHINES=$LAYER_BASE/0/machines
		# mount folder
		echo_green_star
		echolog "$SETUP_MACHINES" $yellow"$1"$default
		mkdir -p $1
		mount --bind "$MACHINES" $1
	fi
	CHANGESMNT="$1/dynamic/$MUID.xzm"
	# if exists static we will use it
	[ -f "$1/static/$MUID.xzm" ] && CHANGESMNT="$1/static/$MUID.xzm"
	# unpack module to changes folder
	if [ -f "$CHANGESMNT" ]; then
		echolog $default"  $SETUP_MACHINES_UNPACKING $yellow$CHANGESMNT$default $SETUP_MACHINES_TO_RAM"
		unsquashfs -f -d "$CHANGES_DIR" "$CHANGESMNT" >/dev/null 2>&1
	fi
	# save module filename
	echo "$CHANGESMNT" >$CHANGES_DIR/.savetomodule
	# lock media from systemd umount
	if ! getpar $UIRD_SHUTDOWN >/dev/null; then
		touch $1/.lock
		losetup $(losetup -f) $1/.lock 2>/dev/null
	fi
}

# Setup homes
# $1 = homes-layer
# $2 = home directory
setup_homes() {
	debug_log "setup homes" "$*"

	local MNT_HOME LAYER_HOMES HOMES_BR HOMES HOME

	HOMES=$(getpar $UIRD_HOMES [[:digit:]])
	HOME=$(getpar $UIRD_HOME 1 1)
	[ -z "$HOMES" ] && [ -z "$HOME" ] && return

	LAYER_HOMES=$1
	MNT_HOME=$2

	echo_green_star
	echolog "$SETUP_HOMES" $brown"$(basename $LAYER_HOMES)" " -> " "$MNT_HOME"$default

	if [ "$HOMES" ]; then
		for d_dirs in "$LAYER_HOMES"/*; do
			if [ -z $HOMES_BR ]; then
				HOMES_BR="$d_dirs=rw+wh"
			else
				HOMES_BR="$HOMES_BR:$d_dirs=rw+wh"
			fi
		done

		if [ "$UNION_FS" == 'aufs' ]; then
			mount -t aufs -o nowarn_perm,xino="$MEMORY/.xino",trunc_xino,br=$HOMES_BR aufs $MNT_HOME
		else
			# Overlayfs mount
			# WARNING!!!!!NOT TESTED!!!!!!!!!!!!!!!
			mkdir -p ${OVERLAY}/homes
			mkdir -p ${OVERLAY}/homes_workdir
			mount -t overlay -o redirect_dir=on,metacopy=off,index=on,lowerdir=${HOMES_BR},upperdir=${OVERLAY}/homes,workdir=${OVERLAY}/homes_workdir overlay $MNT_HOME
		fi
	else
		HOMES_BR="$LAYER_HOMES"/0
		mount -o bind $HOMES_BR $MNT_HOME
	fi
}

# Activate persistent changes
# $1 = data directory
# $2 = target changes directory
#
persistent_changes() {
	debug_log "persistent_changes" "$*"

	local CHANGES T1 T2

	CHANGES="$1/$(basename "$2")"
	T1="$CHANGES/.empty"
	T2="$T1"2

	# Setup the directory anyway, it will be used in all cases
	mkdir -p "$2"

	# If persistent changes are not requested, end here
	if grep -vq perch /proc/cmdline; then
		return
	fi

	# check if changes directory exists and is writable
	touch "$T1" 2>/dev/null && rm -f "$T1" 2>/dev/null

	# if not, simply return back
	if [ $? -ne 0 ]; then
		echolog "Persistent changes not writable or not used"
		return
	fi

	echo_green_star
	echolog "Testing persistent changes for posix compatibility"
	touch "$T1" && ln -sf "$T1" "$T2" 2>/dev/null &&
		chmod +x "$T1" 2>/dev/null && test -x "$T1" &&
		chmod -x "$T1" 2>/dev/null && test ! -x "$T1" &&
		rm "$T1" "$T2" 2>/dev/null

	if [ $? -ne 0 ]; then
		echo_green_star
		echolog "Activating dynamic sized storage for persistent changes"
		rm "$T1" "$T2" 2>/dev/null

		mount.dynfilefs "$CHANGES/changes.dat" 4000 "$2"
		if [ "$(device_bestfs "$2/loop.fs" | tr -d " ")" = "-t" ]; then
			mke2fs -F "$2/loop.fs" >/dev/null
		fi
		mount -o loop,sync "$2/loop.fs" "$2"
		rmdir "$2/lost+found" 2>/dev/null
	else
		echo_green_star
		echolog "Activating native persistent changes"
		mount --bind "$CHANGES" "$2"
	fi
}

# Find $UIRD_RO=,$UIRD_RW= modules in given dir
# $1 = layer directory
#
find_modules() {
	debug_log "find_modules" "$*"
	local ARR_FILTER FIND_PARAMS filter
	ARR_FILTER=$(echo $(getpar $UIRD_RO [[:digit:]])" "$(getpar $UIRD_RW [[:digit:]])" "$(getpar $UIRD_RUN [[:digit:]])" "$(getpar $UIRD_CP [[:digit:]]))
	FIND_PARAMS=$(echo $(getpar $UIRD_FIND_PARAMS 1 1) | sed 's/_/ /g')
	#    echolog "======================"$FIND_PARAMS"================="
	for filter in $ARR_FILTER; do
		find "$1" -path "$filter" $FIND_PARAMS 2>/dev/null | sort
	done
}

# List all modules in all directories
# and filter out
# $1 = layer directory

list_modules() {
	debug_log "list_modules" "$*"
	local LOAD NOLOAD MODNAME LINE
	LOAD=$(echo $(getpar $UIRD_LOAD [[:digit:]]) | sed 's/ /|/g')
	NOLOAD=$(echo $(getpar $UIRD_NOLOAD [[:digit:]]) | sed 's/ /|/g')
	find_modules "$1" | sort | uniq | while read LINE; do
		MODNAME=$(echo $LINE | cut -b ${#1}- | cut -b 2-)
		if [ "$LOAD" -a "$(echo $MODNAME | grep -E -i "$LOAD")" ]; then
			if [ "$NOLOAD" -a "$(echo $MODNAME | grep -E -i "$NOLOAD")" ]; then continue; fi
			echo $LINE
		fi
	done
}

# Copy content of rootcopy directory to union
# $1 = data directory
# $2 = union directory
copy_rootcopy_content() {
	debug_log "copy_rootcopy_content" "$*"

	if [ "$(ls -1 "$1/rootcopy/" 2>/dev/null)" != "" ]; then
		echo_green_star
		echolog "Copying content of rootcopy directory..."
		cp -a "$1"/rootcopy/* "$2"
	fi
}

# $1 copy target dir
# $2... marker files (dirs), it may be /proc/PID
copy_timer() {
	local file TARGET_DIR MARKERS_LIST REWRITE traff iface
	TARGET_DIR=$1
	shift
	MARKERS_LIST="$@"
	REWRITE="\e[25D\e[1A\e[K"
	sek=0
	echo "wait..."
	while true; do
		BREAK=yes
		echo -ne $green
		traff="$(cat /proc/net/dev | grep ':' | grep -v lo: | tail -n1 | awk '{print $2}') "
		iface="$(cat /proc/net/dev | grep ':' | grep -v lo: | tail -n1 | awk '{print $1}') "
		if [ "$traff" -eq 0 -o -z "$traff" ]; then
			iface=""
			traff=""
		else
			traff=$(((${traff} + 1) / 1048576))
		fi
		echo -e "${REWRITE}* Time: ${sek};   ${TARGET_DIR}: $(du -hd 0 $TARGET_DIR | cut -f1);   $iface  $traff "
		for file in $MARKERS_LIST; do
			[ -e $file ] && BREAK=no
		done
		[ "$BREAK" == "yes" ] && break
		sleep 1
		sek=$(($sek + 1))
		echo -ne $default
	done
}

aria2_preload() {
	local PiD ARIA_IN
	mkdir -p $1/data
	ARIA_IN=$(getpar $UIRD_ARIA2RAM [[:digit:]] | sed 's/+/  /g')
	[ "$(getpar $UIRD_ARIA2RAM 2)" ] && ARIA_IN="$ARIA_IN -Z"
	init_ifcfg
	echolog "Aria2c preload media" $green${ARIA_IN} " -> " $brown$1$default
	aria2c -q --no-netrc --seed-time=0 $ARIA_IN -d $1/data >/dev/null 2>&1 &
	PiD=/proc/$!
	log "copy_timer $PiD $1 "
	copy_timer $1 $PiD
	#hack to find_file
	mkdir $1/mount_bind
	mount -o bind $1/data $1/mount_bind
}

# Copy modules to directory
# $1 = data directory
# $2 = target directory
# $3 = target name
# $4 = filter

copy_to() {
	debug_log "copy_to" "$*"
	local C2PARAM MODNAME BUNDLE
	C2PARAM="$4"
	fullist=$(list_modules "$1")
	c2() {
		log "c2 $@"
		MODULE=$3
		MODNAME=$(echo $MODULE | cut -b ${#1}- | cut -b 2-)
		TARGET=$(dirname "$MODULE" | cut -b ${#1}- | cut -b 2-)
		mkdir -p "$2/$TARGET"
		if [ -f "$BIN_RSYNC" ]; then
			"$BIN_RSYNC" -a $MODULE $2/${TARGET}
		else
			cp -fr $MODULE $2/${TARGET}
		fi
	}
	for BUNDLE in $fullist; do
		[ "$C2PARAM" ] && ! [ "$(echo $BUNDLE | grep -E -i "$C2PARAM")" ] && continue
		echolog $yellow"  $3 $blue<- $purple$(basename "$BUNDLE")"$green
		(c2 "$1" "$2" "$BUNDLE") &
		PIDSS="$PIDSS /proc/$!"
	done
	copy_timer $2 $PIDSS
	#wait
}

# Copy modules to target directory
# $1 = data directory
# $2 = target directory
# $3 = short name (it shows in boot log, and using as alias to $4 in cmdline)
# $4 = cmdline par
copy_to_target() {
	debug_log "copy_to_target" "$*"
	if [ "$(getpar $3)$(getpar $4)" ]; then
		echo_green_star
		echolog "$COPY_TO $3"
		log "$(getpar $3)$(getpar $4)"
		FILTER="$(getpar $3 1 1)$(getpar $4 1 1)"
		if [ "$(getpar $4)" == "enabled" -o "$FILTER" == '*' ]; then
			FILTER='.'
		else
			FILTER=$(echo $(getpar $4 [[:digit:]]) | sed -r 's/\?/./g' | sed -r 's/\*/.\*/g' | sed -r 's/ /|/g')
		fi
		log "copy_to $1 $2 $3 "$FILTER""
		copy_to $1 $2 $3 "$FILTER"
	fi
}

# Create empty fstab properly
# $1 = root directory
#
fstab_create() {
	debug_log "fstab_create" "$*"

	local FSTAB
	FSTAB="$1/etc/fstab"
	echo aufs / aufs defaults 0 0 >$FSTAB
	echo proc /proc proc defaults 0 0 >>$FSTAB
	echo sysfs /sys sysfs defaults 0 0 >>$FSTAB
	echo devpts /dev/pts devpts gid=5,mode=620 0 0 >>$FSTAB
	echo tmpfs /dev/shm tmpfs defaults 0 0 >>$FSTAB
}

# ===========================================================
# FSTAB functions
# ===========================================================

# $1 = fstab file
# $2 = device name
dev_is_in_fstab() {
	debug_log "dev_is_in_fstab" "$*"
	cat "$1" | sed -r "s/#.*//" | grep -v "^[[:space:]]*none[[:space:]]" | grep -v "^[[:space:]]*tmpfs[[:space:]]" | grep -Eq "^[[:space:]]*$2[[:space:]]"
}

# update given line in fstab, add new values only if the device is not found
# $1 = fstab file to parse
# $2 = device name
# $3 = mountpoint
# $4 = filesystem
# $5 = mount options
#
fstab_add_line() {
	debug_log "fstab_add_line" "$*"
	local DIR

	if [ "$4" != "swap" ]; then DIR="$3"; else DIR="none"; fi
	if ! dev_is_in_fstab "$1" "$2"; then
		echo "$2" "$DIR" "$4" "$5" 0 0 "$FSTABLLFLAG" >>$1
	fi
}

# create correct fstab file in $1/etc/fstab and create apropriate
# mount directories in $1/mnt. This function is only calld once,
# during liveCD startup (even before init from the distro is started).
# $1 = root directory (union)
#
fstab_update() {
	debug_log "fstab_update" "$*"
	local FSTAB FSTABTMP

	FSTAB="$1/etc/fstab"
	FSTABTMP=$FSTAB$$
	mkdir -p $1/etc $1/mnt
	cat $FSTAB 2>/dev/null | grep -v "$FSTABLLFLAG" >$FSTABTMP

	if [ "$UNION_FS" = "overlay" ]; then
		fstab_add_line $FSTABTMP overlay / overlay defaults
	else
		fstab_add_line $FSTABTMP aufs / aufs defaults
	fi
	fstab_add_line $FSTABTMP proc /proc proc defaults
	fstab_add_line $FSTABTMP sysfs /sys sysfs defaults
	fstab_add_line $FSTABTMP devpts /dev/pts devpts gid=5,mode=620

	# need to fix for UIRD
	for a in "/$MOUNTDIR/$LIVEMEDIA" "/$MOUNTDIR/$LIVECHANGES" "/$LOOPMOUNT" "/$LIVEREPOSITORY" "/$MOUNTDIR/$LIVEHOME"; do
		grep -q " $a " /proc/mounts || continue
		fstab_add_line $FSTABTMP $(grep " $a " /proc/mounts | head -1 | awk '{ print $1 " " $2 " " $3 " noauto," $4 }')
	done

	mv -f $FSTABTMP $FSTAB
	return

	list_cdrom_devices | while read DEVICE; do
		MNT=$(device_mountdir $DEVICE)
		FS=$(device_filesystem $DEVICE)
		if [ "$FS" = "" ]; then FS=iso9660; fi
		mkdir -p "$1/$MNT"
		fstab_add_line $FSTABTMP $DEVICE $MNT $FS $(fs_options $FS fstab)
	done
	list_partition_devices | while read DEVICE; do
		MNT=$(device_mountdir $DEVICE)
		FS=$(device_filesystem $DEVICE)
		OPT=$(fs_options $FS fstab)

		if [ "$FS" = "swap" ]; then
			fstab_add_line $FSTABTMP $DEVICE $MNT $FS $OPT
		fi

		# If the partition has a valid filesystem, add it to fstab
		if is_supported_filesystem "$FS"; then
			fstab_add_line $FSTABTMP $DEVICE $MNT $FS $OPT
			mkdir -p "$1/$MNT"
		fi
	done

	mv -f $FSTABTMP $FSTAB
}

freemedia_old() {
	local devs device notfree dev
	#DATAMNT=/memory/data
	#MOUNTDIR=/memory/layer-base
	devs=$(cat /proc/mounts | grep -E "${DATAMNT}/from|$MOUNTDIR" | cut -d " " -f 1 | sort | uniq -d)
	for dev in $devs; do
		umount $(cat /proc/mounts | grep ${dev}.*$MOUNTDIR | cut -d " " -f 2) 2>/dev/null
		umount $dev 2>/dev/null && echo "$dev is free now"
	done
	for device in $(echo $devs | while read a; do echo $a | cut -c 1-8; done | sort | uniq); do
		cat /proc/mounts | grep -q $device && notfree="$notfree $device"
	done
	if [ $notfree ]; then
		echolog "Media:" $red"$notfree"$default "is not free!!!"
		echo -ne $yellow"(S)hutdown, (R)eboot, (C)ontinue"$default
		ANS=$(ask_answer "(S)hutdown, (R)eboot, (C)ontinue") #"
		case "$ANS" in
		"S" | "s")
			#shutdown
			poweroff -f
			;;
		"R" | "r")
			#reboot
			reboot -f
			;;
		"C" | "c")
			#continue
			;;
		*)
			#else - SHELL
			shell_cmd "shell"
			;;
		esac
	fi
}

move_run() {
	ismountpoint "${UNION}/run" && return
	echo_green_star && echolog "$INITIALIZE /run/initramfs...."
	mkdir "${UNION}/run" 2>/dev/null # if /run was removed
	mount -o move /run "${UNION}/run"
	mount -o remount,exec "${UNION}/run"
	mkdir -p "${UNION}/run/initramfs"
	rm -rf /lib/modules/*
	rm -rf /lib/firmware/*
	cp -a /{bin,dev,etc,li,root,sbin,usr,var,shut}* "${UNION}/run/initramfs/"
}

# Change root and execute init
# $1 = where to change root
#
change_root() {
	debug_log "change_root" "$*"

	umount /proc
	umount /sys

	cd "$1"

	# make sure important device files and directories are in union
	mkdir -p boot dev proc sys tmp mnt run
	chmod 1777 tmp
	if [ ! -e dev/console ]; then mknod dev/console c 5 1; fi
	if [ ! -e dev/tty ]; then mknod dev/tty c 5 0; fi
	if [ ! -e dev/tty0 ]; then mknod dev/tty0 c 4 0; fi
	if [ ! -e dev/tty1 ]; then mknod dev/tty1 c 4 1; fi
	if [ ! -e dev/null ]; then mknod dev/null c 1 3; fi
	if [ ! -e sbin/fsck.aufs ]; then ln -s /bin/true sbin/fsck.aufs; fi

	# find chroot and init
	if [ -x bin/chroot ]; then CHROOT=bin/chroot; fi
	if [ -x sbin/chroot ]; then CHROOT=sbin/chroot; fi
	if [ -x usr/bin/chroot ]; then CHROOT=usr/bin/chroot; fi
	if [ -x usr/sbin/chroot ]; then CHROOT=usr/sbin/chroot; fi
	if [ "$CHROOT" = "" ]; then fatal "Can't find executable chroot command"; fi

	if [ -x bin/init ]; then INIT=bin/init; fi
	if [ -x sbin/init ]; then INIT=sbin/init; fi
	if [ "$INIT" = "" ]; then fatal "Can't find executable init command"; fi

	mkdir -p mnt/live
	mount -n -o remount,ro aufs .
	pivot_root . mnt/live
	exec $CHROOT . $INIT <dev/console >dev/console 2>&1
}

setup_preinit() {
	local FNAME FMODE runscript str
	#local INIFILE
	#INIFILE=$(getpar $UIRD_CONFIG 1 1)
	#[ -z $INIFILE ] && return
	INIGZFILE=$MEMORY/$INIFILE.gz
	# OS.ini processing
	if [ -f $INIGZFILE ]; then
		FNAME="/dev/null"
		FMOD=""
		zcat $INIGZFILE | while read a; do
			echo "$a" | grep -Eq '^[[:space:]]*#|^[[:space:]]*$' && continue
			if echo "$a" | grep -q "^\[.*\][[:space:]]*"; then
				FNAME=$(echo "$a" | tr '[]' '|' | awk -F'|' '{print $2}' | sed s-^/--)
				FMOD=$(echo "$a" | tr '[]' '|' | awk -F'|' '{print $3}' | tr -d ' ')
				FEXEC=$(echo "$a" | tr '[]' '|' | awk -F'|' '{print $4}')
				[ ! -z "$FEXEC" ] && echo "$FEXEC  $FNAME" >> /tmp/exec
				if [ ! -z "$FMOD" ]; then
					mkdir -p "$(dirname "$FNAME")"
					[ -e "$FNAME" ] || touch "$FNAME"
					chmod "$FMOD" "$FNAME"
				fi
			elif echo "$a" | grep -q "^-"; then
				nv="$(echo "$a" | sed 's/^-//')"
				sed -i /^"$nv"$/d "$FNAME"
			elif echo "$a" | grep -q "^|"; then
				echo "$a" | sed 's/^|//' >> "$FNAME"
			elif echo "$a" | grep -q "^+"; then
				nv="$(echo "$a" | sed 's/^+//')"
				grep -q "$nv" "$FNAME" || echo "$nv" >> "$FNAME"
			else
				nv=$(echo $a | awk -F= '{print $1}')
				[ "$nv" = "" ] && continue
				if ! grep -q "^[[:space:]]*$nv=" "$FNAME" 2>/dev/null; then
					grep -q "^$a$" "$FNAME" 2>/dev/null || echo "$a" >>"$FNAME"
				else
					sed -i 's|'"^[[:space:]]*$nv=.*$"'|'"$a"'|' "$FNAME"
				fi
			fi
		done
	fi
	#run preinit scripts
	[ -f /tmp/exec ] && . /tmp/exec
	if getpar $UIRD_PREINIT && check_true $(getpar $UIRD_PREINIT 1 1); then
		for NUMPAR in $(getpar $UIRD_PREINIT); do
			runscript="$(getpar $UIRD_PREINIT $NUMPAR 1)"
			[ -x "$runscript" ] && /bin/bash $runscript
		done
	fi
}

mkimg() {
	local DIR newimg SIZE FS MNT_DIR PASS KEY FORCE
	newimg=$1  #new img (or new dir) name
	MNT_DIR=$2 #mount point
	SIZE=''
	FS=''
	KEY=''
	FORCE=""
	FPARS=$3
	if [ "$FPARS" ]; then
		for str in $(cat $FPARS | sed -n '2,$p'); do
		    local | grep -q "$(echo $str | cut -f1 -d=)=" && eval $str
		done
	fi
	log "mkimg: $FS $SIZE"
	echo ''
	echo_green_star
	echolog "$TRY_CREATE $SOURCE $FS ${SIZE}"
	if $(dirname $newimg | grep -q ^$SYSMNT); then
		DIR=$(dirname $newimg)
		mkdir -p $DIR
		SIZE=512
		FS=btrfs
	else
		ANS="y"
		if ! [ "$(getpar $UIRD_FORCE)_" == "enabled_" -o "$FORCE" == "yes" ]; then
			echo "$SOURCE $NOT_FOUND_CREATE (Y/N):"
			ANS=$(ask_answer "$SOURCE  $NOT_FOUND_CREATE (Y/N):") #"
		fi
		if [ "$ANS" == "y" -o "$ANS" == "Y" ]; then
			if $(dirname $newimg | grep -q [[:alnum:]]); then
				DIR=$(find_data $(dirname $newimg) $MNT_DIR "")
			else
				DIR="$(find $LAYER_BASE -maxdepth 1 -type d | sort | tail -n1)"
			fi
			if ! [ "$FS" ]; then
				echo "$ENTER_FS_TYPE (default ext4): "
				FS=$(ask_answer "$ENTER_FS_TYPE (default ext4): ")
				[ "$FS" == "" ] && FS='ext4'
			fi
			if ! [ "$SIZE" ]; then
				maxsize=$(df -m $DIR | tail -n1 | awk '{print $4}')
				echo "$ENTER_SIZE  (default: 1024, max: $maxsize): "
				SIZE=$(ask_answer "$ENTER_SIZE (default: 1024, max: $maxsize): ")
				[ "$SIZE" == "" ] && SIZE='1024'
			fi
		fi
	fi
	if basename $newimg | grep -Eq '\.img$|\.enc$'; then
		FNAME="$DIR/$(basename $newimg)"
		dd if=/dev/zero of="$FNAME" bs=1 count=0 seek=${SIZE}M >/dev/null
		if basename $newimg | grep -q 'enc$'; then
			if [ -n "$KEY" -a ! -f "$KEY" ]; then
				EXIST_KEY=$(find_data "$KEY" "/tmp/aeskey")
				if ! [ -f "$EXIST_KEY" ]; then
					if $(dirname $KEY | grep -q [[:alnum:]]); then
						KEYDIR=$(find_data $(dirname $KEY) $MNT_DIR "")
					else
						KEYDIR="$(find $LAYER_BASE -maxdepth 1 -type d | sort | tail -n1)"
					fi
					EXIST_KEY="${KEYDIR}/$(basename $KEY)"
					[ -f "$EXIST_KEY" ] || head -c 3705 /dev/urandom | uuencode -m - | head -n 66 | tail -n 65 > "$EXIST_KEY"
					echo ""
					echo_blue_star
					echolog "Keyfile   "$EXIST_KEY" generated"
				fi
				KEY="$EXIST_KEY"
				echo "KEY=$EXIST_KEY" >> $FPARS # to do not find it again
			fi
			if [ -f "$KEY" ]; then
				cryptsetup open --type loopaes "$FNAME" uirdnewenc --key-file "$KEY"
			else
				echo "$ENTER_PASSWORD (default: linuxforever) "
				PASS=$(ask_answer "$ENTER_PASSWORD:(default: linuxforever) ") #"
				[ -z "$PASS" ] && PASS='linuxforever'
				echo "$PASS" | cryptsetup open --type loopaes "$FNAME" uirdnewenc --key-file -
			fi
			FNAME="/dev/mapper/uirdnewenc"
		fi
		mkfs.$FS "$FNAME" >/dev/null
		basename $newimg | grep -q 'enc$' && cryptsetup close uirdnewenc
		DATA_FROM="$DIR/$(basename $newimg)"
	elif
		basename $newimg | grep -qv "\."
	then
		mkdir "$DIR/$(basename $newimg)" && DATA_FROM="$DIR/$(basename $newimg)"
	fi
}

setup_rootfs() {
	local SIZE='70%' ALG='none' FSTYPE RAM SWAP
	if [ "$1" != "yes" ]; then
		for str in $(getpar $UIRD_ROOTFS 1 '2,$p'); do
			local | grep -q "$(echo $str | cut -f1 -d=)=" && eval $str
		done
	fi
	FSTYPE=$(getpar $UIRD_ROOTFS 1 1)

	[ -z "$FSTYPE" ] && FSTYPE=tmpfs
	RAM=$(free -m | grep -i "^mem.*: " | awk '{print $2}')
	SWAP=$(free -m | grep -i "^swap.*:" | awk '{print $2}')
	[ "_$swap" == "_" ] && swap="0"
	if [ "$FSTYPE" == 'tmpfs' ]; then
		[ "$SIZE" == 'auto' ] && SIZE="$(expr \( $RAM + $SWAP \) \* 70 \/ $RAM)%"
		mount -t tmpfs -o "size=${SIZE%%%}%" tmpfs $MEMORY
	elif [ "$FSTYPE" == 'zram' ]; then
		[ $SIZE == 'auto' ] && SIZE=90%
		modprobe -q zram num_devices=2 2>/dev/null
		if [ "$ALG" != 'none' ]; then
			modprobe -q $ALG 2>/dev/null
			echo $ALG > /sys/block/zram1/comp_algorithm 2>/dev/null
		fi
		ALG=$(cat /sys/block/zram1/comp_algorithm | sed -e 's/^.*\[//' -e 's/\].*$//')
		mem_zram=$(expr $(grep MemTotal /proc/meminfo | awk ' { print $2 } ') \* ${SIZE%%%} / 100 \* 1024)
		echo $mem_zram >/sys/block/zram1/disksize
		echo $mem_zram >/sys/block/zram1/mem_limit
		mkfs.ext4 -O ^has_journal /dev/zram1 >/dev/null 2>&1
		mount -t ext4 -o discard,rw /dev/zram1 $MEMORY
	else
		echolog "unknown rootfs type: $FSTYPE"
		debug_shell
	fi

    echo_green_star
    echolog "RAM: $RAM,  SWAP: $SWAP"
    echo_green_star
    echolog "ROOTFS TYPE: ${FSTYPE} ${ALG}, ${RAMDISK_SIZE}: ${SIZE%%%}% RAM"

}

unsquashfs() {
	local force='' filexzm='' destdir
	log "using unsquashfs function, not binary"
	destdir=$(pwd)
	for a in "$@"; do
		[ -f "$a" ] && filexzm="$a"
	done
	set -- $(getopt "fd:" "$@")
	while [ ! -z "$1" ]; do
	    case "$1" in
		-f)
		    force="f"
		    shift
		    ;;
		-d)
		    destdir="$2"
		    shift 2
		    ;;
                *) break ;;
	    esac
	done
	if ! [ -f $filexzm ]; then
		echolog " $filexzm -- no such file"
		return
	fi
	mkdir -p /tmp/tmpmntdir
	mount_device "$filexzm" /tmp/tmpmntdir
	cp -a"$force" /tmp/tmpmntdir/. ${destdir}/
	[ $? != 0 ] && echolog "ERROR: $0 $@"
	umount /tmp/tmpmntdir
	rm -rf /tmp/tmpmntdir
}

ask_answer() {
	local ANSWER
	if plymouth --ping 2>/dev/null; then
		ANSWER=$(plymouth ask-question --prompt="$1")
	else
		read ANSWER
	fi
	echo "$ANSWER"
}

ask_pass() {
	local ANSWER
	if plymouth --ping 2>/dev/null; then
		ANSWER=$(plymouth ask-for-password --prompt="$1")
	else
		read -s ANSWER
	fi
	echo "$ANSWER"
}

expand_part() {
	local device partition TYPE
	which parted >/dev/null 2>&1 || return
	[ $1 ] && DEV=$1 || return
	[ -b $DEV ] || return
	eval $($BIN_BLKID -s TYPE $DEV | cut -f2 -d ' ')
	device=$(echo "$DEV" | sed -r "s/p*[0-9]+\$//g")
	partition=$(echo $DEV | sed 's/^.*[^[:digit:]]//')
	echo_green_star
	echolog "$EXPAND_DEVICE" $green"$DEV "$default >/dev/console 2>/dev/console
	parted -a optimal -s $device resizepart $partition 100% || return
	# partprobe $device
	mkdir /tmp/tmpmnt
	case $TYPE in
	ext*)
		resize2fs ${device}$partition
		mount -o rw ${device}$partition /tmp/tmpmnt
		;;
	btrfs)
		mount -o rw ${device}$partition /tmp/tmpmnt
		btrfs filesystem resize max /tmp/tmpmnt
		;;
	*) return ;;
	esac
	rm -f /tmp/tmpmnt/EXPAND_ME
	umount /tmp/tmpmnt
	rmdir /tmp/tmpmnt
	return 0
}

# check $1  to false value (no, 0, false, disable)
# if $1 empty return 0
check_true() {
	[ -z "$1" ] && return
	[ "$1" ] || return
	[ "$1" == 'no' ] && return 1
	[ "$1" == 'false' ] && return 1
	[ "$1" == 'disable' ] && return 1
	[ "$1" == '0' ] && return 1
	return 0
}

setup_union() {
	local UNION_FS
	if [ "$(getpar $UIRD_UNION 1 1)" == 'auto' ]; then
		modprobe aufs 2>/dev/null
		if cat /proc/filesystems | grep -q "aufs"; then
			echo "aufs"
			return
		else
			UNION_FS='overlay'
		fi
	else
		UNION_FS="$(getpar $UIRD_UNION 1 1)"
		[ -z $UNION_FS ] && UNION_FS='aufs'
	fi
	modprobe "$UNION_FS" 2>/dev/null
	echo "$UNION_FS"
}

setfontkeys() {
	[ -d "/usr/lib/consolefonts/${LANG}" -o -L "/usr/lib/consolefonts/${LANG}" ] && loadfont </usr/lib/consolefonts/${LANG}/$(ls -1 /usr/lib/consolefonts/${LANG}/) >/dev/null
	[ -d "/usr/lib/kbd/${LANG}" -o -L "/usr/lib/kbd/${LANG}" ] && loadkeys /usr/lib/kbd/${LANG}/$(ls -1 /usr/lib/kbd/${LANG}/) >/dev/null
}
