#!/bin/sh
#UBM module extractor
#VERSION 4.4

if [ -f $(dirname $0)/ubm ] ;  then
    . $(dirname $0)/ubm
else
    . $(which ubm) || exit 13
fi

HLP(){
echo "\
$(basename $0) - Распаковщик для модулей ubm
Использование:
    $(basename $0) file.$EXT - если модуль составной - разобрать на составляющие модули в папку ./file
                          на один уровень вложенности
    $(basename $0) file.$EXT --noubm  - разобрать составной модуль на составляющие на всю глубину вложенности,
                                   результат не паковать.
    $(basename $0) file.$EXT - если модуль простой - распаковать
    $(basename $0) file.$EXT pack1 pack2 - извлечь из file.$EXT только модули pack1 и pack2,
                                      имена в формате ubminfo module.$EXT
    
Параметры (ключи):
	-i / --install   распаковать в систему т.е. \"установить\"
	-o / --out-dir path/dir - создать каталог dir и распаковывать в него
	-d / --noubm - разобрать на каталоги вместо модулей
	-no-progress - не показывать строку прогресса.
	-f  / --fast - быстрая компрессия (размер .ubm больше, но создается быстрее).
	--mksqfs - параметры для mksquashfs. Внимание, параметр должен быть последним.
" >&2 ;exit 1
}

extract_simple() {
#unsquashfs non component-ubm or simple squashfs
    #[ "$sourcelist" ] && exitmsg "File '${ubm}' is not component-ubm.  Can't extract packages: $sourcelist" 1
    if [ $install ] ; then
		dir="/" && mkdir -p ${UBMDIR}/install/
    else
		[ $dir ] || dir="./"
		dir=$dir/$(basename $ubm |sed "s/\.${EXT}$//") && mkdir -p $dir
    fi
    eval unsquashfs -f -dest "${dir}" "${ubm}" $noprogress $useproc "$devnull"
    exitmsg "Unsquashfs error" $?
    if [ "$install" ] ;  then
		UBMINFO=$(ubminfo "$ubm")
		if [ "$UBMINFO" ] ; then
			mv ${UBMDIR}/mount/"$UBMINFO" ${UBMDIR}/install/
		else
			mkdir -p ${UBMDIR}/install/$(basename "${ubm%.$EXT}")
			unsquashfs -l "$ubm" |sed 's/squashfs-root//' | grep "^/.*" > ${UBMDIR}/install/$(basename "${UBM%.$EXT}")/ubm.files
			[ $? -ne 0 ] && exitmsg "$i install error" $?
			return 0
		fi
	else
		rm -R ${dir}${UBMDIR} 2>/dev/null
		return 0 # need zero exit code
	fi
 }

extract_container() {
#extract packages from container
dir=$(basename $ubm |sed "s/\.${EXT}$//")
mkdir "$dir"
[ "noubm" -a "$ADDINFO" ] && ubminfo $ubm > ${dir}/$(basename $dir).info
for m in $sourcelist ; do
    eval echo  "submodule: $m    -- processing..." $devnull
    m=$(echo $m |sed 's#/#/submod/mount/#g')
    n="$(make_aufs || exitmsg "make_aufs error" 2)"
	nn="$(echo "$n" | sed -n 's/^.*\([0-9]\)$/\1/p')"
	[ -d "$n" ] || exitmsg "error mounting aufs" 3
    bundle=$(add_layer "$nn" "$ubm" || exitmsg "can't insert layer to aufs $n" 5)
     
    cat "${n}${UBMDIR}/mount/${m}/ubm.files" | while read F; do
	touch "$n$F"
	if ! [ -e "$SYSMNT/changes$nn/$F" ] ; then
		CPWD=$(pwd)
		cd  "$bundle" >/dev/null
		cp -a --parents "$(echo "$F" |sed 's:^/::')" "${n}/"
		cd $CPWD  >/dev/null
	fi
	[ -e "$SYSMNT/changes$nn/$F" ] || echo "Warning. Cannot extract $F"
    done
  
    emp="$SYSMNT/aufs$nn/${UBMDIR}/mount/$m/ubm.dirs.empty"
    [ -f "$emp" ] && cat "$emp" | while read F; do
	F=$(echo $F |sed s':\$::')
    if [ -d "$F" ] ; then
	    touch "$SYSMNT/aufs$nn$F"
	else
	    echo "$F - is not directory"
	fi
    done
	cp -a $SYSMNT/aufs$nn${UBMDIR}/mount/${m}/unique/*  "${n}/" 2>/dev/null
          
    
	if [ "$noubm" ] ; then
		moddirname=$(basename $m)
		#submod names may be equal
		[ -d  "$dir/$moddirname" ] && moddirname=${moddirname}_$RANDOM
		mkdir -p "$dir/${moddirname}"
		cp -a "$SYSMNT/changes$nn"/* "$dir/${moddirname}/" &&
		rm -f $dir/${moddirname}/$UBMDIR/mount/{ubm.files,.dirs.empty}
		rmdir $dir/${moddirname}/$UBMDIR/mount $dir/${moddirname}/$UBMDIR 2>/dev/null
	elif [ "$install" ] ; then
	    mklist source_root="$SYSMNT/changes$nn" base_root="$SYSMNT/aufs$nn" pack_name="$(basename $m)"
		cp -a "$SYSMNT/changes$nn"/* /
		mv -f ${UBMDIR}/mount/$m ${UBMDIR}/install/
		eval echo  "package: $m  install complete" $devnull
    else
		touch "$SYSMNT/aufs$nn/${UBMDIR}"
		if [ -d "$SYSMNT/aufs$nn${UBMDIR}/mount/$m/submod/mount" ] ; then
			cp -fr "$SYSMNT/aufs$nn${UBMDIR}/mount/$m/submod/mount"  "$SYSMNT/changes$nn/${UBMDIR}/"
		else 
			# сохраняем спеки
			mkdir -p "$SYSMNT/changes$nn${UBMDIR}/mount/$(basename $m)"
			find "$SYSMNT/aufs$nn${UBMDIR}/mount/$m/" -type f | while read aaa ; do
			[ "$(basename $aaa)" = 'ubm.files' -o "$(basename $aaa)" = 'ubm.dirs.empty' ] && continue
			cp -f  "$aaa" "$SYSMNT/changes$nn/${UBMDIR}/mount/$(basename $m)/"
			done
		fi	
		#rm -rf $SYSMNT/changes$nn/${UBMDIR}
		modname="$dir/"$(basename $m)".$EXT"
		[ -f $modname ] && modname="$dir/"$(basename $m)_$RANDOM".$EXT"
		mkdir -p "$dir" && mksqmod "$SYSMNT/changes$nn" $modname
    fi
    delete_aufs $nn ; echo ''
done
}

installDir()  {
    sourcedir=$(echo $sourcelist |sed 's:^\ *::')
    eval echo "directory: $sourcedir installing..." $devnull
    mklist source_root="$sourcedir"   dest_root='/'
    cp -a "$sourcedir"/*   /
    mkdir -p ${UBMDIR}/install/
    mv -f ${UBMDIR}/mount/$(basename "${sourcedir}") ${UBMDIR}/install/
    exit
}

[ "$1" ] || HLP

#parsing for "--mksqfs" arg
argslist="$@"
if  echo $argslist |grep -q "\-*mksqfs .*" ; then
	compression="$(echo $@ |sed 's/^.*\-*mksqfs//')"
	argslist="$(echo $@ |sed 's/\-*mksqfs.*$//')"
fi

#get opts
sourcelist=""
for arg in $argslist
do
  case "${arg}" in
    "-o" | "--out-dir") onuserout="on";;
    "-d" | "--noubm") noubm=yes ;;
    "-i" | "--install") install=yes ;;
    "-h" | "--help")  HLP ;;
    "-q" | "--quiet" ) devnull='>/dev/null' ;;
    "-no-progress" | "--no-progress") noprogress="-no-progress";;
    "-processors"  | "--processors" ) numproc="on";;
    "-f" | "--fast"  ) [ "$compression_fast" ] && compression="$compression_fast" || compression="gzip";;
    "-"*[A-Za-z]*) echo "$(basename "$0"): invalid option: '$(echo ${arg})'" >&2; HLP; exit 1;;
    *) if [ "${onuserout}" = "on" ]; then dir="${arg}"
        elif [ "${numproc}" = "on" ]; then useproc="-processors ${arg}"
        else sourcelist="${sourcelist} ${arg}"; fi
        onuserout="off";  numproc="off";;
  esac
done

allow_only_root

#check kernel
check_ubm >/dev/null 2>&1
exitmsg "Kernel is not support squashfs/aufs!" $?
wh="-regex -e ".wh..wh.""

# find module in arg list

for item in $sourcelist ; do
	if [ "$(fs_type $item)" = "squashfs" ] ; then
		ubm=$item
		break
	fi
done
sourcelist=$(echo "$sourcelist" |sed 's#'"$ubm"'##')

[ ! $ubm ] &&  [ $i ]  && [ -d $sourcelist ] && installDir
[ $ubm ] || exitmsg "There is no source ubm module" 2

#удаляем $sourcelist если  он существует, но  состоит из одних  пробелов, такое может получиться  после разбора параметров.
echo "$sourcelist"  |grep  -q "[[:alnum:]]" || unset sourcelist
ubmInfo=$(ubminfo $ubm)
if ! [ "$sourcelist" ] ; then
	if  [ $noubm ] ; then
		echo "$ubmInfo" |grep -q '/' &&  ADDINFO='yes'
		for a in $ubmInfo ; do
			echo "$ubmInfo" | grep ^${a}/  || sourcelist="$sourcelist $a"
		done
    else
		for a in $ubmInfo ; do
			echo $a |grep -qv "/"  && sourcelist="$sourcelist $a"
		done
	fi
else
	checked=""
	for m in $ubmInfo ;do
		echo " $sourcelist " |grep  -qF " $m " && checked="$checked $m"
	done
	sourcelist="$checked"
fi

if [ "$(unsquashfs -l ${ubm} |grep ${UBMDIR}/mount | grep -E '.files$' |wc -l)" -lt 2 ];then
		extract_simple
else
		extract_container
fi
