#!/bin/bash
# barium helper scripts
# author: rosalinux.ru: betcher_

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

filter="$SYSMNT /tmp /var/tmp /var/log /var/spool /var/cache /run /root /boot /proc /sys /root /home"
changes=$(ls_union |head -n1)

mk_point () {
	echo "Create control point. Please wait..."
	[ "$ID" ] || ID=$(date +%H%M%S)
	dir=/tmp/barium_changes/$ID

	mkdir -p $dir
	mkdir -p $dir/ctlpoint  
	: > $dir/ctlpoint.list
	: > $dir/ctlpoint.noreg

	for file in $(find $changes/) ; do 
		if [ -f $file -o -d $file -o -L $file ]; then 
			echo $file >> $dir/ctlpoint.list
		else
			echo $file >> $dir/ctlpoint.noreg
		fi
	done
	for file in $(cat  $dir/ctlpoint.list) ; do
		if [ -d "$file" ] ; then
			mkdir -p $dir/ctlpoint/$(echo  $file |sed "s:$changes::")
		else
			mkdir -p $dir/ctlpoint/$(dirname $file |sed "s:$changes::")
			if [ -f "$file" ] ; then 
				md5sum $file |cut -f1 -d ' ' > $dir/ctlpoint/$(echo $file |sed "s:$changes::")
			else
				cp -a $file $dir/ctlpoint/$(echo $file |sed "s:$changes::")
			fi
		fi
	done
	echo "ID: $ID"
}

get_new () {
	echo "Processing directory \"$dir/new\""
	mkdir -p $dir/new
	for file in $(find $changes/) ; do 
		if [ -f $file -o -d $file -o -L $file ]; then 
			if ! grep -q $(echo $file |sed "s:^${changes}/:/:") $dir/ctlpoint.list; then
				for int in $filter ;do
					if echo $file |sed "s:^${changes}/:/:" |grep -Eq ^"$int" ; then
						echo $file >> $dir/filtered.list
						break 2
					fi
				done
				echo $file >> $dir/new.list
			fi
		else
			if ! grep -q $(echo $file |sed "s:^${changes}/:/:") $dir/ctlpoint.noreg ; then
				echo $file >> $dir/new.noreg
			fi
		fi
	done
	echo "Finished creating files list. Copying files"
	for file in $(cat  $dir/new.list) ; do
		mkdir -p $dir/new/$(dirname $file |sed "s:^${changes}::")
		cp -fax $file $dir/new/$(dirname $file |sed "s:^${changes}::")/
	done
}

get_removed () {
	echo "Processing \"removed\""
	: > $dir/removed.list
	for file in $(cat $dir/ctlpoint.list) ; do
		[ -e $file -o -L $file ] || echo $file >> $dir/removed.list
	done
}

get_changed () {
	echo "Processing directory \"$dir/changed\""
	mkdir -p $dir/changed
	for file in $(find $changes -cnewer $dir/ctlpoint.list ) ; do 
		if [ -f $file ]; then 
			if grep -q $(echo $file |sed "s:^${changes}/::") $dir/ctlpoint.list; then
				new_md5=$(md5sum $file |cut -f1 -d ' ')
				old_md5=$(cat $dir/ctlpoint/$(echo $file |sed "s:^${changes}/:/:"))
				[ "$new_md5" != "$old_md5" ] && echo $file >> $dir/changed.list
			fi
		fi
	done
	echo "Finished creating files list. Copying files"
	for file in $(cat  $dir/changed.list) ; do
		mkdir -p $dir/changed/$(dirname $file |sed "s:^${changes}::")
		cp -fax $file $dir/changed/$(dirname $file |sed "s:^${changes}::")/
	done
}

get_whiteouts() {
	echo "Processing \"whiteouts\""
	: > $dir/whiteouts.list
	if [ $(check_union) == 'ovl' ]; then
		find $changes -cnewer $dir/ctlpoint.list  -perm 0000 >> $dir/whiteouts.list
	elif [ $(check_union) == 'aufs' ] ; then
		find $changes -cnewer $dir/ctlpoint.list  -name '*.wh.*' >> $dir/whiteouts.list
	fi
}

HELP () {
cat <<EOF
$0 - Tool to calculate diff of current changes and control point created earlye   

Using:
$0                  create control point
$0 -d               calculate diff  of changes
$0 -d -m new -r     calculate diff, create module from new files, remove control point
 
Patameters:
  -h | --help               - this help
  -l | --ls | --list        - show list of control points 
  -i | --ID                 - id for control point
  -p | --control-point      - create control point
  -r | --remove             - remove control point 
  -d | --diff               - calculate diff
  -F | --filter             - set own filter instead internal
  -m | --mkmod (all)        - create module ID.xzm from changed and new files
  --mkmod new               - create module ID.xzm from new files
  --mkmod changed           - create module ID.xzm from changed files
EOF
exit
}

if [ ! "$1" ] ; then
	mkpoint='yes'
else
	while [ -n "$1" ] ; do
		case $1 in
			'-h' | '--help' ) HELP ;;
			'-l' | "--ls" | "--list" )  ls -1 /tmp/barium_changes/ 
										exit ;;
			'-R' | '--remove-all' ) rm -rf '/tmp/barium_changes' 
									exit ;;
			'-i' | '--ID' ) shift ; ID="$1" ;;
			'-p' | '--control-point' ) mkpoint='yes' ;;
			'-r' | '--remove' ) REMOVE='yes' ;;
			'-d' | '--diff' ) DIFF='yes' ;;
			'-F' | '--filter') shift ; filter="$1" ;;
			'-m' | '--mkmod') 	if [ "$2" ] && [ "${2:0:1}" != '-' ] ; then 
									MKMOD="$2"
									shift
								else
									MKMOD='all'
								fi ;;
			'-'*) 	echo "$(basename "$0"): invalid option ${1}"
				exit ${LINENO} ;;
			*) 	[ $ID ] || ID="$1";;
		esac
		shift
	done
fi

if [ "$mkpoint" == "yes" ] ; then
    mk_point
    exit $?
fi

if [ ! "$ID" ] ; then
	ID=$(ls -1 /tmp/barium_changes/)
	if [ $(echo "$ID" |wc -l) -gt 1 ] ; then
		echo "Please specify control point ID:"
		echo "$ID"
		exit ${LINENO}
	fi
fi

dir="/tmp/barium_changes/$ID"
if ! [ -d "/tmp/barium_changes/$ID" ] ; then
	echo -e "Unknown ID: $ID\nselect one from:"
	ls -1  /tmp/barium_changes
	exit ${LINENO}
fi

if [ "$DIFF" ] ; then
	: > $dir/new.list
	: > $dir/new.noreg
	: > $dir/changed.list
	: > $dir/filtered.list
	rm -rf "$dir/new"
	rm -rf "$dir/changed"
	get_new
	get_changed
	get_whiteouts
	get_removed
	echo "See: $dir"
fi

if [ "$MKMOD" ] ; then 
	if [ -d "${dir}/new" ] && [ -d "${dir}/changed" ] ; then
		if [ "$MKMOD" == 'new' ] ; then
			mksquashfs ${dir}/new "${ID}.$EXT" ${SQFSOPT}  -noappend 
		elif  [ "$MKMOD" == 'changed' ] ; then
			mksquashfs ${dir}/new "${ID}.$EXT" ${SQFSOPT}  -noappend
		elif  [ "$MKMOD" == 'all' ] ; then
			barium mkmod -o "${ID}.$EXT" ${dir}/new ${dir}/changed
			if [ -s "$dir/whiteouts.list" ] || [ -s "$dir/removed.list" ] ; then
				union=$(check_union)
				echo ==========================================================================
				echo "Warning!
One of source directories for module ${ID}.$EXT contains $union whiteouts, 
or some files from $changes have been removed by the current system changes.
Module: ${ID}.$EXT - may not work properly! !
You can try: 
	$0 --mkmod new
or / and 
	$0 --mkmod changed
because merged (new + changed) modules have no $union whiteouts."
				echo ==========================================================================
			fi
		else
			echo "Unknown value for --mkmod: $MKMOD"
			exit ${LINENO}
		fi
	else
		echo "Please calculate diff first"
	fi
	[ -f "${ID}.$EXT" ] && echo "$(realpath ${ID}.$EXT)"
fi

[ "$REMOVE" ] && rm -rf "$dir"
