#!/usr/bin/env bash
#
# Description: Unload modules and directory from AUFS
#
# Author: Dmitry Razumov <asmeron@ublinux.com>
#

VERSION_SCRIPT=2.17

usage(){
cat <<EOF
Usage: $(basename $0) <keys> [OBJECTS LIST]

$(basename $0) keys:
 -h, --help      Help
 -k              Kill open branch files
 -n, --no-update Do not update caches
 -s, --saveram   Do not remove module from RAM after unmounting
 -v              Verbose output
 -V              Version script

OBJECTS LIST:
 module, directory, iso, img, squashfs, etc, layer number(see aufs-n)
 Use a [space] or [,] or [;] for the separator

=====================================================
Examples:
$(basename $0) module1.ubm,module2.ubm module3.ubm
$(basename $0) -nvk module1.ubm
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 ;;
	    -k)			KillBranchFiles=1 ;;
	    -n | --no-update) 	fupdate="no" ;;
	    -s | --saveram) 	saveram="yes" ;;
	    -v) 		verb="yes" ;;
	    -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
    sourcelist="${POSITIONAL_ARGS[@]}"
    [[ -n "${sourcelist}" ]] || usage
}
files_open_lsof() {
# Показать файлы которые загружены mmem из точки монтирования ветки aufs
    FilesOpen=$(lsof / 2>/dev/null | awk '{print $9}' | grep "/..*" | grep -Ev "/proc|/sys|/run|/tmp|/dev|/home" | sort -u)
    for ItemFile in ${FilesOpen}; do
	[[ -d ${ItemFile} ]] && continue
	[[ -f ${ItemFile} ]] || continue
	[[ -f "${mountpoint}${ItemFile}" ]] && BranchFiles+=" ${ItemFile}"
    done
    if [[ -n ${BranchFiles} ]]; then
	if [[ -n ${verb} ]]; then
	    echo "Files opened from \"${infile}\":"
	    for ItemBranchFiles in ${BranchFiles}; do
		echo -n ${ItemBranchFiles}
		[ -f "${changesDir}${ItemBranchFiles}" ] && echo " - changed" || echo ''
	    done
	fi
	# Убить все открытые файлы
	[[ -n ${KillBranchFiles} ]] && fuser -uk ${BranchFiles}
    fi
}
run_scriptlets() {
#	for script in $(find $(dirname $0) -maxdepth 1 -name "runubmunload*" -user root) ; do
#	    $script "${mountpoint}"  &
#	done
## Выполнить скрипт отключения модуля ubm_unload() из .install пакета pacman
##	for script in $(find ${mountpoint}/var/lib/ubfs/*/scripts -maxdepth 1 -type f -name "*.unload*" -user root 2>/dev/null); do
##   	    $script "${mountpoint}"
##  done
    true
}

##################################
###		MAIN		##
##################################
    [[ -f $(dirname $0)/ubm ]] && . $(dirname $0)/ubm || . $(which ubm) || exit 1
    NAMESCRIPT=$(basename $0)
    arguments $@
    allow_only_root

    for infile in $(echo ${sourcelist} | tr ',; ' '\n'); do
	prefix=$(grep ' / aufs' /proc/mounts | cut -f2 -d= | tr ',' ' ' | cut -f1 -d' ')
	if [[ -f ${infile} ]]; then
	# Найти по указанному имени файла бандл для отключения
	    findit=$(realpath ${infile})
	    mountpoint=$(ls /sys/fs/aufs/si_${prefix}/br{[0-9],[0-9][0-9],[0-9][0-9][0-9]} 2>/dev/null | xargs cat | sed "s/=.*//" | grep -E "/${findit##*/}$" )
	elif [[ ${infile} =~ ^[0-9]+$ ]]; then
	# Найти по указанному номеру бандл для отключения
	    mountpoint=$(ls /sys/fs/aufs/si_${prefix}/br${infile} 2>/dev/null | xargs cat | head -1 |sed "s/=.*//")
	else
	# Найти по указанному имени бандл для отключения, может быть каталог или любое имя найденное
	    mountpoint=$(ls /sys/fs/aufs/si_${prefix}/br{[0-9],[0-9][0-9],[0-9][0-9][0-9]} 2>/dev/null | xargs cat | sed "s/=.*//" | grep "/${infile##*/}$")
	fi
	if [[ -d ${mountpoint} ]]; then
	    files_open_lsof
	    sync; echo 3 >/proc/sys/vm/drop_caches; sync
	    mount -t aufs -o remount,del="${mountpoint}"/ aufs /  2>/dev/null
	    stataufs=$?
	    sync
	    losetup | grep -q "${copyramdir}${fsname}" && ramfree=yes
	    [ ${stataufs} -eq 0 ] && run_scriptlets
	    [ "${fupdate}" != "no" -a ${stataufs} -eq 0 ] && ubm_update_caches "${mountpoint}"
	    umount -d "${mountpoint}" 2>/dev/null
	    status=$?
	    [ ${status} -eq 0 ] && rmdir "${mountpoint}" 2>/dev/null && sync
	    [ ${status} -eq 0 ] && status=${stataufs}
	    [ ${status} -gt 0 ] && echo "ERROR: Unmount \"${mountpoint}\" failed!" >&2  && exit ${status}
	    if [[ ${ramfree} ]]; then
		[[ ${saveram} ]] || ubmramfree "${mountpoint}"
	    fi
	else
	    echo "WARNING: Object \"${infile}\" not mounted" >&2
	fi
    done
    sync 2>/dev/null; sync 2>/dev/null; sync 2>/dev/null
    echo 3 > /proc/sys/vm/drop_caches
    