#!/bin/sh
#
# $Id: rc.autofs.in,v 1.58 2005/04/11 11:30:54 raven Exp $
#
# 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
#
# On most distributions, this file should be called:
# /etc/rc.d/init.d/autofs or /etc/init.d/autofs
#

# For Redhat-ish systems
#
# chkconfig: 3 28 72
# processname: /usr/sbin/automount
# config: /etc/auto.master
# description: Automounts filesystems on demand

# This is used in the Debian distribution to determine the proper
# location for the S- and K-links to this init file.
# The following value is extracted by debstd to figure out how to
# generate the postinst script. Edit the field to change the way the
# script is registered through update-rc.d (see the manpage for
# update-rc.d!)
#
FLAGS="defaults 21"

#
# Location of the automount daemon and the init directory
#
DAEMON=/sbin/automount
prog=`basename $DAEMON`
initdir=/etc/init.d

test -e $DAEMON || exit 0

#
# Determine which kind of configuration we're using
#
system=debian

if [ $system = redhat ]; then
	. $initdir/functions
fi

if [ $system = debian ]; then
	thisscript="$0"
	if [ ! -f "$thisscript" ]; then
		echo "$0: Cannot find myself" 1>&2
		exit 1
	fi
fi

PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH

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

#
# Daemon options
# e.g. --timeout=60
#
daemonoptions=''

#
# load custom settings
#
if [ "$system" = "redhat" ]; then
	LOCALOPTIONS=""
	DAEMONOPTIONS=""
	UNDERSCORETODOT=1
	DISABLE_DIRECT=1
	DAEMON_EXIT_WAIT=20

	[ -f /etc/sysconfig/autofs ] && . /etc/sysconfig/autofs

	# Over-ride localoptions if set
	if [ -n "$LOCALOPTIONS" ]; then
		localoptions=$LOCALOPTIONS
	fi

	# Over-ride daemonoptions if set
	if [ -n "$DAEMONOPTIONS" ]; then
		daemonoptions=$DAEMONOPTIONS
	fi
elif [ "$system" = "debian" ]; then
	TIMEOUT=300
	DISABLE_DIRECT=1
	DAEMON_EXIT_WAIT=20

	# Production parameters
	DEBUG=
	VERBOSE=

	# Debug parameters (note that DEBUG and VERBOSE are meaningful only with
	# syslogd)
	#DEBUG=-d
	#VERBOSE=-v

	# Use ghosting, does not break anything if kernel support not present. 
	GHOSTING=

	[ -f /etc/default/autofs ] && . /etc/default/autofs

	daemonoptions="$daemonoptions $DEBUG $VERBOSE $GHOSTING --timeout=$TIMEOUT"
fi

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

	if [ `echo $SOURCES | awk '{print NF}'` -gt 0 ]
	then
		echo ${SOURCES}
	else
		echo files
	fi
}

catnismap()
{
    if [ -z "$1" ] ; then
        map="auto_master"
    else
        map="$1"
    fi
    /usr/bin/ypcat -k "$map" 2> /dev/null | sed -e '/^#/d' -e '/^$/d'
}

getfilemounts()
{
    if [ -f /etc/auto.master ] ; then
        cat /etc/auto.master | awk '{print $0}' | sed -e '/^#/d' -e '/^$/d' | (
        while read auto_master_in
        do
            if [ "`echo $auto_master_in | grep '^+'`" = "" ]; then
                echo $auto_master_in
            else
                for nismap in `cat /etc/auto.master | grep '^\+' |
                        sed -e '/^#/d' -e '/^$/d'`; do
                    catnismap `echo "$nismap" | sed -e 's/^\+//'`
                done
            fi
        done
        )
    fi
}

getnismounts()
{
    YPMAP=`catnismap auto.master`
    if [ -z "$YPMAP" ]; then
       catnismap
    else
       catnismap auto.master
    fi
}

getldapmounts()
{
    if [ -x //lib/autofs/autofs-ldap-auto-master ]; then
        //lib/autofs/autofs-ldap-auto-master 2> /dev/null
    fi
}

getrawmounts()
{
    for scheme in `getschemes` ; do
        case "$scheme" in
            files)
                if [ -z "$filescheme" ] ; then
                    getfilemounts
                    filescheme=1
                    export filescheme
                fi
                ;;
            nis)
                if [ -z "$nisscheme" ] ; then
                    getnismounts
                    nisscheme=1
                    export nisscheme
                fi
                ;;
            ldap*)
                if [ -z "$ldapscheme" ] ; then
                    getldapmounts
                    ldapscheme=1
                    export ldapscheme
                fi
                ;;
        esac
    done
}


#
# 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
#
getmounts()
{
	local LC_ALL=C
	export LC_ALL
	knownmaps=" "
	getrawmounts | (
	while read dir map options
	do
	    # These checks screen out duplicates and skip over directories
	    # where the map is '-'.
	    # We can't do empty or direct host maps, so don't bother trying.

	    # Strip trailing slashes from the dir line if it exists to aid
	    # in checking for duplicate maps
	    dir=`echo "$dir" | sed -e "s/\/*$//"`

	    if [ ! -z "$map" -a "$map" = "-hosts" ] ; then
		continue
	    fi

	    if [ $DISABLE_DIRECT -eq 1 \
			-a x`echo $dir | grep -E "^/-"` != 'x' ]
	    then
		continue
	    fi

	    # Do not include a map if it is a duplicate, maps on top of
	    # another map or another map, maps on top of it.
	    for knownmap in $knownmaps
	    do	
		if [ "`echo $dir/ | grep ^$knownmap`" != "" \
			-o "`echo $knownmap | grep ^$dir/`" != "" \]
		then 
		    continue 2
		fi	
	    done

	    if [ ! -z "$dir" -a ! -z "$map" \
			-a x`echo "$map" | cut -c1` != 'x-' ]
	    then
		# If the options include a -t or --timeout, a -g or --ghost,
		# a -v or --verbose or a -d or --debug paramter, then pull
		# those particular options out.
		: echo DAEMONOPTIONS OPTIONS $daemonoptions $options
		startupoptions=
		if echo "$options" | grep -qE -- '\B-(t\b|-timeout\b=)' ;
		then
		    startupoptions="--timeout=$(echo $options |\
			sed 's/.*-\(t[^0-9]*\|-timeout\)[ \t=]*\([0-9][0-9]*\).*$/\2/g')"
		elif echo "$daemonoptions" | grep -q -- '-t' ;
		then
		    # It's okay to be sloppy with DAEMONOPTIONS as there is no
		    # possibility of conflicting with mount or map options.
		    startupoptions="--timeout=$(echo $daemonoptions | \
		      sed 's/.*--*t\(imeout\)*[ \t=]*\([0-9][0-9]*\).*$/\2/g')"
		fi

		# Check for the ghost option
		if echo "$daemonoptions $options" | grep -qE -- '\B-(g\b|-ghost\b)' ;
		then
		    startupoptions="$startupoptions --ghost"
		fi
		# Dont even deal with conflicts between --ghost and [no]browse
		# Its just insane to configure things like that.
		if echo "$options" | grep -qE -- '\B-browse\b' ;
		then
		    startupoptions="$startupoptions --ghost"
		fi
		# Check for verbose
		if echo "$daemonoptions $options" | \
					grep -qE -- '\B-(v\b|-verbose\b)' ;
		then
		    startupoptions="$startupoptions --verbose"
		fi

		# Check for debug
		if echo "$daemonoptions $options" | \
					grep -qE -- '\B-(d\b|-debug\b)' ;
		then
		    startupoptions="$startupoptions --debug"
		fi

		# Other option flags are intended for maps.
		mapoptions="$(echo "$daemonoptions $options" |\
		      sed   's/-\(t[^0-9]*\|-timeout\)[ \t=]*\([0-9][0-9]*\)//g' |
		      sed   's/-\(g\b\|-ghost\b\)//g' |
		      sed   's/-\(v\b\|-verbose\b\)//g' |
		      sed   's/-\(d\b\|-debug\b\)//g' |
		      sed   's/-\b\(no\)\?browse\b//g')"

		# Break up the maptype and map, if the map type is specified
		maptype=`echo $map | cut -f1 -d:`
		# Handle degenerate map specifiers
		if [ "$maptype" = "$map" ] ; then
		    if [ "$map" = "hesiod" -o "$map" = "userhome" ] ; then
			maptype=$map
			map=
		    elif [ "$map" = "multi" ] ; then
			maptype=$map
			map=
#		    elif echo "$map" | grep -q '^!'; then
#		        map=`echo "$map"| sed -e 's/^!//g'`
		    elif `echo $map | grep -q "^/"` && [ -x "$map" ]; then
			maptype=program
		    elif [ -x "/etc/$map" ]; then
			maptype=program
			map=`echo /etc/$map | sed 's^//^/^g'`
		    elif `echo $map | grep -q "^/"` && [ -f "$map" ]; then
			maptype=file
		    elif [ -f "/etc/$map" ]; then
			maptype=file
			map=`echo /etc/$map | sed 's^//^/^g'`
		    else
			maptype=yp
			if [ "$UNDERSCORETODOT" = "1" ] ; then
			    map=`basename $map | sed -e s/^auto_home/auto.home/ -e s/^auto_mnt/auto.mnt/`
			else
			    map=`basename $map | sed 's^//^/^g'`
			fi
		    fi
		fi
		map=`echo $map | cut -f2- -d:`

		: echo STARTUPOPTIONS $startupoptions
		: echo DIR $dir
		: echo MAPTYPE $maptype
		: echo MAP $map
		: echo MAPOPTIONS $mapoptions
		: echo LOCALOPTIONS $localoptions

		NEWOPTIONS=""
		for m in $mapoptions
		do
			if [ x"$m" = x"--" ]; then
				NEWOPTIONS="$NEWOPTIONS $localoptions --"
			else
				NEWOPTIONS="$NEWOPTIONS $m"
			fi
		done
		mapoptions=$NEWOPTIONS

		echo "$DAEMON $startupoptions $dir $maptype $map $mapoptions $localoptions" | sed -e 's/	/ /g' -e 's/  */ /g'

		: echo ------------------------
	        knownmaps=" $dir/ $knownmaps"
	    fi
	done
    )
}

#
# Status lister.
#
status()
{
	echo -e $"Configured Mount Points:\n------------------------"
	getmounts
	echo ""
	echo -e $"Active Mount Points:\n--------------------"
	ps axwww|grep "[0-9]:[0-9][0-9] $DAEMON " | (
		while read pid tt stat time command; do echo $command; done
	)
}

get_command_from_pid()
{
	ps ax | grep "[0-9]:[0-9][0-9] $DAEMON " | (
		while read pid tt stat time command; do
			if [ "$pid" = "$1" ] ; then
				echo `echo "$command" | \
					sed 's/--pid-file.*\.pid/ /'`
				return 0
			fi
		done
	)
	return 0
}

# return true if at least one pid is alive
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
}

#
# Find pids of process group leaders
#
get_pgrp_pids()
{
	ps -eo pid,pgrp,cmd|grep $DAEMON|\
	awk '{print $1,$2}'|\
	while read pid pgrp
	do
		if [ $pid -eq $pgrp ]
		then
			echo $pid
		fi
	done
}

#
# Signal each automount process group leader
#
signal_automounts()
{
	RETVAL=0
	pgrp_pids=`get_pgrp_pids`
	for pid in $pgrp_pids
	do
		kill -USR2 $pid 2 > /dev/null
		count=0
		while ps ax|grep -v grep|grep $pid >/dev/null
		do
			sleep 1 
			count=$(expr $count + 1)
			if [ $count -gt $DAEMON_EXIT_WAIT ]; then
				break;
			fi
		done
	done

	if [ -n "`/sbin/pidof $DAEMON`" ] ; then
		RETVAL=1
	fi

	return $RETVAL
}

umount_loopback()
{
    loops=`LC_ALL=C awk '!/^#/ && $1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts`
    automounts=`LC_ALL=C awk '!/^#/ && $1 ~ /^automount/ {print $2}' /proc/mounts`

    for l in $loops
    do
	# If a loop device is mounted into a subdir of the automount point,
	# umount it here.
	for a in $automounts
	do
	    match=`echo $l | grep -E "^$a[\$|/]" || true`
	    if [ -n "$match" ]; then
		echo ""
		echo -n $"Unmounting loopback filesystem $match:  "
		loopdev=`LC_ALL=C grep $l /proc/mounts | awk '{print $1}'`
		umount -d $match
		if [ $? -eq 0 ]; then
		    echo "done"
		else
		    echo "failed ($?)"
		fi
	    fi
	done
    done

    # If the loop device file exists under the automount point, umount
    # it here.
    loopmnts=`LC_ALL=C awk '!/^#/ && $1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts`
    for l in $loopmnts
    do
	loopmnt=`losetup $l | awk -F\( '{print $2}' | awk -F\) '{print $1}'`
	for a in $automounts
	do
	    match=`echo $loopmnt | grep -E "^$a[\$|/]" || true`
	    if [ -n "$match" ]; then
		echo ""
		echo -n $"Unmounting loopback filesystem $match:  "
		umount -d $match
		if [ $? -eq 0 ]; then
		    echo "done"
		else
		    echo "failed ($?)"
		fi
	    fi
	done
    done
}

#
# Redhat start/stop function.
#
redhat()
{

#
# See how we were called.
#
case "$1" in
  start)
        # Make sure the autofs filesystem type is available.
        (grep -q autofs /proc/filesystems || /sbin/modprobe -k autofs4 || /sbin/modprobe -k autofs) 2> /dev/null
        echo -n $"Starting $prog: "
        TMP=`mktemp /tmp/autofs.XXXXXX` || { echo $"could not make temp file" >& 2; exit 1; }
        getmounts | tee $TMP | sh
        RETVAL=$?
	if [ -s $TMP ] ; then
	    if [ $RETVAL -eq 0 ] ; then
		success "$prog startup"
	    else
		failure "$prog startup"
	    fi
	    [ $RETVAL = 0 ] && touch /var/lock/subsys/autofs
	else
	    echo -n $"No Mountpoints Defined"
	    success "$prog startup"
	fi
	rm -f $TMP
	echo
	;;
  stop)
	echo -n $"Stopping $prog:"
	if [ -z "`pidofproc $prog`" -a -z "`getmounts`" ]; then
		RETVAL=0
	else
		umount_loopback
		signal_automounts
		RETVAL=$?
	fi
	count=0
	while [ -n "`/sbin/pidof $DAEMON`" -a $count -lt 10 ] ; do
	   killproc $DAEMON -USR2 >& /dev/null
	   RETVAL=$?
	   [ $RETVAL = 0 -a -z "`/sbin/pidof $DAEMON`" ] || sleep 3
	   count=`expr $count + 1`
	done
	umount -a -f -t autofs
	rm -f /var/lock/subsys/autofs
	if [ -n "`/sbin/pidof $DAEMON`" ] ; then
	    failure "$prog shutdown"
	else
	    success "$prog shutdown"
	fi
	echo
	;;
  restart)
	redhat stop
	redhat start
	;;
  reload)
	if [ ! -f /var/lock/subsys/autofs ]; then
		echo $"$prog not running"
		RETVAL=1
		return
	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 axwww|grep "[0-9]:[0-9][0-9] $DAEMON " | (
	    while read pid tt stat time command; do
		echo "$command" >>$TMP2
		if ! grep -q "^$command" $TMP1; then
		    if ! echo "$command" | grep -q -e --submount; then
			kill -USR2 $pid 2> /dev/null
			echo $"Stop $command"
		    fi
		else
			kill -HUP $pid 2> /dev/null
			echo $"Reload map $command"
		fi
	    done
	)
	cat $TMP1 | ( while read x; do
		if ! grep -q "^$x" $TMP2; then
			$x
			echo $"Start $x"
		fi
        done )
	rm -f $TMP1 $TMP2
	;;
  status)
	status
	;;
  condrestart)
	[ -f /var/lock/subsys/autofs ] && redhat restart
        RETVAL=0
	;;
  *)
	echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}"
	RETVAL=0
esac
}

#
# Debian start/stop functions.
#
debian()
{

case "$1" in
start)
	echo -n 'Starting Automounter: '

	# make sure autofs4 is loaded
	if ! grep -q autofs4 /proc/filesystems
	then
		# autofs filesystem support not loaded
		echo -n ' loading autofs4 kernel module, '
		modprobe autofs4 || true
	elif ([ -f /proc/modules ] && lsmod) | grep -q autofs[^4]; then
		# wrong autofs filesystem module loaded
		echo
		echo "WARNING: autofs kernel module is loaded, autofs4 needed"
		echo " for correct behaviour. You might experience mount failures."
	fi

	# Check that maps exist
	if [ -z "$(getrawmounts)" ]
	then
		echo " no automount maps defined."
		exit 0
	fi

	# ensure pid file directory exists
	if [ ! -e /var/run/autofs ]
	then
		mkdir /var/run/autofs
	fi

	getmounts | while read cmd rest
	do
		mnt=`echo $rest | sed 's/^.* \(\/[^ ]*\) [A-Za-z].*$/\1/'`
		pidfile=/var/run/autofs/`echo $mnt | sed 's,/,_,g'`.pid

		start-stop-daemon --start --pidfile $pidfile --quiet \
	  		--exec $DAEMON -- --pid-file=$pidfile $rest

		ret=$?

		if [ $ret -ne 0 ]
		then
			echo
			echo " failed to start automount point $mnt"
		fi
	done

	echo "$prog."
	;;
stop)
	echo -n 'Stopping Automounter: '

	umount_loopback
	
	any=0
	for file in `ls /var/run/autofs/*.pid 2>/dev/null`
	do
		if [ -e "$file" ]
		then
			any=1
			pid=`head -n 1 $file`
			mnt=`ps -wwo 'cmd=' $pid | sed -e \
			  's,.* --pid-file=/var/run/autofs/\([^ ]*\)\.pid.*,\1,; s,_,/,g'`
			dname=`basename $DAEMON`

			start-stop-daemon --stop --quiet \
					--signal USR2 \
					--pidfile $file --name $dname
#					--retry USR2/$DAEMON_EXIT_WAIT \
#

			ret=$?

			case $ret in
			0)
#				echo -n " $mnt"
				rm -f $file
				;;
			1)
				echo -n -e "\n No process for automount $mnt"
				rm -f $file
				;;
			2)
				echo -n -e "\n  Couldn't stop automount for $mnt"
				;;
			*)
				echo -n -e \
			 	"\n Strange start-stop-daemon exit status: $ret"
				;;
			esac
		fi
	done

	echo "$prog."
	;;
reload)
	echo "Reloading Automounter: checking for changes ... "

	TMP1=`mktemp -t autofs.XXXXXX`
	TMP2=`mktemp -t autofs.XXXXXX`

	getmounts >$TMP1

	for i in `ls /var/run/autofs/*.pid 2>/dev/null`
	do
		pid=`head -n 1 $i 2>/dev/null`
		[ "$pid" = "" ] && continue
		
		cmd=`get_command_from_pid $pid`
		echo $cmd >>$TMP2

		mnt=`ps -wwo 'cmd=' $pid | sed -e \
		 's,.* --pid-file=/var/run/autofs/\([^ ]*\)\.pid.*,\1,; s,_,/,g'`

		if ! grep -q "$cmd" $TMP1; then
			echo "Stopping automounter for: $mnt"
			kill -USR2 $pid 2> /dev/null
		else
			echo "Reloading automounter map for: $mnt"
			kill -HUP $pid 2> /dev/null
		fi
	done

	cat $TMP1 | (while read x; do
		if ! grep -q "^$x" $TMP2; then
			echo $x | while read cmd rest; do

			mnt=`echo $rest | sed 's/^.* \(\/[^ ]*\) [A-Za-z].*$/\1/'`
			pidfile=/var/run/autofs/`echo $mnt | sed 's,/,_,g'`.pid

			start-stop-daemon --start --pidfile $pidfile --quiet \
				--exec $DAEMON -- --pid-file=$pidfile $rest

			ret=$?

			if [ $ret -ne 0 ]
			then
				echo
				echo " failed to start automount point $mnt"
			else
				echo "Started automounter: $mnt"
			fi
			done
		fi
	done)

	rm -f $TMP1 $TMP2
	;;
force-reload|restart)
	debian stop
	debian start
	;;
status)
	status
	;;
getmounts)
    	getmounts
	;;
active)
    	alive
	;;
*)
	echo "Usage: $initdir/autofs {start|stop|restart|reload|status|getmounts|active}" >&2
	exit 1
	;;
esac
}

RETVAL=0
if [ $system = debian ]; then
	debian "$@"
elif [ $system = redhat ]; then
	redhat "$@"
fi

exit $RETVAL
