#!/bin/sh
# 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/uird.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 UIRD 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 "UIRD 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=               - расположение конфигурационного файла системы MagOS.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_COPY2CAHE ] && 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=$(cat /proc/cmdline 2>/dev/null | grep debug)
}

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

# header
# $1 = text to show
#
header() {
if ! getpar $UIRD_SILENT >/dev/null ; then
	echo ''
	echolog $brown"$@"$default
	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
}
export -f echo_green_star

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

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

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
}
export -f echolog

# 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
		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
	plymouth --ping >/dev/null 2>&1 && plymouth quit
	ln -s /root/bash_profile /root/.bash_profile 2>/dev/null
cat << EOF > /root/.bashrc
# .bashrc
PATH=.:/:/usr/sbin:/usr/bin:/sbin:/bin
ENV=/root/.bashrc
USERNAME="root"
LANG=$LANG
PS1='\[\033[31;1m\][\u@QuickShell \W] # \[\033[m\]'
. /livekitlib
setfontkeys
export USERNAME ENV PATH PS1 LANG
EOF
	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
}
export -f shell_cmd

# start quickshell
start_quickshell() {
	if getpar qs  > /dev/null ; then
		[ "$SECLEVEL" -gt 2 ] && return
		mkdir -p /mnt
		automount
		plymouth --ping >/dev/null 2>&1 && plymouth quit
		clear
		setfontkeys
		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
}

# 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/magos/${name}.log; then
			echo "$0 --  debug mode enabled"
			test -d ${slash}var/log/magos || mkdir -p ${slash}var/log/magos
			echo $(date) >${slash}var/log/magos/${name}.log || echo "can not create log file"
			$0 "$@" 2>&1 | tee -a ${slash}var/log/magos/${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:]].*)$/_&/'  | update_initvars
	else
		: > /tmp/parameters/$parDir/enabled
		echo "${par}=enabled" | sed -re 's/^(.*)\.(.*\=.*)$/\1_\2/' -e 's/^([[:digit:]].*)$/_&/' | update_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 -E -q " -|^-" || 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
}
export -f getpar

# 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
}


# 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
}

# 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 -E -v '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
}

# 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/"
}

# 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 -fa $([ "$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,${3//+/,}"; 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" ] && cryptsetup isLuks "$DEV"  ; then
		LUKS_DEV=$(echo $DEV |sed 's:/dev/::')
		times=3
		while [ $times -gt 0 ]; do
			echolog "$MOUNT_DEVICE_ENC" "LUKS" $green"$DEV"$default
			if ! [ -b "/dev/mapper/$LUKS_DEV" ] ; then
				log "Initialization luks partition $LUKS_DEV"
				if [ "$PASS" == '//hardware//' ] ; then
					# try all getpass_* functions
					for getpass_func in $(typeset -f |grep '^getpass_.*(.*)' |sed 's#(.*)##') ; do
						if $getpass_func $DEV | cryptsetup luksOpen "$DEV" "$LUKS_DEV" >> $LOGFILE 2>&1 ; then 
							echo getpass_${LUKS_DEV}=${getpass_func} | update_initvars
							break
						fi
					done
				fi

				if ! [ -b "/dev/mapper/$LUKS_DEV" ] ; then
					[ "$KEY"_ != "_" ] && [ ! -f $KEY ] && 	KEY=$(find_data "$KEY" "/tmp/lukskey")
					if [ "$KEY" ] ; then
						[ ! -f $KEY ] && KEY=$(find_data "$KEY" "/tmp/lukskey")
						[ -f "$KEY" ] && cryptsetup -d $KEY luksOpen "$DEV" "$LUKS_DEV" >> $LOGFILE 2>&1
					fi
				fi

				if ! [ -b "/dev/mapper/$LUKS_DEV" ] ; then
					echo "$LUKS_PASS" >/dev/console
					PASS=$(ask_pass "$LUKS_PASS")
					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 btfs (bittorrent) filesystem from the given server
# $1 = magnet link
# $2 = mountdir
# $3 = file with options
mount_btfs() {
	debug_log "mount_btfs" "$*"
	command -v $BIN_BTFS >/dev/null 2>&1 || return
	init_ifcfg 1>&2
	if [ "$3" ] ; then
		for str in  $(sed -n '2,$p' $3)  ; do
			local |grep -q "$(echo $str |cut  -f1 -d=)=" &&  eval $str 
		done 
	fi
	mkdir -p $2
	$BIN_BTFS MNT_OPTS "$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_http() {
	debug_log "mount_httpfs" "$*"
	command -v $BIN_HTTPFS >/dev/null 2>&1 || return
	init_ifcfg 1>&2
	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
# $3 = file with options
mount_ftp() {
	local DEF_OPTIONS MNT_OPTS
	debug_log "mount_curlftpfs" "$*"
	command -v $BIN_CURLFTPFS >/dev/null 2>&1 || return
	init_ifcfg 1>&2
	if [ "$3" ] ; then
		for str in  $(sed -n '2,$p' $3)  ; do
			local |grep -q "$(echo $str |cut  -f1 -d=)=" &&  eval $str 
		done 
	fi
	mkdir -p $2
	$BIN_CURLFTPFS $MNT_OPTS $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
# $ = file with parameters
mount_ssh() {
	local DEF_OPTIONS ERR MNT_OPTS
	debug_log "mount_sshfs" "$*"
	command -v $BIN_SSHFS >/dev/null 2>&1 || return
	init_ifcfg 1>&2
	if [ "$3" ] ; then
		for str in  $(sed -n '2,$p' $3)  ; do
			local |grep -q "$(echo $str |cut  -f1 -d=)=" &&  eval $str 
		done 
	fi	
	mkdir -p $2
	times=3
	$BIN_SSHFS ${1/ssh:??/} $2 $MNT_OPTS </dev/console >/dev/console 2>/dev/console
	[ "$?" -eq 0 ] || $BIN_SSHFS $(dirname ${1/ssh:??/}) $2 $MNT_OPTS </dev/console >/dev/console 2>/dev/console
	[ "$?" -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
# $3 - file with parameters
mount_9p() {
	debug_log "mount_9p" "$*"
	local TAG ERR MNT_OPTS DEF_OPTIONS
	DEF_OPTIONS="trans=virtio,msize=100000000"
	if [ "$3" ] ; then
		for str in  $(sed -n '2,$p' $3)  ; do
			local |grep -q "$(echo $str |cut  -f1 -d=)=" &&  eval $str 
		done 
	fi
	[ "$MNT_OPTS" ] || MNT_OPTS="$DEF_OPTIONS"
	TAG=$(echo $1 |sed 's#^9p://##')
	mkdir -p $2
	mount -t 9p -o ${MNT_OPTS//+/,} $TAG $2
	ERR=$?
	[ $ERR -eq 0 ] || return
	echo $2
}

# Mount nfs filesystem from the given server
# $1 = server
# $2 = mountdir
# $3 - file with parameters
mount_nfs() {
	debug_log "mount_nfs" "$*"
	local DEF_OPTIONS MNT_OPTS SHARE
	DEF_OPTIONS="nolock,rsize=4096,wsize=4096"
	init_ifcfg 1>&2
	if [ "$3" ] ; then
		for str in  $(sed -n '2,$p' $3)  ; do
			local |grep -q "$(echo $str |cut  -f1 -d=)=" &&  eval $str 
		done 
	fi
	[ "$MNT_OPTS" ] || MNT_OPTS="$DEF_OPTIONS"
	mkdir -p $2
	modprobe nfs
	SHARE=$(echo $1 | sed s-^nfs://--)
	if mount -t nfs $SHARE $2 -o ${MNT_OPTS//+/,} 2>/dev/null; then
		echo $2
	elif mount -t nfs $(dirname $SHARE) $2 -o ${MNT_OPTS//+/,} 2>/dev/null; then
		echo $2/$(basename $SHARE)
	fi
}

# Mount cifs filesystem from the given server
# $1 = server
# $2 = mountdir
# $3 = file with options
mount_cifs() {
	debug_log "mount_cifs" "$*"
	local DEF_OPTIONS MNT_OPTS SHARE
	init_ifcfg 1>&2
	if [ "$3" ] ; then
		for str in  $(sed -n '2,$p' $3)  ; do
			local |grep -q "$(echo $str |cut  -f1 -d=)=" &&  eval $str 
		done 
	fi
	mkdir -p $2
	modprobe cifs 1>&2
	SHARE=$(echo $1 | sed s-^cifs://--)
	if mount -t cifs $SHARE $2 -o ${MNT_OPTS//+/,} 2>/dev/null 1>&2; then
		echo $2
	elif mount -t cifs $(dirname $SHARE) $2 -o ${MNT_OPTS//+/,} 2>/dev/null 1>&2 ; then
		echo $2/$(basename $SHARE)
	fi
}

# Mount rsync filesystem from the given server
# $1 = server
# $2 = mountdir
# $3 = file with options
mount_rsync() {
	debug_log "mount_rsync" "$*"
	local DEF_OPTIONS MNT_OPTS SHARE
	command -v $BIN_RSYNC >/dev/null 2>&1 || return
	init_ifcfg 1>&2
	DEF_OPTIONS="--progress -a"
	if [ "$3" ] ; then
		for str in  $(sed -n '2,$p' $3)  ; do
			local |grep -q "$(echo $str |cut  -f1 -d=)=" &&  eval $str 
		done 
	fi
	[ "$MNT_OPTS" ] || MNT_OPTS="$DEF_OPTIONS"
	mkdir -p $2
	$BIN_RSYNC $MNT_OPTS $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=${MNT_OPTS//+/,}
	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
}
export -f uuid_label_to_dev

# 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=''
	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/')
	[ "$TIMEOUT" = "" ] && TIMEOUT=5
	log "find_file "$1" "$2" "$3" "
	while [ $TIMEOUT -gt 0 -a "$RESULT" = "" ]; do
		log "find_file "$1" "$2" "$3" "
		if echo "$1" | grep -q "://"  ; then
			PROTOCOL=$(echo $1 |cut -f1 -d:)
			[ -f "/mount_$PROTOCOL" ] && source "/mount_$PROTOCOL" 1>&2 
			RESULT=$(mount_$PROTOCOL $1 $2 $FPARS)
		else
			RESULT=$(find_file "$1" "$2" "$FPARS")
		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
}

# 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
export -f init_network_dev

	# 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
	ifconfig |grep -q 'addr' && return
	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
		fi

	done
}
export -f init_ifcfg

# 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="${MNT_OPTS//+/,}" 
	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" )
##################################################################
		if ! [ -e "$DATA_FROM" ] ; then 
			echo $FPARS |grep -E -q '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 -mP |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() {
	command -v posixovl >/dev/null 2>&1 || return 
	# 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" | update_initvars
	grep -E -v '^#|^$' "$PATHINI" | sed s-\\\\r-- | gzip >$MEMORY/$LIVEKITNAME.ini.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/$LIVEKITNAME.ini.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
}

# 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
}

# $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
}

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/"
}

setup_preinit ()  {
local  FNAME FMODE runscript str
INIGZFILE=$MEMORY/$LIVEKITNAME.ini.gz
# OS.ini processing
if [ -f $MEMORY/$LIVEKITNAME.ini.gz ] ;  then
FNAME="/dev/null" ; FMOD=""
zcat  $INIGZFILE |  while read a ;do
   echo "$a" | grep -E -q '^[[: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 -E -q '\.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
    parted --fix -a optimal -s $device resizepart $partition 100% 1>&2 || return
    partprobe $device 2>/dev/null 1>&2 || sleep 1
    fsck_device ${device}$partition $TYPE 1>&2
    mkdir /tmp/tmpmnt
    case $TYPE in
	ext* )
		resize2fs ${device}$partition 1>&2
		mount -o rw ${device}$partition /tmp/tmpmnt 1>&2  ;;
	btrfs )
		mount -o rw ${device}$partition /tmp/tmpmnt 1>&2
		btrfs filesystem resize max /tmp/tmpmnt 1>&2 ;;
	*) return ;;
	esac
	rm -f /tmp/tmpmnt/EXPAND_ME 1>&2
	umount /tmp/tmpmnt 1>&2
	rmdir /tmp/tmpmnt 1>&2
	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
}

getpass_lspci() {
	busybox lspci |md5sum |cut -f1 -d ' '
}

update_initvars() {
	local str nv 
	read str
	nv=$(echo $str | awk -F= '{print $1}')
	if ! grep -q "^[[:space:]]*$nv=" /etc/initvars 2>/dev/null ;then
		grep -q "^$str$" /etc/initvars 2>/dev/null || echo "$str" >> /etc/initvars
    else
		sed -i 's|'"^[[:space:]]*$nv=.*$"'|'"$str"'|' /etc/initvars
	fi
	sed -i '/^$/d' /etc/initvars
}
