#!/usr/bin/env bash
#
# Description: Load modules and directory to 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
 -u, --upper            Mount filesystem to upper layer AUFS
 -l, --lower            Mount filesystem to lower layer AUFS
 -n, --no-update        Don't update cache
     --ro, --read-only  Mount read-only
 -r, --toram            Copy module to RAM disk (tmpfs) before loading"
 -V                     Version script

OBJECTS LIST:
  module, directory, iso, img, squashfs, etc
  Use a [space] or [,] or [;] for the separator

=====================================================
Examples:
$(basename $0) module1.ubm,module2.ubm module3.ubm
$(basename $0) -n 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 ;;
	    -u | --upper)	mntmode="upper" ;;
	    -l | --lower)	mntmode="lower" ;;
	    -n | --no-update)	fupdate="no" ;;
	    -r | --toram)	toram="yes" ;;
	    -q | --quiet)     	QUIET=1 ;;
	    -V | --version)	echo "Version: ${VERSION_SCRIPT}"; exit 0 ;;
	    --ro | --read-only) romode="yes" ;;
	    --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[@]}"
    [[ -z ${mntmode} ]] && mntmode="upper"
    [[ -n "${sourcelist}" ]] || usage
}

toram() {
    mkdir -p ${copyramdir}
    df   ${copyramdir} |grep -Eq '^tmpfs|^/dev/zram'  || mount -t tmpfs tmpfs "${copyramdir}"
    freeram=$(checkramfreeb)
    filesize="$(du -k "${fsfile}" | cut -f 1)"
    minram="$(( ${filesize} + ${TMPFSLIMIT} ))"
    [ "${minram}" -gt "${freeram}" ] && exitmsg "ERROR: Not enough free RAM space" 3
    if [ -f "${copyramdir}/${fsname}" ] ;then
	ubmunload -r ${fsname}
	exitmsg "File already in ram and mounted" $?
    fi
#   echo "\"${fsname}\" copy to RAM..."
    cp -afL "${fsfile}" "${copyramdir}" || return 2
    echo  "${copyramdir}/$(basename ${fsfile})" | sed 's://:/:g'
}


##################################
###		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
    [ -z "${infile}" ] && continue
    if [ -f "${infile}" ]; then
	fsfile="$(realpath "${infile}")"
	[ $toram ] && fsfile=$(toram)
	devtype="file"
    elif [ -b "${infile}" ]; then
	fsfile="${infile}"
	devtype="dev"
    elif [ -d "${infile}" ]; then
	fsfile="$(realpath "${infile}")"
	devtype="dir"
    else
	exitmsg "WARNING: Object \"${infile}\" not found!"  2
    fi

    if [ "${devtype}" != "dir" ]; then
	fstype=$(fs_type "${fsfile}")
	[ "${fstype}" = "" ] && exitmsg "ERROR: Unknown file system -- \"$fsfile\"" 3
	[ check_ubm 2>/dev/null ] || exitmsg "ERROR: Kernel not support module squashfs/aufs!" 4
    else
	fsinfo="$(df -aT "${fsfile}" | tail -n 1 | tr -s ' ' '_' | cut -d'_' -f 2)"
	case "${fsinfo}" in
	    "ntfs"|"fat32"|"aufs")
		exitmsg "ERROR: \"$fsinfo\" -- isn't supported FS" 5
	    ;;
	esac
	fstype="${fsinfo}"
    fi
  
    fsname="$(basename "${fsfile}")"
    mountpoint="${prefixmp}${fsname}"
    [ -d "${mountpoint}" ] && rmdir "${mountpoint}" 2>/dev/null
    [ -d "${mountpoint}" ] && exitmsg "INFO: Object \"${fsfile}\" is mounted!" 6

    if [ "${devtype}:${fstype}" = "file:squashfs" ]; then
	sync
	freeloop=0
	looplist="$(losetup -a)"
	while true ; do
	    echo "${looplist}" | grep -q -F "/dev/loop${freeloop}" && freeloop="$(expr ${freeloop} + 1)" || break
	done
	if [ ! -b /dev/loop${freeloop} ]; then
	    mknod -m660 /dev/loop${freeloop} b 7 ${freeloop}
	    chown root:root /dev/loop${freeloop}
	    sync
	fi
	[ -b /dev/loop${freeloop} ] || exitmsg "ERROR: Free loop devices is not found!" 7
	losetup /dev/loop${freeloop} "${fsfile}"
	status=$?
    else
	status=0
    fi

    if [ ${status} -eq 0 ]; then
	mkdir -p "${mountpoint}"
	sync
	case "${devtype}" in
	    "file")
		if [ "${fstype}" = "squashfs" ]; then
            	    mount -t squashfs -o ro /dev/loop${freeloop} "${mountpoint}" >/dev/null #2>&1
                else
            	    [ "${romode}" ] && optmnt="loop,ro" || optmnt="loop"
            	    mount -t ${fstype} -o ${optmnt} "${fsfile}" "${mountpoint}" >/dev/null #2>&1
                fi
            ;;
	    "dev")
		[ "${romode}" ] && optmnt="ro" || optmnt="rw"
                mount -t ${fstype} -o ${optmnt} "${fsfile}" "${mountpoint}" >/dev/null
            ;;
	    #"dir")
#		mount -t ${fstype} --bind "${fsfile}" "${mountpoint}" >/dev/null
#	    ;;
	    "dir")
		mount --bind "${fsfile}" "${mountpoint}" >/dev/null
	    ;;
	esac
	status=$?
	if [ ${status} -eq 0 ]; then
	    sync
	    if [ "${mntmode}" = "upper" ]; then
		nlayer=1
		prefix=$(grep ' / aufs' /proc/mounts | cut -f2 -d= | tr ',' ' ' | cut -f1 -d' ')
		[ -w $(cat /sys/fs/aufs/si_${prefix}/br1 | head -n1 | sed 's/=.*//') ] && nlayer=2
		[ -w "${mountpoint}" ] && nlayer=1
		mount -o remount,add=${nlayer}:"${mountpoint}"=ro+wh / >/dev/null #2>&1
	    else
    		mount -o remount,append="${mountpoint}"=ro+wh / >/dev/null #2>&1
	    fi
	    status=$?
	    sync
    
	    if [ ${status} -eq 0 ]; then
		mount_ok="yes"
	    else
    		umount -d "${mountpoint}" >/dev/null
		rmdir "${mountpoint}" >/dev/null
		exitmsg "ERROR: AUFS error!" ${status}
	    fi
	else
	    losetup -d /dev/loop${freeloop}
	    rmdir "${mountpoint}" >/dev/null
	    exitmsg "ERROR: Unable to mount \"${fsfile}\" in \"${mountpoint}\"." ${status}
	fi
    else
	rmdir "${mountpoint}" 2>/dev/null
	exitmsg "ERROR: Mount error!" ${status}
    fi
    sync

#for script in $(find ${mountpoint}/var/lib/ubm/*/scripts -maxdepth 1 -type f -name "*.load*" -user root); do
#	$script "${mountpoint}" &
#done

#for script in $(find $(dirname $0) -maxdepth 1 -name "runubmload*" -user root) ; do
#	$script "${mountpoint}" &
#done

done

    [[ ${mount_ok} == "yes"  && "${fupdate}" != "no" ]] && ubm_update_caches "${sourcelist[@]}"
    sync
