#!/bin/bash

# description: mount and umount the filesystem

# Leave debugging off by default
DEBUG=""

wait_for_finish()
{
   test -n "${1}" && sleep ${1}
}


run_without_msg()
{
   if [ -z "${1}" ]; then
      echo -n "run_without_msg: missing command."
      echo -e ${RESULT_FAIL}
      return
   fi

   if [ -n "${DEBUG}" ]; then
      echo -e "< ${1} >\n" 
      eval ${1}
   else
      eval ${1} &> /dev/null      
   fi

   local exit_status=$?

   wait_for_finish "${2}"

   return ${exit_status}   
}


run_with_msg_and_exit_codes()
{
   # $1 : message
   # $2 : command
   # $3 : white space separated list of OK exit values
   # $4 : white space separated list of WARNING exit values
   # $5 : white separated list of FAILURE exit values

   if [ ! ${#} -eq 5 ]; then
      echo "run_with_special_exit_codes: wrong parameter count. 5 params expected"
      return 1
   fi    

   echo -n "${1}"

   if [ -n "${DEBUG}" ]; then
      echo -e "\n< run_with_special_exit_codes >"
      echo -e "\n< command : ${2} >"
      echo -e "\n< valid   : ${3} >"
      echo -e "\n< warn    : ${4} >"
      echo -e "\n< fail    : ${5} >"
      eval ${2}
   else
      eval ${2} &> /dev/null
   fi

   local exit_status=$?

   for i in "${3}"
   do
      if [ "${exit_status}" = "${i}" ]; then
         echo -e ${RESULT_OK}
         return ${exit_status}
      fi
   done 

   for i in "${4}"
   do
      if [ "${exit_status}" = "${i}" ]; then
         echo -e ${RESULT_WARN}
         return ${exit_status}
      fi
   done 

   for i in "${5}"
   do
      if [ "${exit_status}" = "${i}" ]; then
         echo -e ${RESULT_FAIL}
         return ${exit_status}
      fi
   done 

   warn_msg "result ${exit_status} did not match any supplied exit code value"
   return ${exit_status}
}


run_with_msg()
{
   # message == $1
   # cmd == $2

   if [ -z "${1}" ]; then 
      echo -n "run_cmd_with_msg: missing message."      
      echo -e ${RESULT_WARN}
      return
   fi

   if [ -z "${2}" ]; then
      echo -n "run_cmd_with_msg: missing command."      
      echo -e ${RESULT_WARN}
      return
   fi
  
   echo -n "${1}"  

   if [ -n "${DEBUG}" ]; then
       echo -n "< ${2} >"
       eval ${2}
   else
       eval ${2} &> /dev/null
   fi

   if [ $? -eq 0 ]; then
      wait_for_finish ${3}
      echo -e ${RESULT_OK}
      return 0 
   else
      wait_for_finish ${3}
      echo -e ${RESULT_FAIL}
      return 1
   fi
}


warn_msg()
{
   echo -ne "${1}"
   echo -e ${RESULT_WARN}
}

kernel_is_26()
{
  # don't forget /proc has to be mounted before we do this!
  uname -r | grep -q "^2\.6" && return 0

  return 1  
}


kernel_is_24()
{
  # don't forget /proc has to be mounted before we do this!
  uname -r | grep -q "^2\.4" && return 0

  return 1
}


# DONT FORGET TO SEE TO LVM FIXES!
start() 
{
   echo -e "Mounting filesystems:"

   run_with_msg " * Mounting proc : " "mount -n -t proc proc /proc"

   run_with_msg " * Remounting root read-only : " "mount -n -o remount,ro /"

   DEVNODES=`grep -o "dev=.*" /proc/cmdline | cut -d" " -f1 | sed -e "s/dev=//g"`
  
   case ${DEVNODES} in
      static|devfs)
         ;;
      udev)
         if kernel_is_24 ; then # *sigh*
            warn_message "No udev for 2.4 kernels. Kernel commandline parameter ignored."
            DEVNODES=""
         fi
         ;;
      ?*)
         warn_msg "Wrong device nodes parameter \"${DEVNODES}\" on kernel line. Valid are: devfs, udev, static\nFalling back to default behaviour"  
         DEVNODES=""
         ;;   
   esac

   # default bahaviour if there is no previous device nodes handling user choice
   if [ -z "$DEVNODES" ]; then
      if kernel_is_26 && [ -x "/sbin/udevstart" ] ; then
         DEVNODES="udev"
	 if [ ! -z "${DEBUG}" ] ; then
	   echo -e "\n< Found udev >"
	 fi
      elif [ -x "/sbin/devfsd" ] ; then
         DEVNODES="devfs"
	 if [ ! -z "${DEBUG}" ] ; then
	   echo -e "\n< Found devfs >"
	 fi 
      else
         warn_msg "* Assuming a static /dev :"
         DEVNODES="static"
      fi
   fi
   
   kernel_is_26 && run_with_msg " * Mounting sysfs : " "mount -n -t sysfs sysfs /sys"
  
   if [ "$DEVNODES" = "devfs" ]; then

      run_with_msg " * Mounting /dev : " "mount -n -t devfs devfs /dev"
      run_with_msg " * Starting devfsd : " "devfsd /dev"
   

   elif [ "$DEVNODES" = "udev" ]; then

      run_with_msg  " * Mounting tmpfs on /dev : "                           "mount -n -t tmpfs tmpfs /dev -o size=4m"
      run_with_msg  " * Setting /sbin/udevsend to manage hotplug events : "  "echo /sbin/udevsend > /proc/sys/kernel/hotplug"
      run_with_msg  " * Creating udev device nodes on /dev : "               "/sbin/udevstart"
      run_without_msg "mkdir -p /dev/{pts,shm}"
	  run_without_msg "ln -sf /proc/self/fd /dev/"

   fi

   if [ -f /forcefsck ] ; then 
      FORCE="-f"
   fi

   run_with_msg_and_exit_codes " * Checking all file systems : " "fsck -A -y -V $FORCE" "0" "1" ""
   exit_status=$?

   case ${exit_status} in 
      0|1) # exited fine ( 0 ), or errors were fixed (1) 
         rm -f /forcefsck
         ;;
      *)  
         echo " * fsck failed!"
		 echo ""
         echo "   Please repair your file system manually by"
		 echo "   running /sbin/fsck without the -p option."
		 echo ""
         sulogin
         reboot  -f
         ;;
   esac
 
  
   run_with_msg " * Remounting root readwrite : " "mount -n -o remount,rw /"

   run_without_msg "echo -n \"\" > /etc/mtab"
   run_without_msg "rm -f /etc/mtab~*"

   run_without_msg "mount -f -o remount,rw /"   
  
   run_with_msg  " * Mounting swap : " "swapon -a"
  
   echo "Mounting remaining filesystems : "

   # We mounted devfs before, now a hack to get it into /etc/mtab
   if [ "$DEVNODES" == "devfs" ]; then
      run_without_msg "mount -f -t devfs devfs /dev"
   fi
  
   # sort the filesystems, swapfiles at bottom, squeeze separators into spaces
   sed 's/#.*$//g' /etc/fstab | tr '\t' ' ' | tr -s '[:space:]' | grep -v -e '^$\|noauto' | LC_ALL=C sort -k2 | while read DEVICE MOUNTPOINT FSTYPE OPTS REST
   do  
      case $MOUNTPOINT in
         /|/proc|/sys|/dev) # been mounted previously
            continue      
            ;;
         none)
            continue
            ;;
      esac

      case $FSTYPE in
         nfs|nfs4|smbfs)    # we don't do networked fs's yet!
            continue 
            ;;
      esac
      
      if [ -n "$OPTS" ]; then
         OPTS="-o $OPTS"
      fi

      run_with_msg  " * Mounting $MOUNTPOINT : "  "mount $MOUNTPOINT $OPTS" 

   done
}


stop() 
{
   # Establish where to get mount table from, save these since the files change if we unmount something
   if [ -r /proc/mounts ] ; then
      MOUNTS=/proc/mounts
   else
      MOUNTS=/etc/mtab
   fi
    
   # write wtmp in /var before umounting /var
   run_without_msg "reboot -w"
    
   echo "Unmounting all filesystems :"
    
   cat $MOUNTS | tac | while read TYPE PNT FS REST ; do
	    
      case $FS in
         nfs|smbfs) # we don't do net filesystems
            continue
            ;;
      esac

      case $PNT in
         /|/proc|/dev|/sys) # no need to unmount these
            continue
            ;;
      esac

      echo  -n " * Umounting $PNT:"
      run_without_msg "sync ; sync" # Flush buffers
	    
      ITERATION=1
      UNMOUNT_ERROR=0

      until [ -z `grep -w $PNT $MOUNTS | awk '{ print $1 }'` ] || [ $UNMOUNT_ERROR -eq 1 ];
      do          
         case $ITERATION in
           1)
             run_without_msg "umount $PNT"
             ;;
           2)
             sleep 1
             run_without_msg "fuser -s -km -3 $PNT" "1"
             run_without_msg "umount $PNT"
             ;; 
           3)
             sleep 1 
             run_without_msg "fuser -s -km -9 $PNT" "1"
             run_without_msg "umount $PNT" "1"
             ;;
           4) 
             sleep 1  
             run_without_msg "fuser -s -km -9 $PNT" "1"
             run_without_msg "umount -lf $PNT" "4"
             run_without_msg "sync; sync"
             ;;
           5)
             UNMOUNT_ERROR=1 # warn that it hasn't been able to unmount the easy way
             ;;
          esac

          (( ITERATION++ ))
      done

      if [ $UNMOUNT_ERROR -eq 1 ]; then # haven't been able to unmount the point, so be drastic
         echo -e $RESULT_WARN
         run_with_msg "  * Attempting to remount $PNT read-only : " "mount $PNT -o remount,ro"
      else
         echo -e $RESULT_OK
      fi

      if [ "$TYPE" == "/dev/loop*" -a -f $PNT ] ; then      
         # unhook loopback device too
         run_with_msg " * Detaching loopback device $TYPE : " "losetup -d $TYPE"
      fi
	    
   done
    
   run_with_msg " * Deactivating swap space : " "swapoff  -a"
    
   run_without_msg "sync; sync;" "2"  # might take some time so we wait here for a couple of seconds
    
   if ! run_with_msg  " * Remounting root readonly : "  "mount -n -o remount,ro /" ; then
      if ! run_with_msg  " * Trying again to remount root readonly : "  "umount -l -O remount,ro /" "4" ; then
         read   -n 1  -t 30  -p  "Do you want to login? (y/n) "  CONFIRM
         echo   ""
         case ${CONFIRM} in
            y|Y)  sulogin ;;
         esac
      fi
   fi

   run_without_msg "sync; sync" "2"
}


# to avoid confusion we force only these options as being valid:
case "${1}" in
   start|stop) 
      ;;

   *) 
      echo "Warning: ${0} should never be called directly";
      exit 1  
      ;;
esac

. /lib/lsb/init-functions

