#!/bin/sh
# rc.cleanup - modified for Fatdog 710 UML
# (C) James Budiono 2012, 2013, 2014
# License: GNU GPL Version 3 or later
#
# version 
# 1.0 - initial release
# 1.1 - heavy re-work
# 2.0 - heavy re-work, now using pivot_root
# 2.1 - modified for Fatdog 700 UML

### configuration parameters
SHUTDOWN_ROOT=/tmp/shutdown.root
KILL_DELAY=2 		# in seconds
OLDROOT=/oldroot
CLEANUP=cleanup
BOOTSTATE_PATH=/etc/BOOTSTATE
[ -e BOOTSTATE_PATH ] && . $BOOTSTATE_PATH 	# need BASELINE_MOUNT, MODULE_SFS_MOUNT, BASE_SFS_PATH

### static executables
BB=/bin/busybox
LVM=/sbin/lvm
CRYPTSETUP=/sbin/cryptsetup
MDADM=/sbin/mdadm

### utilities - kill processes. Will kill everything except ourself and init
# $1 kill flags, everything else - PIDs to kill
kill_processes() {
	killflags=$1
	shift
	for PID in $*; do 	
		case $PID in
			1|$$) ;; # echo dont kill init or own process 
			*) $BB kill $killflags $PID 2> /dev/null ;;
		esac
	done
}

### utilities - get list of all processes, except transport (ntfs-3g, nbd-client)
all_processes_except_transport() {
	$BB ps | $BB sed -e '/ntfs-3g/ d; /nbd-client/ d; /posixovl/ d; s/^ *//; s/ .*//'
}

### utilities - get list of all processes
all_processes() {
	$BB ls /proc
}

### utilities - remove and unmount branches from aufs
# need /sys and $OLDROOT
unstack_aufs() {
	# find all the branches of aufs	                   
	AUFS_ROOT_ID=$($BB awk -v oldroot=$OLDROOT '$2==oldroot && $3=="aufs" { match($4,/si=[0-9a-f]*/); print "si_" substr($4,RSTART+3,RLENGTH-3); exit }' /proc/mounts)
	BRANCHES=$($BB sed 's/=.*//' /sys/fs/aufs/$AUFS_ROOT_ID/br[0-9]*)
	echo -n $1

	# remove all branches from union and unmount them
	for b in $BRANCHES; do
		#echo mount -t aufs -o remount,del:$b aufs $OLDROOT
		echo -n " ${b#${OLDROOT}}"
		$BB mount -t aufs -o remount,del:$b aufs $OLDROOT
		$BB umount -d -r $b
	done
	echo
}

### utilities - mount /proc and /sys 
mount_proc_sys() {
	$BB mount -t proc proc /proc	# need proc to kill & busybox self-exec
	$BB mount -t sysfs sysfs /sys	# need sys to find the branches
}

########### main ############
### assume /proc and /sys still mounted
grep -q debuginitrd /proc/cmdline && set -x || exec 2> /dev/null
case "$1" in
	"") ### phase1 ###
	
		echo Stopping filesystems ...
		$BB swapoff -a
	
		# make private space for new root
		$BB rm -rf $SHUTDOWN_ROOT; $BB mkdir -p $SHUTDOWN_ROOT; 
		$BB mount -t tmpfs tmpfs $SHUTDOWN_ROOT; cd $SHUTDOWN_ROOT
		$BB mkdir -p etc bin sbin dev proc sys ${OLDROOT##*/}
		$BB cp /sbin/init bin/busybox # assuming that /sbin/init is really static busybox
		for p in ash sh mount; do $BB ln -s /bin/busybox bin/$p; done
		$BB ln -s /bin/busybox bin/sh
		$BB cp "$0" ${CLEANUP}
		
		# run this in the comfort of a static root
		$BB pivot_root $SHUTDOWN_ROOT $SHUTDOWN_ROOT/$OLDROOT
		$BB mount -o move $OLDROOT/dev /dev
		$BB mount -o move $OLDROOT/proc /proc
		$BB mount -o move $OLDROOT/sys /sys
		exec $BB ash $CLEANUP phase2
esac

########## phase2 #########

# restart - do it before aufs is unravelled
#echo Prepare for system-restart
#$BB ln -s /sbin/system-restart /init
#$BB cat /dev/loop0 > /${MODULE_SFS_MOUNT##*/}.sfs
#$BB cat /dev/loop1 > /${BASE_SFS_PATH##*/}

# sync and then kill all process except transport
$BB sync
kill_processes "" $(all_processes_except_transport)
$BB sleep $KILL_DELAY
$BB sync
kill_processes -9 $(all_processes_except_transport)

# unmount idle devices
exec 3> /dev/holdme	# keep /dev mounted r/w - needed by lvm/mdadm
$BB umount -a -r -d
			
# un-wind our aufs root
mount_proc_sys
# remount ro, disable xino, so r/w layer is unlocked and can be removed
$BB mount -t aufs -o ro,remount,noxino aufs $OLDROOT
unstack_aufs "#1: " # remove aufs branches
unstack_aufs "#2: " # do it twice to ensure pup_rw is unmounted
umount -a -r -d		# unmount savefile, savedevice and aufs

# close cryptsetup devices, if any
if [ "$DMCRYPT_DEVNAME" ]; then
	mount_proc_sys
	for p in $DMCRYPT_DEVNAME; do
		$CRYPTSETUP close ${p##*/}
	done
	umount -a -r -d # unmount stuff previously held by cryptsetup
fi

# remove all lvm devices - note lvm before mdadm
mount_proc_sys
$LVM vgchange -an --sysinit

# remove all mdadm devices
$MDADM --stop --scan

# final unmount attempt: remove everything
$BB umount -a -r -d
echo Filesystems stopped.

# That's it!
#$BB sh
