#! /bin/sh
### BEGIN INIT INFO
# Provides:          checkroot mtab
# Required-Start:    mountdevsubfs hostname
# Required-Stop:     
# Should-Start:      keymap hwclockfirst hdparm bootlogd
# Should-stop:
# Default-Start:     S
# Default-Stop:
# X-Interactive:     true
# Short-Description: Check to root file system.
### END INIT INFO

# Include /usr/bin in path to find on_ac_power if /usr/ is on the root
# partition.
setvar PATH = "/sbin:/bin:/usr/bin"
setvar FSCK_LOGFILE = "/var/log/fsck/checkroot"
test $FSCKFIX || setvar FSCKFIX = 'no'
test $SULOGIN || setvar SULOGIN = 'no'
source /lib/init/vars.sh

source /lib/lsb/init-functions
source /lib/init/mount-functions.sh

proc do_start {
	# Trap SIGINT so that we can handle user interrupt of fsck.
	trap "" INT

	#
	# Set SULOGIN in /etc/default/rcS to yes if you want a sulogin to
	# be spawned from this script *before anything else* with a timeout,
	# like sysv does.
	#
	test $SULOGIN = yes && sulogin -t 30 $CONSOLE

	setvar KERNEL = "$(uname -s)"
	setvar MACHINE = "$(uname -m)"

	read_fstab

	#
	# Activate the swap device(s) in /etc/fstab. This needs to be done
	# before fsck, since fsck can be quite memory-hungry.
	#
	setvar ENABLE_SWAP = 'no'
	case (KERNEL) {
	  Linux {
	  	if test $NOSWAP = yes
		{
			test $VERBOSE = no || log_warning_msg "Not activating swap as requested via bootoption noswap."
			setvar ENABLE_SWAP = 'no'
		} else {
			if test $swap_on_lv = yes
			{
				test $VERBOSE = no || log_warning_msg "Not activating swap on logical volume."
			} elif test $swap_on_file = yes
			{
				test $VERBOSE = no || log_warning_msg "Not activating swap on swapfile."
			} else {
				setvar ENABLE_SWAP = 'yes'
			}
		}
		}
	  * {
		setvar ENABLE_SWAP = 'yes'
		}
	}
	if test $ENABLE_SWAP = yes
	{
		if test $VERBOSE = no
		{
			log_action_begin_msg "Activating swap"
			swapon -a -e >/dev/null 2>&1
			log_action_end_msg $?
		} else {
			log_daemon_msg "Activating swap"
			swapon -a -v
			log_end_msg $?
		}
	}

	#
	# Does the root device in /etc/fstab match with the actual device ?
	# If not we try to use the /dev/root alias device, and if that
	# fails we create a temporary node in /run.
	#
	# Do this only on Linux. Neither kFreeBSD nor Hurd have
	# /dev/root and the device ids used here are specific to
	# Linux.
	setvar KERNEL = "$(uname)"
	if test $rootcheck = yes && test $KERNEL = Linux
	{
		setvar ddev = "$(mountpoint -qx $rootdev)"
		setvar rdev = "$(mountpoint -d /)"
		if test $ddev != $rdev && test $ddev != "4:0"
		{
			if test $(mountpoint -qx /dev/root) = "4:0"
			{
				setvar rootdev = "/dev/root"
			} else {
				if \
					rm -f /run/rootdev \
					&& mknod -m 600 /run/rootdev b ${rdev%:*} ${rdev#*:} \
					&& test -e /run/rootdev
				{
					setvar rootdev = "/run/rootdev"
				} else {
					setvar rootfatal = 'yes'
				}
			}
		}
	}

	#
	# Bother, said Pooh.
	#
	if test $rootfatal = yes
	{
		log_failure_msg "The device node $rootdev for the root filesystem is missing or incorrect 
or there is no entry for the root filesystem listed in /etc/fstab. 
The system is also unable to create a temporary node in /run. 
This means you have to fix the problem manually."
		log_warning_msg "A maintenance shell will now be started. 
CONTROL-D will terminate this shell and restart the system."
		# Start a single user shell on the console
		if ! sulogin $CONSOLE
		{
			log_failure_msg "Attempt to start maintenance shell failed. 
Will restart in 5 seconds."
			sleep 5
		}
		test $VERBOSE = no || log_action_msg "Will now restart"
		reboot -f
	}

	# See if we're on AC Power.  If not, we're not gonna run our
	# check.  If on_ac_power (in /usr/) is unavailable, behave as
	# before and check all file systems needing it.
# Disabled AC power check until fsck can be told to only check the
# file system if it is corrupt when running on battery. (bug #526398)
#	if which on_ac_power >/dev/null 2>&1 && [ "$rootcheck" = yes ]
#	then
#		on_ac_power >/dev/null 2>&1
#		if [ "$?" -eq 1 ]
#		then
#			log_warning_msg "On battery power, so skipping file system check."
#			rootcheck=no
#		fi
#	fi

	#
	# See if we want to check the root file system.
	#
	setvar FSCKCODE = '0'

	if test -e /run/initramfs/fsck-root
	{
		setvar rootcheck = 'no'
	}

	if is_fastboot_active
	{
		test $rootcheck = yes && log_warning_msg "Fast boot enabled, so skipping root file system check."
		setvar rootcheck = 'no'
	}

	if which findmnt >/dev/null 2>&1
	{
		if test $(findmnt -f -n -o FSTYPE /) = "btrfs"
		{
			test $rootcheck = yes && log_warning_msg "btrfs root detected, so skipping root file system check."
			setvar rootcheck = 'no'
		}
	}

	if test $rootcheck = yes
	{
		#
		# Ensure that root is quiescent and read-only before fsck'ing.
		#
		# mount -n -o remount,ro / would be the correct syntax but
		# mount can get confused when there is a "bind" mount defined
		# in fstab that bind-mounts "/" somewhere else.
		#
		# So we use mount -n -o remount,ro $rootdev / but that can
		# fail on older kernels on sparc64/alpha architectures due
		# to a bug in sys_mount().
		#
		# As a compromise we try both.
		#
		if \
			! mount    -n -o remount,ro              $rootdev /              \
			&& ! mount -n -o remount,ro -t dummytype $rootdev /  2>/dev/null \
			&& ! mount -n -o remount,ro                       /  2>/dev/null
		{
			log_failure_msg "Cannot check root file system because it is not mounted read-only."
			setvar rootcheck = 'no'
		}
	}

	#
	# The actual checking is done here.
	#
	if test $rootcheck = yes
	{
		if test -f /forcefsck || grep -q -s -w -i "forcefsck" /proc/cmdline
		{
			setvar force = ""-f""
		} else {
			setvar force = """"
		}

		if test $FSCKFIX = yes
		{
			setvar fix = ""-y""
		} else {
			setvar fix = ""-a""
		}

		setvar spinner = ""-C""
		case (TERM) {
		  dumb|network|unknown|"" {
			setvar spinner = """" }
		}
		# This Linux/s390x special case should go away.
		if test "${KERNEL}:${MACHINE}" = Linux:s390x
		{
			setvar spinner = """"
		}
		
		if test $VERBOSE = no
		{
			log_action_begin_msg "Checking root file system"
			logsave -s $FSCK_LOGFILE fsck $spinner $force $fix -t $roottype $rootdev
			setvar FSCKCODE = ""$?
			if test $FSCKCODE = 0
			{
				log_action_end_msg 0
			} else {
				log_action_end_msg 1 "code $FSCKCODE"
			}
		} else {
			log_daemon_msg "Will now check root file system"
			logsave -s $FSCK_LOGFILE fsck $spinner $force $fix -V -t $roottype $rootdev
			setvar FSCKCODE = ""$?
			log_end_msg $FSCKCODE
		}
	}

	#
	# If there was a failure, drop into single-user mode.
	#
	# NOTE: "failure" is defined as exiting with a return code of
	# 4 or larger. A return code of 1 indicates that file system
	# errors were corrected but that the boot may proceed. A return
	# code of 2 or 3 indicates that the system should immediately reboot.
	#
	if test $FSCKCODE -eq 32
	{
		log_warning_msg "File system check was interrupted by user"
	} elif test $FSCKCODE -gt 3
	{
		# Surprise! Re-directing from a HERE document (as in "cat << EOF")
		# does not work because the root is currently read-only.
		log_failure_msg "An automatic file system check (fsck) of the root filesystem failed. 
A manual fsck must be performed, then the system restarted. 
The fsck should be performed in maintenance mode with the 
root filesystem mounted in read-only mode."
		log_warning_msg "The root filesystem is currently mounted in read-only mode. 
A maintenance shell will now be started. 
After performing system maintenance, press CONTROL-D 
to terminate the maintenance shell and restart the system."
		# Start a single user shell on the console
		if ! sulogin $CONSOLE
		{
			log_failure_msg "Attempt to start maintenance shell failed. 
Will restart in 5 seconds."
			sleep 5
		}
		test $VERBOSE = no || log_action_msg "Will now restart"
		reboot -f
	} elif test $FSCKCODE -gt 1
	{
		log_failure_msg "The file system check corrected errors on the root partition 
but requested that the system be restarted."
		log_warning_msg "The system will be restarted in 5 seconds."
		sleep 5
		test $VERBOSE = no || log_action_msg "Will now restart"
		reboot -f
	}

	#
	# Remount root to final mode (rw or ro).
	#
	# See the comments above at the previous "mount -o remount"
	# for an explanation why we try this twice.
	#
	if ! mount -n -o remount,$rootopts,$rootmode $fstabroot / 2>/dev/null
	{
		mount -n -o remount,$rootopts,$rootmode /
	}

	# If possible, migrate /etc/mtab to be a symlink to
	# /proc/mounts.  Note that not all systems e.g. Hurd currently
	# support this.
	if test $rootmode != "ro" {
		mtab_migrate
	}

	if selinux_enabled && test -x /sbin/restorecon && test -r /etc/mtab
	{
		restorecon /etc/mtab
	}

	#
	# Remove /run/rootdev if we created it.
	#
	rm -f /run/rootdev

	# Update mount options for mounts created in early boot
	# S01mountkernfs.sh
	/etc/init.d/mountkernfs.sh reload
	# S03mountdevsubfs.sh
	/etc/init.d/mountdevsubfs.sh reload

}

proc do_status {
	# If / is read-write or swap is enabled, this script have done
	# its job.
	setvar rootrw = 'false'
	setvar swapon = 'false'
	if test -f /etc/mtab  {
	    if grep " / " /etc/mtab |grep -q rw  {
		setvar rootrw = 'true'
	    }
	}
	if test -f /proc/swaps  {
	    if test $(cat /proc/swaps |grep -v ^Filename)  {
		setvar swapon = 'true'
	    }
	}
	if test true = $rootrw || test true = $swapon  {
		return 0
	} else {
		return 4
	}
}

case (1) {
  start|"" {
	do_start
	}
  restart|reload|force-reload {
	echo "Error: argument '$1' not supported" >&2
	exit 3
	}
  stop {
	# No-op
	}
  status {
	do_status
	exit $?
	}
  * {
	echo "Usage: checkroot.sh [start|stop]" >&2
	exit 3
	}
}

: