#! /bin/bash
# Copyright (c) 1996-2002 SuSE Linux AG, Nuernberg, Germany.
# Copyright (c) 2008 SuSE LINUX Products GmbH, Nuernberg, Germany.
# All rights reserved.
#
# Author: Florian La Roche, 1996
#      Werner Fink <werner@suse.de>, 1996,2008
#      Burchard Steinbild, 1996
#
# Please send feedback to http://www.suse.de/feedback
#
# /etc/init.d/nfs
#
### BEGIN INIT INFO
# Provides:       nfs
# Required-Start: $network $portmap
# Required-Stop:  $network $portmap
# Default-Start:  3 5
# Default-Stop:   0 1 2 6
# Short-Description: NFS client services 
# Description:    All necessary services for NFS clients
### END INIT INFO

. /etc/rc.status
. /etc/sysconfig/nfs

IDMAPD_BIN=/usr/sbin/rpc.idmapd
GSSD_BIN=/usr/sbin/rpc.gssd

IDMAPD_CLIENT_STATE=/var/lock/subsys/nfs-rpc.idmapd
IDMAPD_SERVER_STATE=/var/lock/subsys/nfsserver-rpc.idmapd

NEED_IDMAPD=no
NEED_GSSD=no
NEED_LDCONFIG=no
state=0
usr=""
opt=""
mnt=""
nfs=no

while read  what where type options rest  ; do
    case "$what" in
	\#*|"")     continue ;;
    esac
    case ",$options," in
	*,noauto,*) continue ;;
    esac
    case "$type" in
	nfs|nfs4)   ;;
	*)          continue ;;
    esac
    nfs=yes
    if test "$1" = status ; then
	grep -qE "^$what[[:blank:]]+$where[[:blank:]]+nfs" /proc/mounts && continue
        state=3
	continue
    fi
    case "$where" in
	/usr*)
	    usr="${usr:+$usr }$where"
	    NEED_LDCONFIG=yes
	    ;;
	/opt*)
	    opt="${opt:+$opt }$where"
	    NEED_LDCONFIG=yes
	    ;;
	*)
	    mnt="${mnt:+$mnt }$where"
	    test "$NEED_LDCONFIG" = yes        && continue
	    grep -qE "^$where" /etc/ld.so.conf || continue
	    NEED_LDCONFIG=yes
	    ;;
    esac
done < /etc/fstab
unset what where type options rest

case $NFS_SECURITY_GSS in
  [Nn]*)        flavors="";;
  [Yy]*)        flavors=krb5;;
  *)            flavors="$NFS_SECURITY_GSS";;
esac

if test -n "$flavors" ; then
    NEED_GSSD=yes
fi

if test "$NFS4_SUPPORT" = yes ; then
    NEED_IDMAPD=yes
fi

if test -x /sbin/portmap ; then
    PORTMAP_BIN=/sbin/portmap
elif test -x /sbin/rpcbind ; then
    PORTMAP_BIN=/sbin/rpcbind
else
    echo "portmap/rpcbind is missing"
    rc_failed 3
    rc_status -v
    rc_exit
fi

mount_rpc_pipefs() {
    # See if the file system is there yet
    case `stat -c "%t" -f /var/lib/nfs/rpc_pipefs` in
    *67596969*)
        return 0;;
    esac
    mount -t rpc_pipefs rpc_pipefs /var/lib/nfs/rpc_pipefs
}

mount_usr() {
    test -n "$usr" -o -n "$opt" || return
    local where
    for where in $usr $opt ; do
	mount -o nolock $where	
    done
}

close_usr() {
    test -n "$usr" -o -n "$opt" -o -n "$mnt" || return
    local -i proc=0
    local where
    for where in $usr $opt $mnt ; do
	fuser -skm -TERM $where && let proc++
    done
    test $proc -eq 0 && return
    sleep 5
    for where in $usr $opt $mnt ; do
	fuser -skm -KILL $where
    done
}

do_start_gssd() {
    for flavor in $flavors; do
        /sbin/modprobe rpcsec_gss_$flavor
    done
    mount_rpc_pipefs
    startproc $GSSD_BIN
    return $?
}

do_start_idmapd() {
    mount_rpc_pipefs

    # as idmapd needs to be run be server and client
    # check if there is already a idmapd running
    if checkproc $IDMAPD_BIN && test -f $IDMAPD_SERVER_STATE; then
        killproc -HUP $IDMAPD_BIN
    else
        startproc $IDMAPD_BIN
	return $?
    fi
}

rc_reset
case "$1" in
    start|reload)
	echo -n "Starting NFS client services:"
	if ! checkproc $PORTMAP_BIN ; then
	    echo "portmap/rpcbind is not running"
	    rc_failed 3
	    rc_status -v
	    rc_exit
	fi

	# in case we need /usr and/or /opt via nfs 
	mount_usr

	# sm-notify
	echo -n " sm-notify"
	/usr/sbin/sm-notify $SM_NOTIFY_OPTIONS

	# start gssd
	if test "$NEED_GSSD" = yes ; then
 	    echo -n " gssd"
	    do_start_gssd || {
	        rc_status -v
	        rc_exit
	    }
	fi

	# start idmapd
	if test "$NEED_IDMAPD" = yes ; then
	    echo -n " idmapd"
	    do_start_idmapd || {
	        rc_status -v
	        rc_exit
	    }
            echo $IDMAPD_BIN > $IDMAPD_CLIENT_STATE
	fi

	# remark: statd is started when needed by mount.nfs

	# Mount all auto NFS devices (-> nfs(5) and mount(8) )
	#  NFS-Server sometime not reachable during boot phase.
	#  It's sometime usefull to mount NFS devices in
	#  background with an ampersand (&) and a sleep time of
	#  two or more seconds, e.g:
	#  
	#   sleep 2 && mount -at nfs,nfs4 &
	#   sleep 2 
	#  
	if test "$nfs" = yes ; then
            mount -at nfs,nfs4 > /dev/null 2>&1
	fi
	#
    	# generate new list of available shared libraries
	#
	if test "$NEED_LDCONFIG" = yes; then
	    # check if ld.so.cache needs to be refreshed
	    /etc/init.d/boot.ldconfig start > /dev/null 2>&1
	fi
	#
	rc_status -v
	;;
    stop)
	echo -n "Shutting down NFS client services:"
	#
	# Unmount background because during long timeouts
	#
	if test "$nfs" = yes ; then
	    umount -alt nfs,nfs4 &
	fi

	# stop gssd
	if test "$NEED_GSSD" = yes ; then
	    echo -n " gssd"
	    killproc $GSSD_BIN || {
	        rc_status -v
	        rc_exit
	    }
	fi

	# stop idmapd
	if test "$NEED_IDMAPD" = yes ; then
	    # only stop idmapd if it is not needed by server
	    if test ! -f $IDMAPD_SERVER_STATE ; then
	        echo -n " idmapd"
	        killproc $IDMAPD_BIN || {
	            rc_status -v
	            rc_exit
	        }
	    fi
	    rm -f $IDMAPD_CLIENT_STATE
	fi 

	# in case we have /usr and/or /opt via nfs terminate all
	# processes on them (nfsservers shouldn't do /usr via nfs)
	case "$RUNLEVEL" in
	[016sS]) close_usr ;;
	esac

	#
	rc_status -v
	;;
    restart|force-reload)
        ## Stop the service and regardless of whether it was
	## running or not, start it again.
	$0 stop
	$0 start
	rc_status
	;;
    status)
	echo -n "Checking for mounted nfs shares (from /etc/fstab):"
	if test "$nfs" = yes ; then
	    rc_failed $status
        else
	    rc_failed 3
	fi
	#
	if test "$NEED_GSSD" = yes && ! checkproc $GSSD_BIN; then
	    echo "gssd not running"
	    rc_failed 3
	fi
	# 
	if test "$NEED_IDMAPD" = yes && ! checkproc $IDMAPD_BIN; then
	    echo "idmapd not running"
	    rc_failed 3
	fi
	if ! checkproc /sbin/portmap; then
	    echo "Warning: portmap not running - nfs may not work well"
	fi
        rc_status -v
	;;
    try-restart|condrestart)
	$0 status
	if test $? -eq 0; then
	    $0 restart
	else
	    rc_reset
	fi
	rc_status
	;;
    *)
	echo "Usage: $0 {start|stop|status|reload|force-reload|restart|try-restart}"
	exit 1
esac
rc_exit