#!/usr/bin/env bash
#
# Description: Make new root from modules for container chroot
#
# Author: Dmitry Razumov  <asmeron@ublinux.com>
#

VERSION_SCRIPT=2.18

usage(){
cat <<EOF
Usage:	$(basename $0) --build <$(basename $0) keys> <--command>
	    Команда которая будет запущена в контейнере
	$(basename $0) --build <$(basename $0) keys> <--script>
	    Скрипт который будет скопирован в контейнер и запущен из контейнера
	$(basename $0) --destroy <$(basename $0) keys>
	    Завершить все процессы, по выбору сохранить изменения контейнера и уничтожить контейнер
	$(basename $0) --build --destroy <$(basename $0) keys> <--command>
	    Команда которая будет выполнена в контейнере,
	    после выполнения по выбору сохранить изменения контейнера и уничтожить контейнер
	$(basename $0) --build --destroy <$(basename $0) keys> <--script>
	    Скрипт который будет скопирован в контейнер и запущен из контейнера,
	    после выполнения по выбору сохранить изменения контейнера и уничтожить контейнер

$(basename $0) keys:
-h, --help 		Справка
    --showlayers 	Показать выбранные слои после фильтров --mask --mlist --flist --plist
    --build, build	Инициализировать контейнер и выполнить команды
-n, --name=<ИМЯ>	Имя создаваемого контейнера
      * ИМЯ=random	Имя создаваемого контейнера рандомное 4 цифры, по умолчанию
	ИМЯ=currentdir	Имя создаваемого контейнера по имени каталога, где расположен скрипт
-t, --type=<ТИП>	Тип контейнера:  * chroot | nspawn | nspawn-service (systemd-nspawn нужен и на хост-системе и на гостевой), без параметра chroot
      * chroot 		Выполнить chroot и запустить интекактивно команду(--command) / скрипт(--script), по умолчанию
	nspawn 		Выполнить systemd-nspawn и запустить интекактивно команду(--command) / скрипт(--script)
	nspawn-service 	Запустить контейнер через сервис и выполнить скрипт --script
-m, --mask=<МАСКА>	Маска для системных бандлов из которых будет создана aufs для контейнера
    --mlist=<МОДУЛЬ1,МОДУЛЬn,ПАПКАn>
			Список модулей и папок для создания aufs, разделитель в списке ","
			В списке можно применять "#" для блокирования. Пример : --mlist 1.${EXT},#2.${EXT},3.${EXT}
    --flist=<ФАЙЛА>	Список модулей из файла. В файле можно применять "#" для блокирования
			Создать список из модулей в каталоге <КАТАЛОГ>: find <КАТАЛОГ> -name *.${EXT} |sort |awk '{print "#"$0}' > <КАТАЛОГ>/flist.lst
    --plist=<КАТАЛОГ>	Список модулей из папки. Формитруем список из файлов, симлинков и каталогов
			Если каталог существует, то в список модулей попадут все файлы/симлинки/директории из каталога <КАТАЛОГ>
    Если отсутствуют опции -m | --mask | --mlist | --flist | --plist, то берутся файлы/симлинки модулей из папки ./modules и файла ./modules/modules.lst
-c, --changes=<КАТАЛОГ>	Место хранения изменений во время работы контейнера, без параметра по умолчанию ram
      * ram		Хранить изменения в ОЗУ во время работы, по умолчанию
        container	Хранить изменения по пути <КАТАЛОГ_КОНТЕЙНЕРА>/changes во время работы
        %КАТАЛОГ%	Хранить изменения по пути %КАТАЛОГ% во время работы
    --boot		Только для --type nspawn. Выполнить полную инициализацию контейнера с сервисами systemd. См. systemd-nspawn -b
-b, --bind=<СПИСОК>	Список каталогов для монтирования в chroot в формате /SOURCE/DIR1::/TARGET/DIR1,/SOURCE/DIR2::/TARGET/DIR2
-X 			Разрешить подключение к текущей X сессии. Для запуска в chroot приложений с GUI. Рекомендуется использовать с --type nspawn
    --prepare		Подготовить контейнер, создать passwd, shadow, group, gshadow (root,nobody), 
			скопировать в контейнер с хоста mirrorlist, pacman.conf, makepkg.conf и др.
--, --command <КОМАНДА>	Команда для выполнения в контейнере, параметр должен быть последним в строке
			Запуск программы с другой локалью : --command LANG=ru_RU.UTF-8 program. Работает только с --type chroot
    --script <ФАЙЛ>	Скрипт, который будет скопирован в контейнер и запущен в нем
			Если не задан параметр --command или --script, то по умолчанию --script ./conf.d/container.script

    --destroy, destroy	Выключить/закрыть контейнер, остановив все процессы контейнера
-f, --fast		Только для --destroy и --save module, создавать модуль изменений c быстрым типом компрессии lz4
    --comp		Только для --destroy и --save module, тип компрессии: gzip, lzma, lzo, lz4, xz, zstd. По умолчанию gzip
    --blocksize		Только для --destroy и --save module, размер блока. Суфикс: K, М. По умолчанию 32K
    --notrim 		Только для --destroy, не удалять заведомо не нужные в модуле файлы (кэш и т.п.)
    --wh 		Только для --destroy, не удалять специальные файлы aufs (тени)
    --save rootcopy 	Только для --destroy, сохранит изменения после закрытия контейнера в папку <КАТАЛОГ_КОНТЕЙНЕРА>/rootcopy
    --save <КАТАЛОГ> 	Только для --destroy, сохранит изменения после закрытия контейнера в папку <КАТАЛОГ>
    --save module 	Только для --destroy, сохранит изменения после закрытия контейнера в модуль <КАТАЛОГ_КОНТЕЙНЕРА>/modules/change-<date>.${EXT}
    --save <ФАЙЛ.${EXT}> 	Только для --destroy, сохранит изменения после закрытия контейнера в модуль <ФАЙЛ.${EXT}>
    Без параметра --save, изменения после выхода из контейнера удаляются

Ядро хост-системы должно быть одинаковой архитектуры (i686 или x86_64) c гостевой. Сама хост-система может быть любой

Примеры
=====================================================
$(basename $0) --showlayers --mask 0[1-9]0-2109-core
    Показать выбранные слои после фильтров --mask --mlist --flist --plist
$(basename $0) --build --name container-01 --flist %КАТАЛОГ_КОНТЕЙНЕРА%/modules/modules.lst -- pacman -S mc
    Создание контейнера container-01, подключить модули по списку из %КАТАЛОГ_КОНТЕЙНЕРА%/modules/modules.lst, внутри контейнера выполнить pacman -S mc
$(basename $0) --build -X -t chroot --mlist /path/1.$EXT,#2.,3.$EXT --command thunar
    Запуск программы thunar из гостевой системы, собранной из модулей 1 и 3 (1 в верхнем слое AUFS, т.е. перекрывает 2):
$(basename $0) --build --boot --type nspawn
    Создать контейнер с именем каталога откуда запустили, подключим модули из папки ./modules/* и файла ./modules/modules.lst,
    запустить скрипт внутри контейнера ./conf.d/container.script

$(basename $0) --destroy --name container-01 --save rootcopy
    Закрыть контейнер container-01, по окончанию сборка модуля изменений в каталог %КАТАЛОГ_КОНТЕЙНЕРА%/rootcopy
$(basename $0) --destroy --name container-01 --save module
    Закрыть контейнер container-01, по окончанию сохранение изменений в модуль %КАТАЛОГ_КОНТЕЙНЕРА%/modules/change-%date%.${EXT}
$(basename $0) --destroy --name container-01 --save module --wh --comp xz --blocksize 32K
    Закрыть контейнер container-01, по окончанию, сохранение изменений с тенями ФС в модуль %КАТАЛОГ_КОНТЕЙНЕРА%/modules/change-%date%.${EXT}
$(basename $0) --destroy --name container-01
    Закрыть контейнер container-01, не сохраняя изменения

$(basename $0) --build --name container-01 --flist /tmp/module.lst --destroy --save rootcopy -- pacman -S mc
    Создание контейнера container-01, подключить модули по списку из /tmp/module.lst, внутри контейнера выполнить pacman -S mc,
    по окончанию сборка модуля изменений в каталог rootcopy
EOF
    exit 0
}

arguments() {
# Pre-process options to:
# - expand -xyz into -x -y -z
# - expand --longopt=arg into --longopt arg
    local ARGV=()
    local END_OF_OPT=
    while [[ $# -gt 0 ]]; do
	arg="$1"; shift
	case "${END_OF_OPT}${arg}" in
	    --) ARGV+=("$arg"); END_OF_OPT=1 ;;
	    --*=*)ARGV+=("${arg%%=*}" "${arg#*=}") ;;
	    --*) ARGV+=("$arg") ;;
	    -*) for i in $(seq 2 ${#arg}); do ARGV+=("-${arg:i-1:1}"); done ;;
	    *) ARGV+=("$arg") ;;
	esac
    done
# Apply pre-processed options
    set -- "${ARGV[@]}"
# Parse options
    local END_OF_OPT=
    local POSITIONAL_ARGS=()
    [[ -z $@ ]] && usage && exit 0
    while [[ $# -gt 0 ]]; do
	case "${END_OF_OPT}${1}" in
	    -h	| --help	| help)		usage && exit 0 ;;
		  --showlayers	| showlayers)	get_layers && echo "${LAYERS}" && exit 0 ;;
		  --build 	| build)	BUILD=1 ;;
		  --destroy 	| destroy) 	DESTROY=1 ;;
	    -n 	| --name) 			shift; NAME="$1" ;;
	    -f 	| --fast) 			COMPRESSION_FAST=1 ;;
		  --comp)			shift; COMPRESSION="$1" ;;
		  --blocksize)			shift; BLOCKSIZE="$1" ;;
	    -s  | --script) 			shift; SCRIPT="$1" ;;
	          --command) 			END_OF_OPT=1 ;;
	    -m  | --mask) 			shift; MASK="$1" ;;
	    -b  | --bind) 			shift; BIND="$1" ;;
		  --mlist) 			shift; MLIST="$1" ;;
		  --flist) 			shift; FLIST="$1" ;;
		  --plist) 			shift; PLIST="$1" ;;
	    -t  | --type) 			shift; TYPE="$1" ;;
    		  --save) 			shift; SAVE="$1" ;;
	    -c  | --changes) 			shift; CHANGES="$1" ;;
		  --notrim) 			NOTRIM=1 ;;
	    -w  | --wh) 			WH_ALLOW=1 ;;
	    -X  | --Xhost)			XHOST=1 ;;
		  --boot) 			BOOT="-b" ;;
		  --prepare) 			PREPARE=1 ;;
	    -q  | --quiet)     	   		QUIET=1 ;;
	    -V  | --version)	   		echo "Version: ${VERSION_SCRIPT}"; exit 0 ;;
	    --stdin)	    	   		READ_STDIN=1 ;;
	    --)             	   		END_OF_OPT=1 ;;
	    -*  | --*)         	   		echo "WARNING: Unrecognized argument, skiped: $1" >&2  ;;
	    *)              	   		POSITIONAL_ARGS+=("$1"); OPT_END="$1" ;;
	esac
	shift
    done
# Restore positional parameters
    set -- "${POSITIONAL_ARGS[@]}"
# Default options
    [[ -n ${BLOCKSIZE} ]] || BLOCKSIZE="32K"
    [[ -n ${COMPRESSION} ]] || COMPRESSION="gzip"
    [[ -n ${COMPRESSION_FAST} ]] && COMPRESSION="lz4"
    [[ -n ${WH_ALLOW} ]] && unset ARG_WH || ARG_WH="-e '... .wh.*'"
#    [[ -n ${NOTRIM} ]] && unset TRIM || TRIM="--trim"
    [[ -z ${TYPE} ]] && TYPE="chroot"
    [[ -z ${NAME} ]] && NAME="random"
    [[ -n ${END_OF_OPT} ]] && { [[ -x ${POSITIONAL_ARGS[@]} ]] && SCRIPT="${POSITIONAL_ARGS[@]}" || COMMAND="${POSITIONAL_ARGS[@]}"; }
# Если условия поиска модулей не заданы, то искать в папке ${PATH_WORK}/modules/
#    if [[ -z "${MASK}${MLIST}${FLIST}${PLIST}" ]]; then
#	PATH_DEF_PLIST="${PATH_WORK}/modules/"
#	PATH_DEF_FLIST="${PATH_WORK}/modules/modules.lst"
#	[[ -n $(find ${PATH_DEF_PLIST} -print) ]] && PLIST="--plist ${PATH_DEF_PLIST}"
#	[[ -f ${PATH_DEF_FLIST} ]] && FLIST="--flist ${PATH_DEF_FLIST}"
#    fi 
}

get_layers(){
    local SRC_LAYERS= FIND_LAYER=
    if  [[ "${MASK}" || "${MLIST}" || "${FLIST}" || "${PLIST}" ]]; then
	[[ "${MASK}" ]] && SRC_LAYERS+="$(aufs-n --hidetop  --reverse --raw '$bname_source $bundle' | grep -E "${MASK}" | awk '{print $2}')"$'\n'
	[[ "${MLIST}" ]] && SRC_LAYERS+="$(echo "${MLIST}" | sed 's/#[^,]\+,\?//g; s/,$//' | sed 's/[\,]/ /g' | sed 's/[\;]/ /g')"$'\n'
	[[ "${FLIST}" ]] && SRC_LAYERS+="$(grep -v '^#' ${FLIST})"$'\n'
	[[ "${PLIST}" ]] && SRC_LAYERS+="$(find ${PLIST}/* -maxdepth 0 -not -name '*.lst' -not -path '*/\.*')"$'\n'
    else
	SRC_LAYERS=$(aufs-n --hidetop --reverse --raw '$bundle')
    fi 2>/dev/null
#    [[ -d "${ROOTCOPY_PATH}" ]] && SRC_LAYERS="${SRC_LAYERS} ${ROOTCOPY_PATH}"
#    echo ${SRC_LAYERS} | grep [[:alnum:]] && return
    while IFS= read -ru3 SELECT_LAYER; do
	[[ ${SELECT_LAYER} == @(""|" ") ]] && continue
	#[ -e ${SELECT_LAYER} ] && realpath -q ${SELECT_LAYER}
	FIND_LAYER_NAME=${SELECT_LAYER##*/}
	[[ ${FIND_LAYER_NAME} =~ ".ubm"$ ]] && FIND_LAYER_NAME=${FIND_LAYER_NAME//.ubm/\.ubm}
	# Если указано в простом виде '010-core-*-*-x86_64.ubm', то заменить на egrep форму '010-core-[^-]-[^-]-x86_64.ubm'
	[[ ${FIND_LAYER_NAME} =~ "-*-" ]] && FIND_LAYER_NAME=${FIND_LAYER_NAME//'-*'/'-[^-]+'}
	# Если указан просто каталог, то добавить шаблон имени модуля *.ubm
	[[ -d ${FIND_LAYER_NAME} ]] && FIND_LAYER_NAME="${FIND_LAYER_NAME}/.*\.ubm"
	local REALPATH_SELECT_LAYER=$(realpath -q ${SELECT_LAYER%/*})
	[[ -n ${REALPATH_SELECT_LAYER} ]] && FIND_LAYER=$(find ${REALPATH_SELECT_LAYER}/ -regextype posix-egrep -regex ".*/${FIND_LAYER_NAME}" -exec realpath -q {} \;) || FIND_LAYER=
	[[ -n ${FIND_LAYER} ]] && LAYERS+="${FIND_LAYER//$'\n'/ } " || msg "Warning: Container \"${SELECT_LAYER}\" cannot be found, it is skipped !" 0
    done 3<<<  "${SRC_LAYERS//,/$'\n'}"
    [[ ${LAYERS} == @(""|" ") ]] && msg "Warning: Empty layers list !" 3 +
}

ubcontainer_rc_local() {
cat <<EOF > $1
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.

[Unit]
Description=UBLinux container autorun scripts - local stage

[Service]
Type=forking
ExecStart=/var/lib/${NAMESCRIPT}/${NAME}/$(basename ${SCRIPT})
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
EOF
}
option_prepare() {
    mkdir -p "${CONTAINER_ROOT}/tmp"
    [[ -f ${CONTAINER_ROOT}/etc/os-release ]] || cp -af /etc/os-release "${CONTAINER_ROOT}/etc/os-release"
    [[ -f ${CONTAINER_ROOT}/etc/passwd ]] || echo -e "root:x:0:0::/root:/bin/bash\nnobody:x:65534:65534:Nobody:/:/usr/bin/nologin" | tee "${CONTAINER_ROOT}/etc/passwd" &>/dev/null
    [[ -f ${CONTAINER_ROOT}/etc/shadow ]] || echo -e "root:!*:14871::::::\nnobody:!*:18660::::::" | tee "${CONTAINER_ROOT}/etc/shadow" &>/dev/null
    [[ -f ${CONTAINER_ROOT}/etc/group ]] || echo -e "root:x:0:root\nnobody:x:65534:" | tee "${CONTAINER_ROOT}/etc/group" &>/dev/null
    [[ -f ${CONTAINER_ROOT}/etc/gshadow ]] || echo -e "root:!*::root\nnobody:!*::nobody" | tee "${CONTAINER_ROOT}/etc/gshadow" &>/dev/null
    cp -af /usr/lib/os-release "${CONTAINER_ROOT}/usr/lib/os-release"
    cp -af /etc/lsb-release "${CONTAINER_ROOT}/etc/"
    cp -af /usr/lib/locale/* "${CONTAINER_ROOT}/usr/lib/locale/"
    install -dm0755 "${CONTAINER_ROOT}/etc/pacman.d"
    cp -af /etc/pacman.d/gnupg "${CONTAINER_ROOT}/etc/pacman.d"
    cp -af /etc/pacman.d/mirrorlist "${CONTAINER_ROOT}/etc/pacman.d/"
    cp -af /etc/pacman.conf "${CONTAINER_ROOT}/etc/"
    cp -af /etc/makepkg.conf "${CONTAINER_ROOT}/etc/"
#    sed -i "/^OPTIONS=/s/\!lto/lto/" "${CONTAINER_ROOT}/etc/makepkg.conf"
    sed -i "s/^#MAKEFLAGS=.*/MAKEFLAGS=\"-j\$\(nproc\)\"/" "${CONTAINER_ROOT}/etc/makepkg.conf"
    sed -i "s/^COMPRESSZST=.*/COMPRESSZST=(zstd -T0 -c -z -v --ultra -20 -)/" "${CONTAINER_ROOT}/etc/makepkg.conf"
    echo "${NAME}" > "${CONTAINER_ROOT}/etc/hostname"
}

option_bind() {
    local binds=$(echo "${BIND}" |sed 's/[\,]/ /g')
    for bnd in $binds; do
    	extdir=$(echo $bnd |sed 's/::/#/' |cut -d "#" -f1)
    	indir="${CONTAINER_ROOT}/$(echo $bnd |sed 's/::/#/' |cut -d "#" -f2)"
	[[ $1 == "mount" ]] && mkdir -p "$indir" && mount -o bind "$extdir" "$indir"
	[[ $1 == "umount" ]] && umount "$indir"
#	BIND_DIRS="$BIND_DIRS $indir"
    done
}

build_container() {
# Generate layer list
    get_layers
# Make root aufs
    CONTAINER_ROOT=$(make_aufs ${NAME} ${CHANGES_PATH}); status=$?
    [[ ${status} -eq 1 ]] && msg "Warning: can't create a \"${NAME}\" container, it already exists !" 0 +
    [[ ${status} -ne 0 ]] && msg "Error: can't create or mounted AUFS" 1 +
    [[ -d ${CONTAINER_ROOT} ]] || msg "Error: path AUFS not found" 2 +
    msg "Info: create and mount AUFS to path: ${CONTAINER_ROOT}" 0
    [[ -d ${CHANGES_PATH} ]] && msg "Info: save changes AUFS to path: ${CHANGES_PATH}" 0
# Add sources as aufs layers
    for i in ${LAYERS} ;do
        add_layer "${NAME}" "$i" || msg "Error: can't insert layer \"$i\" to aufs container ${NAME}" 4 +
    done
}
prepare_service() {
    # Подготовка systemd
    [[ -e /var/lib/machines/${NAME} ]] && msg "Warning: container '/var/lib/machines/${NAME}' already exist." 0 +
    # Copy to main system
    [[ -L /var/lib/machines/${NAME} ]] || ln -s ${CONTAINER_ROOT} /var/lib/machines/${NAME}
    mkdir -p /etc/systemd/system/systemd-nspawn@${NAME}.service.d
    [[ -f ${PATH_CONF}/service-override.conf ]] \
        && cp -u ${PATH_CONF}/service-override.conf /etc/systemd/system/systemd-nspawn@${NAME}.service.d
    # Set env path container source path
    echo -e "[Service]\nEnvironment=UBCONTAINER_SRC_PATH=${UBCONTAINER_SRC_PATH}" > /etc/systemd/system/systemd-nspawn@${NAME}.service.d/service-env.conf
    [[ -n ${BIND} ]] && EXECSTARTPRE="--bind ${BIND}"
    [[ -n ${PREPARE} ]] && EXECSTARTPRE=" ${EXECSTARTPRE} --prepare"
    [[ -n ${CHANGES} ]] && EXECSTARTPRE=" ${EXECSTARTPRE} --changes ${CHANGES}"
    [[ -n ${MASK} ]] && EXECSTARTPRE=" ${EXECSTARTPRE} --mask ${MASK}"
    [[ -n ${MLIST} ]] && EXECSTARTPRE=" ${EXECSTARTPRE} --mlist ${MLIST}"
    [[ -n ${FLIST} ]] && EXECSTARTPRE=" ${EXECSTARTPRE} --flist ${FLIST}"
    [[ -n ${PLIST} ]] && EXECSTARTPRE=" ${EXECSTARTPRE} --plist ${PLIST}"
#> Как вариант - вставить только подготовленные модули, когда restart .service при стопе будут делаться изменеия сохранений, но при старте не учитываться
#>	[[ ${LAYERS} ]] && EXECSTARTPRE=" ${EXECSTARTPRE} --mlist $(echo ${LAYERS} | tr ' ' ',')"
    [[ ${SCRIPT} ]] && EXECSTARTPRE=" ${EXECSTARTPRE} --script ${SCRIPT}"
    [[ ${COMMAND} ]] && EXECSTARTPRE=" ${EXECSTARTPRE} --command ${COMMAND}"
    echo -e "[Service]\nExecStartPre=/usr/bin/${NAMESCRIPT} --build --name ${NAME} ${EXECSTARTPRE}" > /etc/systemd/system/systemd-nspawn@${NAME}.service.d/service-startpre.conf
    if [[ -n ${DESTROY} ]]; then 
        if [[ -n ${SAVE} ]]; then
	    [[ -n ${COMPRESSION_FAST} ]] && EXECSTOPPOST="--fast"
	    [[ -n ${COMPRESSION} ]] && EXECSTOPPOST="--compression ${COMPRESSION}"
	    [[ -n ${NOTRIM} ]] || EXECSTOPPOST=" ${EXECSTOPPOST} --notrim"
	    [[ -n ${WH_ALLOW} ]] && EXECSTOPPOST=" ${EXECSTOPPOST} --wh" 
	    [[ -n ${CHANGES} ]] && EXECSTOPPOST=" ${EXECSTOPPOST} --changes ${CHANGES}"
	    echo -e "[Service]\nExecStopPost=/usr/bin/${NAMESCRIPT} --destroy --name ${NAME} --save ${SAVE} ${EXECSTOPPOST}" > /etc/systemd/system/systemd-nspawn@${NAME}.service.d/service-stoppost.conf
	else
	    [[ ${CHANGES} ]] && EXECSTOPPOST="--changes ${CHANGES}"
		echo -e "[Service]\nExecStopPost=/usr/bin/${NAMESCRIPT} --destroy --name ${NAME} ${EXECSTOPPOST}" > /etc/systemd/system/systemd-nspawn@${NAME}.service.d/service-stoppost.conf
	fi
    fi
    mkdir -p /etc/systemd/nspawn
    [[ -f ${PATH_CONF}/container.nspawn ]] \
        && cp -u ${PATH_CONF}/container.nspawn /etc/systemd/nspawn/${NAME}.nspawn
    # Настройки сети
    ls ${PATH_CONF}/*.network &>/dev/null \
        && mkdir -p ${CONTAINER_ROOT}/etc/systemd/network \
        && cp -af ${PATH_CONF}/*.network ${CONTAINER_ROOT}/etc/systemd/network/
    systemctl daemon-reload
}
prepare_info() {
# Info about source chroot
    mkdir -p ${CONTAINER_ROOT}/var/lib/${NAMESCRIPT}/${NAME}
    date > ${CONTAINER_ROOT}/var/lib/${NAMESCRIPT}/${NAME}/makedate
    chmod 600 ${CONTAINER_ROOT}/var/lib/${NAMESCRIPT}/${NAME}/makedate
    echo $@ > ${CONTAINER_ROOT}/var/lib/${NAMESCRIPT}/${NAME}/cmdline
    chmod 600 ${CONTAINER_ROOT}/var/lib/${NAMESCRIPT}/${NAME}/cmdline
}
option_script() {
    cp -fu ${SCRIPT} ${CONTAINER_ROOT}/var/lib/${NAMESCRIPT}/${NAME}/
    chmod 700 ${CONTAINER_ROOT}/var/lib/${NAMESCRIPT}/${NAME}/$(basename $SCRIPT) 
# Copy enabled services rc-local
#   echo ${ubcontainer_rc_local} >> $CONTAINER_ROOT/usr/lib/systemd/system/ubcontainer-rc-local.service
    ubcontainer_rc_local ${CONTAINER_ROOT}/usr/lib/systemd/system/ubcontainer-rc-local.service
    ln -sf /usr/lib/systemd/system/ubcontainer-rc-local.service ${CONTAINER_ROOT}/usr/lib/systemd/system/multi-user.target.wants/ubcontainer-rc-local.service 
}


##################################
###		MAIN		##
##################################
    [[ -f /usr/bin/ubm ]] && . /usr/bin/ubm || . $(command -v ubm) || exit 1
    NAMESCRIPT=$(basename $0)
    arguments $@
    allow_only_root

    # Если во входящем окружении присутствует ${UBCONTAINER_SRC_PATH}, то не определять ${UBCONTAINER_SRC_PATH}. 
    # Метка, что запущен скрипт из сервиса текущего контейнера.
    # Сделано для входящей переменной из сервиса контейнера, определить путь исходников контейнера где для сохранений лежит ./modules/{rootcopy|changes|*.ubm} 
    [[ -z ${UBCONTAINER_SRC_PATH} && -n ${NAME} && -f /etc/systemd/system/systemd-nspawn@${NAME}.service.d/service-env.conf ]] \
	&& UBCONTAINER_SRC_PATH=$(cat /etc/systemd/system/systemd-nspawn@${NAME}.service.d/service-env.conf | grep UBCONTAINER_SRC_PATH | cut -d"=" -f3)
    if [[ -z ${UBCONTAINER_SRC_PATH} ]]; then
	UBCONTAINER_SRC_PATH=$(ps -o cmd= $PPID | cut -d" " -f2)
	[[ ${UBCONTAINER_SRC_PATH:0:1} == "." || ${UBCONTAINER_SRC_PATH:0:1} == "/" ]] && UBCONTAINER_SRC_PATH=$(cd ${UBCONTAINER_SRC_PATH%/*}; pwd -P) || UBCONTAINER_SRC_PATH=$(pwd -P)
    fi
    # Ищем каталог настроект контейнера
    [[ -d ${UBCONTAINER_SRC_PATH}/conf.d ]] && PATH_CONF="${UBCONTAINER_SRC_PATH}/conf.d" || PATH_CONF="."
    # Если существует скрипт 'container.script', то запускаем
    [[ -x ${PATH_CONF}/container.script ]] && SCRIPT="${PATH_CONF}/container.script"
    # Опция иземенения контейнера в папку
    [[ ${CHANGES} == "container" ]] && CHANGES="${UBCONTAINER_SRC_PATH}/changes"
    [[ -n ${CHANGES} ]] && CHANGES_PATH=$(realpath ${CHANGES}) && mkdir -p ${CHANGES_PATH}
# Generate Name from random 4 dig
    [[ ${NAME} == "random" ]] && NAME="${RANDOM:0:4}"
# Generate Name from current dir
#    [[ ${NAME} == "currentdir" ]] && NAME=$(cd ${UBCONTAINER_SRC_PATH%/*}; basename $(pwd -P))
    [[ ${NAME} == "currentdir" ]] && NAME=$(basename ${UBCONTAINER_SRC_PATH})
    NAME=${NAME%.$EXT}
    msg "Info: name container '${NAME}'" 0
##################
## 	BUILD	##
##################
    if [[ -n ${BUILD} ]]; then
	msg "Info: SCRIPT container '${SCRIPT}'" 0
	msg "Info: COMMAND container '${COMMAND}'" 0
	[[ -d ${SYSMNT}/aufs-${NAME} ]] && msg "Warning: container '${SYSMNT}/aufs-${NAME}' already exist." 0 +
	msg "Info: type container \"${TYPE}\"" 0
	LAYERS=
	build_container
	prepare_service
	prepare_info $@
	# Option enable --prepare
	[[ -n ${PREPARE} ]] && option_prepare
	# Option script
	[[ -f "${SCRIPT}" ]] && option_script
	# Option enable --bind mount
        [[ -n ${BIND} ]] && option_bind "mount"
##
## Проверить
##	auth_file=/tmp/${container_name}_xauth
##	xauth nextract - "$DISPLAY" | sed -e 's/^..../ffff/' | xauth -f "$auth_file" nmerge -
## 	systemd-nspawn --directory=$container_name --bind=/tmp/.X11-unix --bind="$auth_file" --set-env=DISPLAY="$DISPLAY" --set-env=XAUTHORITY="$auth_file"
## Проверить
## DBus Tray
##	if [[ -n $DBUS_SESSION_BUS_ADDRESS ]]; then # remove prefix
##          host_bus=${DBUS_SESSION_BUS_ADDRESS#unix:path=};
##	else # default guess
##	    host_bus=/run/user/$UID/bus;
##	fi
##	container_bus=/run/user/host/bus
##	sudo systemd-nspawn --directory=$container_name --bind-ro=$host_bus:$container_bus --set-env=DBUS_SESSION_BUS_ADDRESS=unix:path=$container_bus
## Проверить
## PulseAudio
##	if [[ -n $PULSE_SERVER ]]; then # remove prefix
##	    host_pulse=${PULSE_SERVER#unix:};
##	else # default guess
##	    host_pulse=/run/user/$UID/pulse;
##	fi
##	container_pulse=/run/user/host/pulse/
##	systemd-nspawn --direcoty=$container_name --bind-ro=$host_pulse:$container_pulse --setenv=PULSE_SERVER=unix:$container_pulse/native
##
##	fc-cache --force
##	gtk-update-icon-cache --force

	# Generate machine-id, nspawn do not works without machine-id
	[[ -f ${CONTAINER_ROOT}/etc/machine-id ]] || dd if=/dev/urandom count=1 bs=512 2>/dev/null | cat - /sys/class/net/*/address 2>/dev/null |  md5sum | awk '{ print $1}' > ${CONTAINER_ROOT}/etc/machine-id
	if [[ ${TYPE} == "chroot" ]] && [[ -n ${COMMAND} || -n ${SCRIPT} ]]; then
	    # Option enable --X
	    [[ -n ${XHOST} ]] &&  xhost +local: && XHOST_ACCESS="+"
	    if command -v arch-chroot &>/dev/null; then
		[[ -n ${SCRIPT} ]]  && arch-chroot ${CONTAINER_ROOT} env -i DISPLAY="$DISPLAY" PATH="$PATH" TERM="$TERM" LANG="$LANG" HOME=/root /var/lib/${NAMESCRIPT}/${NAME}/$(basename ${SCRIPT})
		[[ -n ${COMMAND} ]] && arch-chroot ${CONTAINER_ROOT} env -i DISPLAY="$DISPLAY" PATH="$PATH" TERM="$TERM" LANG="$LANG" HOME=/root ${COMMAND}
	    elif command -v chroot &>/dev/null; then
		mkdir -p ${CONTAINER_ROOT}/{dev,run,proc,sys,tmp,sys/firmware/efi/efivars}
		[[ -d /dev ]] && mount --rbind /dev ${CONTAINER_ROOT}/dev/
		[[ -d /proc ]] && mount -t proc /proc ${CONTAINER_ROOT}/proc/
		[[ -d /sys ]] && mount -t sysfs /sys ${CONTAINER_ROOT}/sys/
		[[ -d /tmp ]] && mount -t tmp /tmp ${CONTAINER_ROOT}/tmp/
		[[ -d /sys/firmware/efi/efivars ]] && mount --rbind /sys/firmware/efi/efivars ${CONTAINER_ROOT}/sys/firmware/efi/efivars/
		# Optional RUN
		#[[ -d /run ]] && mount --rbind /run ${CONTAINER_ROOT}/run/
		[[ -n ${SCRIPT} ]] && chroot ${CONTAINER_ROOT} env DISPLAY="$DISPLAY" /var/lib/${NAMESCRIPT}/${NAME}/$(basename ${SCRIPT})
		[[ -n ${COMMAND} ]] && chroot ${CONTAINER_ROOT} env DISPLAY="$DISPLAY" ${COMMAND}
	    fi
	elif [[ ${TYPE} == "nspawn" ]] && [[ -n ${COMMAND} || -n ${SCRIPT} ]]; then
	    [[ -d /tmp/.X11-unix ]] && BIND_X11="--bind=/tmp/.X11-unix"
	    [[ ${SCRIPT} ]] && systemd-nspawn --quiet $BOOT --link-journal=try-guest --settings=override -D ${CONTAINER_ROOT} -M ${NAME}  --setenv=DISPLAY="$DISPLAY" --setenv=TERM="$TERM" --setenv=LANG="$LANG" ${BIND_X11} /var/lib/${NAMESCRIPT}/${NAME}/$(basename $SCRIPT)
	    [[ ${COMMAND} ]] && systemd-nspawn --quiet $BOOT --link-journal=try-guest --settings=override -D ${CONTAINER_ROOT} -M ${NAME} --setenv=DISPLAY="$DISPLAY" --setenv=TERM="$TERM" --setenv=LANG="$LANG" ${BIND_X11} ${COMMAND}
#--quiet --keep-unit --boot --link-journal=try-guest --network-veth -U --settings=override
 #systemd-run --service-type=notify systemd-nspawn 
	elif [[ "$TYPE" == "nspawn-service" ]]; then
	    [[ "$SCRIPT" ]] && systemctl --quiet --now enable systemd-nspawn@${NAME}
	else 
	    unset SAVE
	    msg "Info:  --command or --script not set or --type not recognized" 0
	fi
    fi
##################
##	DESTROY	##
##################
    if [[ -n ${DESTROY} && ${TYPE} != "nspawn-service" ]]; then
	# Удалить все найденные контейнеры
	if [[ ${NAME} == "all" ]]; then
	    for CONTAINER in $(find /memory -maxdepth 1 -type d -regextype posix-egrep -iregex "/memory/aufs-.*"); do
		/usr/bin/bash -c "$0 --destroy --name ${CONTAINER/\/memory\/aufs-/}"
	    done
	    exit 0
	fi
	[[ -f ${SYSMNT}/aufs-${NAME}.lock ]] || msg "Error: destroyable container ${NAME} not found!" 7 +
	[[ -n ${XHOST_ACCESS} ]] && xhost -local: 
	#systemd-run --service-type=notify 
	systemctl --quiet is-enabled systemd-nspawn@${NAME} && systemctl --quiet --wait disable systemd-nspawn@${NAME}
#	if machinectl --no-pager --no-legend --no-ask-password list | cut -d" " -f1 | grep -e "^${NAME}$" &>/dev/null; then
	if machinectl status ${NAME} &>/dev/null; then
	# Останавливая не запускать второй экземпляр теекущего скрипта из сервиса, если работаем через утилиту
	    rm -f /etc/systemd/system/systemd-nspawn@${NAME}.service.d/service-stoppost.conf
	    systemctl daemon-reload
	    systemd-run --quiet --wait --machine=${NAME} poweroff 2>/dev/null && msg "Info: nspawn container ${NAME} stoped." 0 || msg "Error: can't stoped container ${NAME}" 8 +
	else
	    msg "Info: container ${NAME} not found in nspawn running list." 0
	fi
	umount_all_chroot ${NAME}
	CONTAINER_CHANGES="${SYSMNT}/changes-${NAME}"
	if [[ -d ${SYSMNT}/aufs-${NAME} && -d ${CONTAINER_CHANGES} ]]; then
	    # Save changes rootcopy or build module
	    if [[ -n ${SAVE} ]]; then
		rm -rdf ${CONTAINER_CHANGES}/{dev,proc,sys,tmp} 2>/dev/null
	        # Delete empty dir
	        rm -df "${CONTAINER_CHANGES}/lost+found" "${CONTAINER_CHANGES}/var/cache" "${CONTAINER_CHANGES}/var/lib" "${CONTAINER_CHANGES}/var" "${CONTAINER_CHANGES}/etc" 2>/dev/null
	        [[ -n ${NOTRIM} ]] || trim "${CONTAINER_CHANGES}"
		ROOTCOPY_PATH="${UBCONTAINER_SRC_PATH}/rootcopy"
		CHANGES_UBM="${UBCONTAINER_SRC_PATH}/modules/change-$(date '+%Y-%m-%d-%H:%M:%S').${EXT}"
		if [[ ${SAVE} == "module" || ${SAVE##*.} == "${EXT}" ]]; then
		    [[ ${SAVE} == "module" ]] || CHANGES_UBM="$(realpath ${SAVE})"
		    mkdir -p ${CHANGES_UBM%/*}
		    if [[ ${COMPRESSION} == "xz" ]]; then
			uname -m | grep -q -e "86" -e "32" -e "64" && COMPRESSION="${COMPRESSION} -Xbcj x86" || COMPRESSION="${COMPRESSION} -Xbcj x86,arm"
		    fi
		    # MKSQUASHFS_OPT="${MKSQUASHFS_OPT}"
		    eval mksquashfs "${CONTAINER_CHANGES}" "${CHANGES_UBM}" -comp ${COMPRESSION} -b ${BLOCKSIZE} -noappend -wildcards -e '.wh..wh.*' ${ARG_WH}
		    [[ -f ${CHANGES_UBM} ]] && rm -rdf ${ROOTCOPY_PATH}/*
		    CHANGES_IT="$(readlink -e ${CHANGES_UBM})" 
		elif [[ ${SAVE} == "rootcopy" || ${SAVE##*.} != "${EXT}" ]]; then 
		    [[ ${SAVE} == "rootcopy" ]] || ROOTCOPY_PATH="${SAVE}"
		    mkdir -p ${ROOTCOPY_PATH}
		    [[ -n ${WH_ALLOW} ]] || WH_EXCLUDE="--exclude=.wh.*"
		    rsync -aq --delete  --exclude=/.wh..wh.* ${WH_EXCLUDE} "${CONTAINER_CHANGES}/" "${ROOTCOPY_PATH}/"
		    CHANGES_IT="$(readlink -e ${ROOTCOPY_PATH}/)"
		fi
	        [[ -d ${CHANGES_PATH} ]] && rm -rdf ${CHANGES_PATH}/* && msg "Info: delete changes AUFS container: ${NAME}" 0 
	    fi
	fi
	# Bind unmount
	[[ -n ${BIND} ]] && option_bind "umount"
	# Kill all process from mount point
	fuser -cuk ${SYSMNT}/aufs-${NAME} 2>/dev/null
	# Check busy AUFS
	msg "Info: find busy process on AUFS container name: ${NAME}" 0
	BUSY_AUFS=$([[ -d ${SYSMNT}/aufs-${NAME} ]] && lsof -w +D ${SYSMNT}/aufs-${NAME})
	if [[ -n ${BUSY_AUFS} ]]; then
	    echo "${BUSY_AUFS}"
	    msg "Error: busy AUFS, busy container: ${NAME}" 9
	fi
	# Delete AUFS
	delete_aufs ${NAME} && msg "Info: delete AUFS container: ${NAME}" 0 || msg "Error: delete AUFS container: ${NAME}" 10
	[[ -d ${CHANGES_PATH} ]] && find ${CHANGES_PATH}/ \( -iname ".wh.*" -o -iname "..." \) -delete && msg "Info: delete '.wh.*' and '...' in changes AUFS container: ${NAME}" 0 
#rm -rdf "${CHANGES_PATH}/wh.*" "${CHANGES_PATH}/..."  && msg "Info: delete changes AUFS container: ${NAME}" 0 
# Remove from main system
#        [[ -d /etc/systemd/system/systemd-nspawn@${NAME}.service.d ]] \
#	    && rm -rdf /etc/systemd/system/systemd-nspawn@${NAME}.service.d
#	[[ -f /etc/systemd/nspawn/${NAME}.nspawn ]] \
#	    && rm -rf /etc/systemd/nspawn/${NAME}.nspawn
	[[ /var/lib/machines/${NAME} ]] \
	    && rm -f /var/lib/machines/${NAME} 
# Имя модуля/rootcopy
	[[ ${CHANGES_IT} ]] && msg "Info: the container '${NAME}' saved the changes to:" 0 && echo ${CHANGES_IT}
    fi
