#!/bin/bash
#
# zfs-mount     This script will import/mount/umount/export the zfs filesystems.
#
# chkconfig:    2345 01 99
# description:  This script will import/mount/umount/export the zfs
#               filesystems during system boot/shutdown.  Configuration of
#               which filesystems should be mounted is handled by the zfs
#               'mountpoint' and 'canmount' properties.  See the zfs(8) man
#               page for details.
#               It is also responsible for all userspace zfs services.
# probe: true
#
### BEGIN INIT INFO
# Provides:       zvol zfs zfs-mount
# Required-Start: $local_fs
# Required-Stop:  
# X-Stop-After:   umountfs
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description: Import and mount ZFS pools, filesystems and volumes
# Description: Run the `zpool import`, `zfs mount -a`, `zfs umount -a` or
#              `zpool export` command.
### END INIT INFO

# Source the common init script
. /etc/zfs/common.init
servicename=zfs-mount

# ----------------------------------------------------

# Import all pools
do_import()
{
	POOL_IMPORTED=
	already_imported=$(zpool list -H -oname)
	available_pools=$(zpool import 2> /dev/null | grep pool: | sed 's@.*: @@')

	# Just in case - seen it happen
	if [ -z "$available_pools" -a -n "$USE_DISK_BY_ID" -a "$USE_DISK_BY_ID" == 'yes' ]; then
		available_pools=$(zpool import -d /dev/disk/by-id 2> /dev/null | \
		    grep pool: | sed 's@.*: @@')
	fi

	for pool in $available_pools; do
		# We have pools that haven't been imported - import them
		if [ -n "$ZFS_POOL_EXCEPTIONS" ]; then
			for exception in $ZFS_POOL_EXCEPTIONS; do
				# ... unless we've specified them as NOT
				# to import.
				[ "$pool" == "$exception" ] && continue 2
			done
		fi

		if [ "$USE_DISK_BY_ID" == 'yes' ]; then
			# Really the default/prefered way.
			for dir in /dev/disk/by-vdev /dev/disk/by-* /dev; do
				$log_begin_msg "Importing ZFS pool $pool (using $dir)"
				"$ZPOOL" import -d $dir -N $pool 2>/dev/null
				RET=$?
				if [ "$RET" -eq 0 ]; then
					POOL_IMPORTED=1
					$log_end_msg $RET
					continue 2
				fi
			done
		elif [ -f "$ZPOOL_CACHE" ] ; then
			# Fallback - use a cache file
			$log_begin_msg "Importing ZFS pools (using cache file)"
			"$ZPOOL" import -c "$ZPOOL_CACHE" -N $pool 2>/dev/null
			RET=$?
			if [ "$RET" -eq 0 ]; then
				POOL_IMPORTED=1
				$log_end_msg $RET
				continue 2
			fi
		else
			# Last ditch attempt, try /dev!
			$log_begin_msg "Importing ZFS pools"
			"$ZPOOL" import -N $pool 2>/dev/null
			RET=$?
			if [ "$RET" -eq 0 ]; then
				POOL_IMPORTED=1
				$log_end_msg $RET
				continue 2
			fi

			$log_end_msg $ret
		fi
	done

	if [ -n "$already_imported" -a -z "$available_pools" ]; then
		# All pools imported
		POOL_IMPORTED=1
		$log_end_msg $RET
	fi
}

# Export all pools
do_export()
{
	$log_begin_msg "Exporting ZFS pools"
	"$ZPOOL" list -H -o name | \
	    while read pool; do
		"$ZPOOL" export $pool
	    done
	rmmod zfs
	$log_end_msg 0 # return code not that important.
}

# Mount all datasets/filesystems
do_mount()
{
	if [ -n "$POOL_IMPORTED" ]; then
		[ "$VERBOSE_MOUNT" == 'yes' ] && verbose=v
		[ "$DO_OVERLAY_MOUNTS" == 'yes' ] && overlay=O

		$log_begin_msg "Mounting ZFS filesystems not yet mounted"
		$ZFS mount -a$verbose$overlay $MOUNT_EXTRA_OPTIONS
		RET=$?
		if [ $RET != 0 ] ; then
			$log_end_msg $RET
			exit $RET
		fi
		$log_end_msg 0

		FS_MOUNTED=1

		$log_begin_msg "Mounting volumes registered in fstab: "
		read_mtab  "^/dev/(zd|zvol)"
		read_fstab "^/dev/(zd|zvol)"
		for volume in "${!FSTAB[@]}" ; do
			in_mtab "$volume" && continue

			$log_progress_msg "$volume "
			mount "$volume"
		done

		read_mtab  "zfs"
		read_fstab "zfs"
		for fs in "${!FSTAB[@]}" ; do
			in_mtab "${FSTAB[$fs]}" && continue

			$log_progress_msg "${FSTAB[$fs]} "
			mount "${FSTAB[$fs]}"
		done

		$log_end_msg 0
	fi
}

# Unmount all filesystems
do_unmount()
{
	$log_begin_msg "Unmounting ZFS filesystems"
	$ZFS unmount -a
	RET=$?

	# Ignore a non-zero `zfs` result so that a busy ZFS instance
	# does not hang the system during shutdown.
	if [ $RET != 0 ] ; then
		$log_end_msg $RET
	fi

	$log_end_msg 0

	read_mtab  "^/dev/(zd|zvol)"
	read_fstab "^/dev/(zd|zvol)"

	$log_begin_msg "Unmounting volumes registered in fstab: "
	for volume in "${!FSTAB[@]}" ; do
		dev=/dev/$(ls -l "$volume" | sed 's@.*/@@')
		if ! in_mtab "$dev" ; then continue ; fi

		$log_progress_msg "$volume "
		umount "$volume"
	done

	$log_end_msg 0
}

# Output the status and list of pools
status()
{
	[ ! -f "$LOCKDIR/$servicename" ] && return 3

	if ! grep -q zfs /proc/modules ; then
		# module not loaded, no point in running zpool.
		exit 0
	fi

	"$ZPOOL" status && echo "" && "$ZPOOL" list
}

start()
{
	checksystem && {
		case "$ZFS_MOUNT" in
			([Oo][Ff][Ff]|[Nn][Oo]|'')
				exit 3
				;;
		esac

		do_import
		do_mount

		[ -n "$POOL_IMPORTED" -a -n "$FS_MOUNTED" ] && \
			touch "$LOCKDIR/$servicename"
	}
}

stop()
{
	case "$ZFS_UNMOUNT" in
		([Oo][Ff][Ff]|[Nn][Oo]|'')
			exit 0
			;;
	esac

	# Check if ZFS is installed.  If not, comply to FC standards and bail
	zfs_installed || {
		$log_failure_msg "not installed"
		$log_end_msg 5
	}

	if ! grep -q zfs /proc/modules ; then
		# module not loaded, no need to umount anything
		exit 0
	fi

	do_unmount

	set -- `mount | grep ' on / '`
	if [ "$5" != "zfs" ]; then
	    # Only export the pool if we're not running a zfs root.
	    # Won't work, because the filesystem (and therefor pool)
	    # is busy (being mounted :).
	    do_export
	fi

	rm -f "$LOCKDIR/$servicename"
}

# ----------------------------------------------------

case "$1" in
	(start)
		start
		;;
	(stop)
		stop
		;;
	(status)
		status
		;;
	(force-reload|condrestart|reload|restart)
		# no-op
		;;
	(*)
		[ -n "$1" ] && echo "Error: Unknown command $1."
		echo "Usage: $0 {start|stop|status}"
		exit 3
		;;
esac
