#!/bin/sh
#PFS module creator 
#VERSION 4.4

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

D(){
    sourcelist="$(find "$1" -maxdepth 1 -mindepth 1 -type d |sort)"
    sourcelist=$(echo $sourcelist |sed 's/\ /#/g')
    [ "$sourcelist" ] || exitmsg "no directory in '$2'" 1
    ondir=
    [ "${userout}_" = "_" ] && [ ! "`echo "$arglist" |grep "\-o "`" ] && userout="./$(basename "$1").$EXT"
}
M(){
    sourcelist="$(find "$1" -maxdepth 1 -mindepth 1 -type f |egrep ".pfs$|.xzm$|.sfs$|.squashfs$|.$EXT$" |sort)"
    sourcelist=$(echo $sourcelist |sed 's/\ /#/g')
    [ "$sourcelist" ] || exitmsg "no modules in '$2'" 1
    onmod=
    [ "${userout}_" = "_" ] && [ ! "`echo "$arglist" |grep "\-o "`" ] && userout="./$(basename "$1").$EXT"
}

save_duplicates() {
	echo "save_duplicates enabled"
	for i in $bundles ; do
    #uniqfiles=$(diff -rq $i $n |grep -v "[[:alnum:]]: [[:alnum:]]" | sed "s#^.*$i##" |cut -d" " -f1)
    uniqfiles=$(LC_MESSAGES=en diff --no-dereference -rq  $i $n |grep "Files.*differ" | sed "s#^.*$i##" |cut -d" " -f1)
	if [[ -n "$uniqfiles" ]] ; then
		dpath=$(pwd)
		dest_dir="$(realpath "$n")${PFSDIR}/mount/$(basename "${i%.$EXT}")/"
		mkdir -p ${dest_dir}/unique
		for file in $uniqfiles ; do 
			cd ${i}
			cp -fr  --parents ".$file" ${dest_dir}/unique/ && echo "$file -- saved as unique for $(basename $i) submodule" 
		done
		cd $dpath
	fi
	done
}


#help
HLP(){
echo "Usage: $0 <list of sources> -o out.$EXT"
echo "Examples:"
echo "$0 ./dir 			-make dir.pfs from dir"
echo "$0 1.$EXT 2.$EXT -o 3.$EXT	-collect 1.$EXT and 2.$EXT to container 3.$EXT"
echo "$0 * -o ./big.$EXT		-collect all dirs and squashfs modules from current dir to big.$EXT" 
echo
echo "Параметры (ключи):"
echo "	-o / --out-file - указывает название выходного файла (если указать без расширения .$EXT на выходе будет каталог)."
echo "  -w - сохранить тени AUFS"
echo "  -l / --local - сборка на месте, без использования aufs."
echo "  -f / --fast - быстрая компрессия (размер .$EXT больше, но создается быстрее)."
echo "  --mkilst  add files list to simple (non container) module"
echo "  --save-duplicates  при сборке контейнеров сохранять одноименные файлы из разных источников если они отличаются, "
echo "                     при распаковке файлы будут возвращены на место"
echo "  --mksqfs / параметры для mksquashfs, компрессия размер блока и проч.(Внимание параметр должен быть последним)"
echo "  --spec ./file  -  Добавить файл с информацией. Только для атомарных модулей"
echo "  --deps aaa,bbb,ccc - Добавить список зависимостей.  Только для атомарных модулей"
echo ""
echo "Алиасы (сокращения):"
echo " -d | -D - Только каталоги"
echo "	$(basename $0) -d dir ---> $(basename $0)" '$(find dir -maxdepth 1 -mindepth 1 -type d ) -o dir.$EXT'
echo " -m | -M - Только модули"
echo "	$(basename $0) -m dir ---> $(basename $0)" '$(find dir -maxdepth 1 -mindepth 1 -type f ) -o dir.$EXT'
exit 1
}

check_kernel(){
checksfsxzb >/dev/null 2>&1
exitmsg "Kernel is not support squashfs/aufs. Work only 'mkpfs -l'" $?
}

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

#get opts
sourcelist=""
inplace=""
sep=''
for arg in "$@"; do
    [ "$arg" = '-mksqfs' -o "$arg" = '--mksqfs' ] && break
  case "$arg" in
    "-o" | "--out-file" ) onuserout="on";;
    "--mkinfo" ) mkinfo='yes';;
    "-d" | "-D" ) ondir="on";;
    "-m" | "-M" ) onmod="on";;
    "-h" | "--help")  HLP ;exit 1;;
    "-q" | "--quiet" ) devnull='>/dev/null' ;;
    "-t" | "--trim" ) TRIM="yes" ;;
    "-no-progress" | "--no-progress") noprogress="-no-progress";;
    "-processors" | "--processors" ) numproc="on";;
    "-save-duplicates" | "--save-duplicates" ) save_dups=on;; 
    "-w" | "--wh" ) WH="yes";;
    "-l" | "--local" ) inplace=yes ;;
    "--mklist" ) make_list=yes ;;
    "--spec" ) make_list=yes ; spec=yes;;
    "--depends" ) make_list=yes ; deps=yes ;; 
    "-f" | "--fast" | "-g" ) [ "$compression_fast" ] && compression="$compression_fast" || compression="gzip";;
    "-"*[A-Za-z]*) echo "$(basename "$0"): invalid option -- '$(echo ${arg} | tr -d '-')'" >&2; HLP; exit 1;;
    *) if [ "${usepkname}" = "on" ]; then packname="${arg}"
       elif [ "${ondir}" = "on" ]; then D "${arg}"
       elif [ "${onmod}" = "on" ]; then M "${arg}"
       elif [ "${onuserout}" = "on" ]; then userout="${arg}"
       elif [ "${spec}" = "yes" ]; then SPEC="${arg}"
       elif [ "${deps}" = "yes" ]; then DEPENDS="${arg}"
       elif [ "${numproc}" = "on" ]; then useproc="-processors ${arg}"
       else sourcelist="${sourcelist}${sep}"${arg}""
       sep='#' ;fi
       onuserout="off"; usepkname="off"; usindlib="off"; numproc="off"; deps="off"; spec="off" ;;
  esac
done

[ "$sourcelist" ] || HLP 
#echo "Sources: $sourcelist"
[ "$inplace" = "yes" -a  "$WH"  != "yes" ] && wh='-wildcards -e "... /.wh.*"'

allow_only_root

[ "$inplace" ] || check_kernel

if [ "${userout}_" = "_" ] ; then 
  first="$(basename "$(echo "$sourcelist" | awk -F# '{print $1}')")" 
  userout="$(echo ${first%.$EXT}).$EXT" 
fi

#1 dir, in place mode
if [ -d $sourcelist 2>/dev/null -a "$inplace" = "yes" ] ;then
	eval echo "==== In place mode ====" $devnull
    [ "$wh" ] ||  eval  echo "=== save aufs whiteout \(.wh*\) ===" $devnull
    [ ! "$(ls -a $sourcelist)" ] && exitmsg "directory '$sourcelist' empty" 1
	[ $make_list ] && mklist source_root=$sourcelist dest_root=$sourcelist pack_name=${userout%.$EXT} spec_file="$SPEC" depends="$DEPENDS" 
    [ $TRIM ] && trim $sourcelist
    if echo ${userout} | grep -q "^.*\.$EXT$" ; then 
		mksqmod $sourcelist "${userout}" && exit 0 
		exitmsg "mkpfs error" 2
	else
		echo "Please wait..."
		rmdir ${userout} 2>/dev/null
		[ -d "${userout}" ] && exitmsg "Output diectory already exist" 6
		mkdir -p "$(dirname ${userout})"
		cp -fax $sourcelist "${userout}" && exit 0
		exitmsg "copy files error" 2
	fi
exit
fi

#test sources, source must be dir or squashfs module
echo $sourcelist |sed 's/#/\n/g' |while read source ; do
	[ -d "$source" ] && continue
	[ "$(fs_type "$source")" = "squashfs" ] && continue
	exitmsg "Type of source \"$source\" is not correct" 2
done	

[ -d "$sourcelist" ] && { ls "$sourcelist" |grep -q . 2>/dev/null || exitmsg "\"`echo $sourcelist`\" is empty" 2 ; }
#make root aufs
n="$(mkaufs || exitmsg "mkaufs error" 2)"
nn="$(echo "$n" | sed -n 's/^.*\([0-9]\)$/\1/p')"
[ -d "$n" ] || exitmsg "error mounting aufs" 3

#add sources as aufs layers

echo $sourcelist |sed 's/#/\n/g' |while read i ; do
    eval addlayer "$nn" "$i" "$devnull" || exitmsg "can't insert layer to aufs $nn" 5
done 

if ! echo $sourcelist |grep '#' ;then
  # if source is only one - submodule name is $userout with no prefix (pfs,xzm,etc)
  pack_name=$(echo ${userout%.$EXT} |sed -e 's/_comma_/,/g' -e 's/_equal_/=/g' -e 's/_asterisk_/\*/g' -e 's/_hash_/\#/g' )
  [ $make_list ] && mklist source_root="$i" dest_root="$n" pack_name="$pack_name" spec_file="$SPEC" depends="$DEPENDS" 
else	
  bundles=$(find $(echo $n |sed 's#aufs#bundles#') -maxdepth 1 -mindepth 1 -type d )
  #mklist for modules, submodule name is basename source with no prefix
  for i in $bundles ;do
	  name="$(basename "${i%.$EXT}" |sed -e 's/_comma_/,/g' -e 's/_equal_/=/g' -e 's/_asterisk_/\*/g' -e 's/_hash_/\#/g')" 
	  mklist source_root="$i" dest_root="$n" pack_name="$name"
  done
  [ $save_dups ] && save_duplicates
fi

[ $TRIM ] && trim $n
if [ $WH ] ; then
	echo ".wh..*" > /tmp/mkpfs_excludes
	find $n |sed "s:$n/:/:" > /tmp/allfiles-wh
	mount -t aufs -o remount,shwh $n
	for line in $(find $n  |sed -re 's:/.wh.|/.wh..wh.:/:' -e "s:$n/:/:"  |sort |uniq -d) ; do
		grep $line /tmp/allfiles-wh |sed -re 's:^(.*/)(.*$):\1.wh.\*\2:' -e 's:^/::' >> /tmp/mkpfs_excludes
	done
	rm /tmp/allfiles-wh
fi

mkinfo() {
	local NAME PACKVER MODVER AUTHOR ALIAS
	info=$1/${PFSDIR}/INFO
	mkdir -p $(dirname $info)
	[ -f "$info" ] && source $info
	> "$info"
	for a in NAME PACKVER MODVER MODREV AUTHOR ALIAS; do
		eval echo -n \""Please enter $a (current: \$$a): "\"
		read newstr
		if ! [ -z "$newstr" ] ; then
			eval $a="$newstr"
		fi
		eval echo "$a=\$$a" >> $info
		unset newstr 
	done
}


if echo "${userout}" | grep -q "^.*\.$EXT$" ; then
	if [ $mkinfo ] ;then 
		mkinfo "$n"
	else
		rm -f $n/${PFSDIR}/INFO
	fi 
	mksqmod "${n}" "${userout}" noexit
else
	echo "Please wait..."
	rmdir ${userout} 2>/dev/null
	if [ -d "${userout}" ] ; then 
		delaufs "$nn" 
		exitmsg "Output diectory already exist" 6
	fi
	mkdir -p "$(dirname ${userout})"
	cp -fax "${n}" "${userout}"
fi
rm -rf $SYSMNT/lost_wh$N 2>/dev/null
exitmsg "mksqmod error" $?  noexit
delaufs "$nn"
exitmsg "delaufs error" $?
