#!/bin/bash
#
# rc file for automount using a Sun-style "master map".
# We first look for a local /etc/auto.master, then a YP
# map with that name
#

### BEGIN INIT INFO
# Provides:       autofs
# Required-Start: $network $syslog $remote_fs
# X-UnitedLinux-Should-Start: ypbind keyserv ldap
# Required-Stop:
# X-UnitedLinux-Should-Stop:
# Default-Start:  3 5
# Default-Stop:
# Description:    Start the autofs daemon for automatic mounting of filesystems.
### END INIT INFO

#
# Location of the automount daemon and the init directory
#
DAEMON=/usr/sbin/automount

. /etc/rc.status
. /etc/sysconfig/autofs

# check if program is installed
test -x $DAEMON || exit 5

PATH=/sbin:/usr/sbin:/bin:/usr/bin
LDAPCONF=/etc/ldap.conf
export PATH LDAPCONF

#
# We can add local options here
# e.g. localoptions='rsize=8192,wsize=8192'
#
localoptions=$LOCAL_OPTIONS

#
# Daemon options
# e.g. --timeout 60
#
daemonoptions=$AUTOFS_OPTIONS

# normal behavior of ps, please.
unset PS_PERSONALITY
unset CMD_ENV

KNOWNMAPS=""

function is_maptype()
{
    local supported="file program yp nisplus hesiod ldap"

    for t in $supported; do
	if [ "$1" == "$t" ]; then
	    return 0;
	fi
    done

    return 1;
}

#
# Get list of local mounts.
#
function getmounts_files()
{
    if [ -f /etc/auto.master ] ; then
	# We remove not only comments, but also "/-" since it stands for
	# direct mounts which autofs doesn't support yet.
	cat /etc/auto.master | sed -e '/^#/d' -e '/^$/d' -e '/^\/-[ \t]/d' | (
	    while read dir line; do
		if `egrep -q "^${dir}" $KNOWNMAPS`; then
		    continue
		fi
		tmp=`echo $line | awk '{ print $1 }'`
		is_maptype $tmp
		if [ $? -eq 0 ]; then
		    # Space separated maptype
		    maptype=$tmp
		    map=`echo $line | awk '{ print $2 }'`
		    options=`echo $line | awk '{ for(i=3; i <= NF; ++i) printf("%s ", $i) }'`
		elif [ "`echo $tmp | sed -n -e '/:/p'`" ]; then
		    # colon separated
		    maptype=${tmp%:*}
		    map=${tmp#*:}
		    options=`echo $line | awk '{ for(i=2; i <= NF; ++i) printf("%s ", $i) }'`
		else
		    # no maptype given
		    maptype=""
		    map=$tmp
		    options=`echo $line | awk '{ for(i=2; i <= NF; ++i) printf("%s ", $i) }'`
		fi
		if [ ! -z "$dir" -a ! -z "$map" -a x`echo "$map" | cut -c1` != 'x-' ] ; then
		    # assume local map if maptype not given
		    if [ -z "$maptype" -o "$maptype" = "file" ]; then
		        map=`echo "/etc/$map" | sed -e 's:^/etc//:/:'`
		    fi
		    options=`echo "$options" | sed -e 's/\(^\|[ \t]\)-/\1/g'`
		    if echo $options | grep -- '-t' >/dev/null 2>&1 ; then
			mountoptions="--timeout $(echo $options | \
			    sed 's/^.*-t\(imeout\)*[= \t]*\([0-9][0-9]*\).*$/\2/g')"
                    else
			mountoptions=""
		    fi
		    options=`echo "$options" | sed -e '
			s/--*t\(imeout\)*[= \t]*[0-9][0-9]*//g
			s/\(^\|[ \t]\)-/\1/g'`
		    echo $dir >> $KNOWNMAPS
		    if [ "$maptype" ]; then
			echo "$DAEMON $daemonoptions $mountoptions $dir $maptype $map $options $localoptions"
		    else
    		        if [ -x $map ]; then
		            echo "$DAEMON $daemonoptions $mountoptions $dir program $map $options $localoptions"
		        elif [ -f $map ]; then
		            echo "$DAEMON $daemonoptions $mountoptions $dir file $map $options $localoptions"
		        else
		            echo "$DAEMON $daemonoptions $mountoptions $dir $maptype `basename $map` $options $localoptions"
		        fi
		    fi
		elif [ ${dir:0:1} = '+' ]; then
		    getmounts_nis ${dir:1}
   		fi
        done
	) | sed 's/ \+/ /g'
    fi
}


#
# Get list of nis mounts.
#
function getmounts_nis()
{
    nis_map=${1:-$NISMASTERMAP}

    if [ -x /usr/bin/ypcat ] && [ `ypcat -k $nis_map 2>/dev/null | wc -l` -gt 0 ] ; then
	# remove "/-" line used by direct mounts, which we don't yet understand
	ypcat -k $nis_map | sed -e '/^\/-[ \t]/d' | (
	    while read dir map options ; do
		if `egrep -q "^${dir}" $KNOWNMAPS`; then
		    continue
		fi
		maptype=${map%%:*}
		if test -z "$maptype" || ! is_maptype "$maptype"; then
		    maptype=yp
		fi
		if [ ! -z "$dir" -a ! -z "$map" -a x`echo "$map" | cut -c1` != 'x-' ] ; then
		    [ "$UNDERSCORETODOT" = "yes" ] && map=`echo "$map" | sed -e 's/^auto_/auto./'`
		    if echo $options | grep -- '-t' >/dev/null 2>&1 ; then
			mountoptions="--timeout $(echo $options | \
			    sed 's/^.*-t\(imeout\)*[= \t]*\([0-9][0-9]*\).*$/\2/g')"
		    fi
		    options=`echo "$options" | sed -e '
			s/--*t\(imeout\)*[= \t]*[0-9][0-9]*//g
			s/\(^\|[ \t]\)-/\1/g'`
		    echo $dir >> $KNOWNMAPS
	            echo "$DAEMON $daemonoptions $mountoptions $dir $maptype $map $options $localoptions"
		fi
	    done
	) | sed 's/ \+/ /g'
    fi
}


#
# Get list of nisplus mounts.
#
function getmounts_nisplus()
{
    if [ -x /usr/bin/niscat ] && [ `niscat auto_master.org_dir 2>/dev/null | wc -l` -gt 0 ] ; then
	# remove "/-" line used by direct mounts, which we don't yet understand
	niscat auto_master.org_dir | sed -e '/^\/-[ \t]/d' | (
	    while read dir map options ; do
		if `egrep -q "^${dir}" $KNOWNMAPS`; then
		    continue
		fi
		if [ ! -z "$dir" -a ! -z "$map" -a x`echo "$map" | cut -c1` != 'x-' ] ; then
		    if echo $options | grep -- '-t' >/dev/null 2>&1 ; then
			mountoptions="--timeout $(echo $options | \
			    sed 's/^.*-t\(imeout\)*[= \t]*\([0-9][0-9]*\).*$/\2/g')"
                fi
		    options=`echo "$options" | sed -e '
			s/--*t\(imeout\)*[= \t]*[0-9][0-9]*//g
			s/\(^\|[ \t]\)-/\1/g'`
		    echo $dir >> $KNOWNMAPS
		    if [ -x $map ]; then
			echo "$DAEMON $daemonoptions $mountoptions $dir program $map $options $localoptions"
		    elif [ -f $map ]; then
			echo "$DAEMON $daemonoptions $mountoptions $dir file $map $options $localoptions"
		    else
			echo "$DAEMON $daemonoptions $mountoptions $dir nisplus $map $options $localoptions"
                    fi
                fi
    done
	) | sed 's/ \+/ /g'
    fi
}


#
# Get list of ldap mounts.
#
function getmounts_ldap()
{
  /usr/lib/autofs/autofs-ldap-auto-master | (
  while read dir maptype map; do
     if `egrep -q "^${dir}" $KNOWNMAPS`; then
        continue
     fi
     # new style ldap maps look this ldap://<host>/basedn 
     # instead of ldap host:basedn
     if [ -z $map ] ; then
        map=$maptype
        maptype=`echo $map | cut -f1 -d:`
        map=`echo $map | sed -e 's/^.*://'`
     fi
     echo $dir >> $KNOWNMAPS
     echo "$DAEMON $daemonoptions $dir $maptype \"$map\" $localoptions"
  done
  )
}


#
# Check for all maps that are to be loaded.
#
function getschemes()
{
    grep ^automount: /etc/nsswitch.conf | sed -e 's/^.*:[ \t]*//'
}


#
# This function will build a list of automount commands to execute in
# order to activate all the mount points. It is used to figure out
# the difference of automount points in case of a reload.
#
function getmounts()
{
    KNOWNMAPS=`mktemp /tmp/autofs.XXXXXX` || { echo "could not make temp file" >& 2; exit 1; }

    for scheme in `getschemes` ; do
        case "$scheme" in
            files)
		getmounts_files
		;;
	    nis)
		getmounts_nis
		;;
	    nisplus)
		getmounts_nisplus
		;;
            ldap)
                getmounts_ldap
                ;;
	esac
	done
	rm -f $KNOWNMAPS
}


#
# Status lister.
#
function status()
{
	echo "Configured Mount Points:"
	echo  "------------------------"
	getmounts
	echo ""
	echo "Active Mount Points:"
	echo  "--------------------"
	ps -w -C automount -o command= | grep "^$DAEMON "
}


#
# Return true if at least one pid is alive.
#
function alive()
{
    if [ -z "$*" ]; then
	return 1
    fi
    for i in $*; do
	if kill -0 $i 2> /dev/null; then
	    return 0
	fi
    done

    return 1
}


#
# Kill all processes using automounted paths.
#
function kill_all_using_me()
{
    for SIG in -TERM -KILL ; do
	while read mount_type path foobar ; do
	    case "$mount_type" in
		automount*)
		    (
		        for d in $path/* ; do
			    test "$d" = "$path/*" && break
		            /bin/fuser -k $SIG -m $d > /dev/null 2>&1
		        done
		    ) &> /dev/null
		    ;;
	    esac
	done < /proc/mounts
	if [ $SIG == -TERM ] ; then
	    sleep 2
		fi
	done
}

# sometimes, the mountpoints cannot be unmounted by automount
# in this case unmount them lazily
function umount_lazy_all()
{
       mounts=$(cat /etc/mtab | grep ^automount | cut -d ' ' -f 2)
        for mnt in $mounts; do
                umount -l $mnt/* 2>/dev/null
                umount -l $mnt   2>/dev/null
        done
}

#
# See how we were called.
#

return=0

case "$1" in
  start)
	# Check if the automounter is already running?
	echo -n "Starting service automounter"
	pids=$(/sbin/pidof $DAEMON)
	if [ ! -f /var/lock/subsys/autofs -o -z "$pids" ]; then
	    rm -f /var/lock/subsys/autofs
	    if [ -z "`getmounts`" ]; then
		schemes=`getschemes`
		if [ "$schemes" ]; then
			echo -n " (\"$schemes\" does not provide any mounts)"
		else
			echo -n " (no mounts configured)"
	    fi
		rc_status -s
		# service is not configured
		rc_failed 6
		rc_exit
	else
		getmounts | sh || return=1
		touch /var/lock/subsys/autofs
	fi
	else
	    echo -n " (already running)"
	fi
	rc_status -v
	;;
  stop)
	echo -n "Shutting down service automount"
	if checkproc $DAEMON ; then
	    # kill all automounts in runlevel 0 and 6 to prevent busy
	    case $RUNLEVEL in
		0|6|s|S)
		    kill_all_using_me
		    ;;
	    esac
	    # now kill daemons
	    pids=$(/sbin/pidof $DAEMON)
	    killproc -TERM $DAEMON || return=1
	    if [ $return == 0 ] ; then
		echo -e "$rc_done"
	    else
		echo -e "$rc_failed"
	    fi
	    count=1
	    while alive $pids; do
		sleep 5
		count=$(expr $count + 1)
		if [ $count -gt 5 ]; then
		    echo "Giving up on automounter"
		    break;
		fi
		echo "Automounter not stopped yet: retrying... (attempt $count)"
	done
	    if [ $count -gt 1 -a $count -le 10 ]; then
		echo "Automounter stopped"
	    fi
	else
	    return=0
	    echo -e "$rc_done"
	fi
	umount_lazy_all
	rm -f /var/lock/subsys/autofs
	;;
  restart|force-reload)
	$0 stop
	$0 start
	return=$?
	;;
  reload)
	if [ ! -f /var/lock/subsys/autofs ]; then
		echo "Automounter not running"
		exit 1
	fi
	echo "Checking for changes to /etc/auto.master ..."
        TMP1=`mktemp /tmp/autofs.XXXXXX` || { echo "could not make temp file" >& 2; exit 1; }
        TMP2=`mktemp /tmp/autofs.XXXXXX` || { echo "could not make temp file" >& 2; exit 1; }
	getmounts >$TMP1
	ps -w -C automount -o pid=,command= | grep " $DAEMON " | (
	    while read pid command; do
		echo "$command" >>$TMP2
		if ! grep -q "^$command" $TMP1; then
		    (
			while kill -USR2 $pid; do
			    sleep 3
			done
		    ) &> /dev/null
		    echo "Stop $command"
		fi
	    done
	)
	( while read x; do
		if ! grep -q "^$x" $TMP2; then
			$x
			echo "Start $x"
		fi
        done ) < $TMP1
	rm -f $TMP1 $TMP2
	;;
  status)
	echo -n "Checking for service autofs: "
        checkproc $DAEMON && return=0 || return=3
	if [ $return == 0 ] ; then
            echo -e "$rc_running"
	else
	    echo -e "$rc_unused"
	fi
	status
	;;
  expire)
	echo -n "Trigger expire for autofs: "
	if checkproc $DAEMON ; then
	    # send USR1 to daemons
	    killproc -USR1 $DAEMON || return=1
	fi
	if [ $return == 0 ] ; then
	    echo -e "$rc_done"
		else
	    echo -e "$rc_failed"
		fi
	;;
    *)
	echo "Usage: $initdir/autofs {start|stop|restart|reload|force-reload|status|expire}"
	exit 3
esac

exit $return

