#!/bin/bash

function header()
{
#	echo
	echo ".----------------------------------------"
	echo "| $1"
	echo "'----------------------------------------------------------------------------------------------------"
#	echo
}

function systemd_services()
{
	systemctl list-unit-files --state=enabled --type=service --state=running \
	| awk '{print $1}' \
	| while read unit; do
		[ -z "$unit" ] && continue
		rootdir=$(systemctl cat "$unit" 2>/dev/null | grep '^ *RootDirectory=' 2>/dev/null | sed 's/^ *RootDirectory=//')
		[[ $rootdir == /chroot/* ]] && echo "$unit"
	done
}

function sysvinit()
{
	initscripts=`find /etc/init.d/ -type f |grep -ve '\/etc\/init\.d\/.*\..*'`

	for script in $initscripts; do
		if (grep -q -e "^CHRDIR=" $script); then
			echo "$script"
		fi
	done
}

function systemd_mounts()
{
	display=$1
	systemctl list-units --type=mount --all --no-legend --no-pager --plain \
	| awk '{print $1}' \
	| while IFS= read -r unit; do
		[ -z "$unit" ] && continue
		[ "$unit" == "-.mount" ] && continue
		uc=$(systemctl cat "$unit" 2>/dev/null)
		what=$(echo "$uc" | grep '^What=' 2>/dev/null | sed 's/^What=//')
		where=$(echo "$uc" | grep '^Where=' 2>/dev/null | sed 's/^Where=//')
		if [ "$display" == "unit" ]; then
			[[ $where == /chroot/* ]] && echo "$unit"
			[[ $what == /chroot/* ]] && echo "$unit"
		else
			[[ $where == /chroot/* ]] && echo "$where"
		fi
	done | \
	sort -k1 -r |uniq
}

function systemd_rootmounts()
{
	display=$1
	systemctl list-units --type=mount --all --no-legend --no-pager --plain \
	| awk '{print $1}' \
	| while IFS= read -r unit; do
		[ -z "$unit" ] && continue
		[ "$unit" == "-.mount" ] && continue
		uc=$(systemctl cat "$unit" 2>/dev/null)
		what=$(echo "$uc" | grep '^What=' 2>/dev/null | sed 's/^What=//')
		where=$(echo "$uc" | grep '^Where=' 2>/dev/null | sed 's/^Where=//')
		if [ "$display" == "unit" ]; then
			[[ $what == /chroot/* ]] && echo "$unit"
		else
			#[[ $where == /chroot/* ]] && echo "$where"
			[[ $what == /chroot/* ]] && echo "$where"
		fi
	done | \
	sort -k1 -r
}

function pslist_chr()
{
	PROCS=""
	JAILS=""
	PJAILS=""
	PJAILSt=""
	JAILLIST=""

	ALLPROCS=`ps aufx`

	ALLPS=`echo "$ALLPROCS" |awk '{ print $2 }'`

	for p in $ALLPS; do
		jail=`readlink /proc/$p/root`
		if [ "$jail" != "/" ]; then
			#echo -n '.' >&2
			PROCS="$PROCS $p"
			PJAILS[$p]=$jail
			PJAILSt[$p]='chr'
			JAILS="$jail\n$JAILS"
		else
			nsjailx=`cat /proc/$p/mountinfo |awk '{print $4 "||" $5}' | grep '||/$' |grep -v '^/||/$'`
			if [ "$nsjailx" != "" ]; then
				#echo -n ':' >&2
				nsjail=`echo "$nsjailx" |sed 's/||\///'`
				PROCS="$PROCS $p"
				PJAILS[$p]=$nsjail
				PJAILSt[$p]='cgrp'
				JAILS="$nsjail\n$JAILS"
			fi
		fi
	done
#	echo >&2

	JAILLIST=`echo -e $JAILS |sort |uniq |grep '^/chroot/'`

	for jail in $JAILLIST; do
		for PROC in $PROCS; do
		    #pjail=`readlink /proc/$PROC/root`
		    pjail=${PJAILS[$PROC]}
		    if [ "$pjail" == "$jail" ]; then
			echo "$ALLPROCS" | grep -e "^[^ ]*[ ]*$PROC" |awk '{ printf "'${jail}'" "\t" "'${PJAILSt[$PROC]}'" "\t" $2 "\t" $1 "\t" $3 "\t" $4 "\t"; for (i=11; i<=NF; ++i) printf $i " "; print ""}'
		    fi
		done
#		echo ""
	done
}

function check_processes()
{
	if (pslist_chr | grep '/chroot/'); then
		return 1
	fi
	return 0
}

function check_mounts()
{
	if (grep '/chroot/' /proc/self/mountinfo); then
		return 1
	fi
	return 0
}

function check_finished()
{
	TRIES=$1

	header "Checking processes and mounts"
	for i in $(seq 1 $TRIES); do
		echo "# Check #$i..."
		sleep $(( 2*i ))
		if (check_processes >/dev/null); then
			if (check_mounts >/dev/null); then
				header "FINISHED - All chroots stopped."
				exit 0
			fi
		fi
	done
	return 1
}

######################################################################################################


if ! [ "x$1" == "xSTOP" ]; then
	echo "This script stops all chroots."
	echo "Usage: $0 STOP"
	exit 0
fi

if [ -d /etc/daemon-watchdog ]; then
	header "Suspending daemon-watchdog"
	touch /etc/daemon-watchdog/disable
fi

header "STOP systemd chr.target:"

if (systemctl list-unit-files --type=target | grep -q "^chr.target"); then
	echo "Stop chr.target"
	systemctl stop chr.target
	check_finished 3
fi


header "STOP systemd services and mounts:"

allsrv=`systemd_services`
echo "$allsrv"
allmnt=`systemd_mounts unit`
echo "$allmnt"

allsrvlist=`echo $allsrv`
allmntlist=`echo $allmnt`
systemctl stop ${allsrvlist} ${allmntlist}

check_finished 4

header "STOP sysvinit scripts:"
for script in `sysvinit`; do
	echo "# $script stop"
	$script stop
done

header "WAITING for services to stop"

for i in 0 1 2 3 4; do
	sleep $(( 3*i ))
	if (check_processes >/dev/null); then
		break
	fi
	if [ $i -eq 4 ]; then
		echo "ERROR: Processes still running in chroot! Please fix."
		exit 9
	fi
done

header "UMOUNT mounts (from mount units), chroot:"

for mnt in `systemd_mounts`; do
	echo "# umount $mnt"
	umount $mnt
done

header "UMOUNT mounts (from mount units), root:"

for rmnt in `systemd_rootmounts`; do
	echo "# umount $rmnt"
	umount $rmnt
done

header "WAITING for mounts to disappear"

check_finished 3

echo "ERROR: Mounts still present in chroot! Please fix."

check_mounts

exit 9
