#!/bin/sh
# This script must be executed with parameter "--start" at the end of distro shutdown
# What it does is it executes as init (process 1) and unmounts all filesystems
# including union and the USB device (if any), so it can be cleanly removed
#
# Simply add the following as the last command executed by init on your distro
# instead of the actual poweroff or shutdown command:
#
#       exec /run/initramfs/lib/cleanup --start poweroff
#    or
#       exec /run/initramfs/lib/cleanup --start shutdown
#
#    on Slackware, add this to rc.0:
#       exec /run/initramfs/lib/cleanup --start /sbin/$command
#
# It may be needed to call this script also with --killall5 from your shutdown scripts
# instead of calling regular killall5, to prevent fuse filesystems from being killed
#
# Author: Tomas M <http://www.linux-live.org/>
#

if [ "$1" = "--killall5" ]; then
   # kill all unneeded processes, which have smaller ID then the ID of
   # current shell's parent process. We can't use killall5, as it would kill some
   # processes which may be currently needed, for example fuse filesystems (ntfs-3g).
   for pid in $(/run/initramfs/bin/ps | grep -v "PID" | grep -E -v "\[.*\]" | grep -E -v "mount|posixovl|fuse" | sed -r "s/^ +//" | cut -d " " -f 1); do
      if [ $pid -lt $PPID ]; then
         LIST="$LIST $pid"
      fi
   done

   kill -15 $LIST 2>/dev/null # SIGTERM
   sleep 2 # give processes some time to end properly
   kill -9 $LIST 2>/dev/null # SIGKILL
fi


if [ "$1" = "--start" ]; then
   # This is the part which is to be called from shutdown script.
   # We will assume init is running as process 1 and re-executes itself after 'telinit u'
   # So we're going to force init to stop and start this script instead as PID 1
   # If your init works differently, you may need to slightly modify few lines below
   # - without this, init would be blocking union and it couldn't be unmounted later.
   cd /run/initramfs
   cp "$0" sbin/init
   pivot_root . memory/union
   echo "$2 -f" > /lib/command
   chroot /memory/union /sbin/telinit u
fi


if [ "$1" = "--init" ]; then
   # now we're called from init to replace the process nr 1.
   # We know that init binary reexecutes itself with --init parameter
   # All other processes are already killed
   # so our goal now is just to unmount everything and reboot/shutdown

   # First, mount proc and sys again since it will be needed and it was already unmounted
   mount -t proc proc /proc >/dev/console 2>&1
   mount -t sysfs sysfs /sys >/dev/console 2>&1

   # if debug is requested, start commandline prompt here
   if grep -q debug /proc/cmdline; then
      echo "Starting shell for debug" >/dev/console
      setsid sh -c 'exec sh < /dev/tty1 >/dev/tty1 2>&1'
   fi

   # Update devs so we are aware of all active /dev/loop* files.
   # Detach loop devices which are no longer used
   mdev -s
   losetup | cut -d : -f 1 | xargs -n 1 losetup -d

   # next, unmount everything from union, backwards
   tac /proc/mounts | grep union | cut -d " " -f 2 | while read LINE; do
      umount $LINE >/dev/console 2>&1
      umount -l $LINE
   done

   # then free up loop mounts, backwards
   tac /proc/mounts | grep loop | cut -d " " -f 2 | while read LINE; do
      umount $LINE >/dev/console 2>&1 || \
      umount -l $LINE
   done

   # remember from which device we are started, do it now before we lose it
   DEVICE="$(cat /proc/mounts | grep /memory/data | grep /dev/ | cut -d " " -f 1)"

   # free up memory mounts, backwards
   tac /proc/mounts | grep memory | cut -d " " -f 2 | while read LINE; do
      umount $LINE >/dev/console 2>&1
      if [ $? -ne 0 ]; then
         mount -o remount,ro $LINE >/dev/console 2>&1
         umount -l $LINE
      fi
   done

   # eject cdrom device if we were running from it
   for i in $(cat /proc/sys/dev/cdrom/info | grep name); do
      if [ "$DEVICE" = "/dev/$i" ]; then
         echo "Attemptiong to eject /dev/$i..." >/dev/console
         eject /dev/$i
         echo "CD/DVD tray will close in 6 seconds..." >/dev/console
         sleep 6
         eject -t /dev/$i
      fi
   done

   # and finally, last chance to run some commands by hand
   if grep -q debug /proc/cmdline; then
      echo "Starting shell for debug" >/dev/console
      setsid sh -c 'exec sh < /dev/tty1 >/dev/tty1 2>&1'
   fi

   cat /lib/command >/dev/console
   $(cat /lib/command 2>/dev/null)
   reboot -f
fi
