#! /bin/bash
#
# $Id: //depot/autofs-4.0/samples/rc.autofs.in#4 $
#
# 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: 345 15 85
# 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=/usr/sbin/automount
initdir=/etc/init.d

#
# Determine which kind of configuration we're using
#
system=unknown
if [ -f /etc/debian_version ]; then
    system=debian
elif [ -f /etc/redhat-release ]; then
    system=redhat
else
    echo "$0: Unknown system, please port and contact autofs@linux.kernel.org" 1>&2
    exit 1
fi

if [ $system = debian ]; then
    [ -f /etc/default/autofs ] && . /etc/default/autofs
fi

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

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

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

#
# We can add local options here
# e.g. localoptions='rsize=8192,wsize=8192'
# Note: These options are passed to mount(8).
#       Be aware of that not all filesystems
#       support all options
#
localoptions=''

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

if [ ! -z "$TIMEOUT" ]; then
    daemonoptions="--timeout=$TIMEOUT $daemonoptions"
fi

# Extract the schemes from /etc/nsswitch.conf
# (function derived from RedHat)
function getschemes()
{
    grep ^automount: /etc/nsswitch.conf | sed -e 's/^.*://' -e 's/\[.*\]/ /g'
}

# Process the schemes found in /etc/nsswitch.conf
# (function derived from RedHat, with some modifications)
function getrawmounts()
{
    for scheme in `getschemes` ; do
        case "$scheme" in
            files)
                if [ -z "$filescheme" ] ; then
                    if getmounts_file /etc/auto.master; then
                        filescheme=1  # success
		    else
                        filescheme=0  # failure
                    fi
                    export filescheme
                fi
                ;;
            nis)
                if [ -z "$nisscheme" ] ; then
                    if getnismounts auto.master; then
                        nisscheme=1  # success
		    else
                        nisscheme=0  # failure
                    fi
                    export nisscheme
                fi
                ;;
            ldap*)
                if [ -z "$ldapscheme" ] ; then
                    if getldapmounts; then
                        ldapscheme=1  # success
		    else
                        ldapscheme=0  # failure
                    fi
                    export ldapscheme
                fi
                ;;
        esac
    done

    if [ -z "$filescheme" -a -z "$nisscheme" -a -z "$ldapscheme" ]; then
	# nothing configured in /etc/nsswitch.conf, fall back to old behaviour

	if ! getmounts_file /etc/auto.master; then
	    if ! getnismounts auto.master; then
		if ! getldapmounts; then
		    echo "no autofs mounts configured!" 1>&2
		fi
	    fi
	fi
    else
	if [ ! \( "$filescheme" == "1" -o "$nisscheme" == "1" -o "$ldapscheme" == "1" \) ]; then
	    # all schemes found in /etc/nsswitch.conf have failed

	    echo "no autofs mounts configured!" 1>&2
	fi
    fi
}

#
# 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()
{
    getrawmounts
}



function getmounts_file()
{
    #
    # Check for local maps to be loaded
    #
    local map="$1"
    shift
    if [ -f "$map" ]
    then
	cat "$map" | sed -e '/^#/d' -e '/^$/d' | process_master_file
    else
	return 1
    fi
}

function process_master_file()
{
    local line_options
    local daemon_options

    line_options="$@"  # from `+auto.master <line_options>' in /etc/auto.master

    while read dir map first_option options
    do
	all_options="$first_option $options"

	case "$dir" in
	    +*)
		# note: $map contains options instead of a map
		getnismounts "${dir/+/}" "$line_options" "$map" "$all_options"
		continue;
		;;
	    '/-')
		# ignore (not supported) direct maps
		continue;
		;;
	    '/')
		# Never mount at root!
		echo You wanted me to start on \"/\", this would break your system\! Ignored. >&2
		continue;
		;;
	esac

	if [ ! -z "$dir" -a ! -z "$map" \
		-a x`echo "$map" | cut -c1` != 'x-' ]
	then
	    type=""

            # Break up the maptype and map, if the map type is specified
            maptype=`echo $map | cut -f1 -d:`
            if [ "$maptype" != "$map" ]; then
                # map has form <maptype>:<map>
                type=$maptype
                map=`echo $map | cut -f2- -d:`
	    else
		# special handling of maps
		case "$map" in
		    hesiod|nisplus|userhome)
			type=$map
			map=""
			;;
		    ldap)
			# /<mountpoint> ldap <ldap data> <options>

			type=ldap

			# extract LDAP data
			map="$first_option"
			all_options=$options
			;;
		    /*)
			# map is absolute path
			if [ -x $map ]; then
			    type=program
			elif [ -f $map ]; then
			    type=file
			else
			    # invalid absolute path, ignoring
			    type=""
			fi
			;;
		    !*)
			# map is executable file
			type=program
			map="${map/!/}"
			;;
		    *)
			# map is relative path or empty

			if [ ! -z "$map" ]; then
			    # map is relative path

			    if [ -x /etc/$map ]; then
				type=program
				map=/etc/$map
			    elif [ -f /etc/$map ]; then
				type=file
				map=/etc/$map
			    else
				type=yp
			    fi
			else
			    # map is empty, ignoring
			    type=""
			fi
			;;
		esac
	    fi

	    if [ "$type" ]; then
		options="$line_options $all_options"

		daemon_options=`munge_options daemon $daemonoptions $options`
		options=`munge_options mount $options`

		echo "$DAEMON $daemon_options -- $dir $type $map $localoptions $options" | sed -e 's/  */ /g'
	    fi
	fi
    done
}

function getnismounts()
{
    #
    # Check for YellowPage maps to be loaded
    #
    local map="$1"
    shift
    if [ -e /usr/bin/ypcat ] && [ `ypcat -k "$map" 2>/dev/null | wc -l` -gt 0 ]
    then
	# exclude references to other nis maps (avoid self-references -> inf. loop)
	# - e.g. a map may look like:
	#   $ ypcat -k auto.master
	#   +auto_master             # <- = auto.master = erk!
	#   /net -hosts             -nosuid,nobrowse
	#   /home auto_home -nobrowse
	ypcat -k "$map" | grep -v '^+' | process_master_file "$@"
    else
	return 1
    fi
}

function getldapmounts() {
    if [ ! -x /usr/bin/ldapsearch -o -z "$LDAPURI" -o -z "$LDAPBASE" ]; then
	return 1
    fi    

    ldapsearch -LLL -H $LDAPURI -b $LDAPBASE -x \
	'(objectClass=automount)' cn automountInformation 2>/dev/null \
    | /usr/share/autofs/join_lines | while read attr val; do
	case "$attr" in
	    dn:) 
		node=""
		args=""
		;;
	    cn:)
		node=$val
		;;
	    automountInformation:)
		args=$val
		;;
	    *)
		;;
	esac
	if [ -n "$node" -a -n "$args" ]; then
	    echo "$node $args" | process_master_file "$@"
	    node=""
	    args=""
	fi
    done
}

#
# List active mounts
#
function active()
{
    ps ax|grep "[0-9]:[0-9][0-9] $DAEMON " |
	while read pid tt stat time command
	do
	    echo $command
	done
}

#
# Status lister.
#
function status()
{
	echo "Configured Mount Points:"
	echo "------------------------"
	getmounts | sed 's/ -- / /'
	echo ""
	echo "Active Mount Points:"
	echo "--------------------"
	active
}

function munge_options()
{
	local which="$1"
	shift

	o="$@"
	# bring `timeout' option in suitable format
	o=`echo "$o" | sed -e 's/\(\(-\|, *\)t\(imeout\)\?\) \+/\1=/g'`
	# remove dashes in front of options
	o=`echo "$o" | sed -e 's/^-\+//' -e 's/ -\+/ /' -e 's/,-\+/,/g'`

	echo "$o" | awk -v which="$which" '
BEGIN {
	RS="[, \n]"
	FS="="
	daemon_opts[ "timeout" ] = "timeout"
	daemon_opts[ "t" ] = "timeout"
}
{
	if ( $0 ~ /^$/ )
		next
	if ( $1 in daemon_opts ) {
		daemon[ daemon_opts[ $1 ] ] = $2
	} else if ($1 ~ /^D.+/) {
		defines[ $1 ] = $2
	} else {
		mount[NR] = $0
	}
}
END {
	if ( which ~ "^daemon$" ) {
		if ( "timeout" in daemon ) {
			printf "--timeout=%s\n", daemon["timeout"]
		}
	} else {
		for ( a in defines ) {
			printf "-%s=%s ", a, defines[a]
		}
		for ( a in mount ) {
			if ( length( out ) )
				out=out "," mount[a]
			else
				out=mount[a]
		}
		printf "%s\n", out
	}
}
'
}

function 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
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
}

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

#
# See how we were called.
#
case "$1" in
  start)
	# Check if the automounter is already running?
	if [ ! -f /var/lock/subsys/autofs ]; then
	    echo 'Starting automounter: '
	    getmounts | sed 's/ -- / /' | sh
	    touch /var/lock/subsys/autofs
	fi
	;;
  stop)
	pids=$(/sbin/pidof $DAEMON)
	kill -TERM $pids 2> /dev/null && sleep 1
	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 5 ]; then
	    echo "Automounter stopped"
	fi
	rm -f /var/lock/subsys/autofs
	;;
  reload|restart)
	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 | sed 's/ -- / /' >$TMP1
	ps ax|grep "[0-9]:[0-9][0-9] $DAEMON " | (
	    while read pid tt stat time command; do
		echo "$command" >>$TMP2
		if ! grep -q "^$command" $TMP2; then
			while kill -USR2 $pid; do
				sleep 3
			done
			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)
	status
	;;
  getmounts)
	getmounts
	;;
  active)
	active
	;;

  *)
	echo "Usage: $initdir/autofs {start|stop|restart|reload|status|getmounts|active}"
	exit 1
esac
}

#
# Debian start/stop functions.
#
function debian()
{
#
# See how we were called.
#
case "$1" in
    start)
	echo -n 'Starting automounter:'
	getmounts | while read cmd args
	do
		opt=${args%%-- *}
		rest=${args#*-- }
		mnt=${rest%% *}
		rest=${rest#* }
		echo -n " $mnt"
		if [ ! -d /var/run/autofs ]; then
			mkdir /var/run/autofs
		fi
		pidfile=/var/run/autofs/`echo $mnt | sed 's,_,__,g;s,/,_:,g'`.pid
		start-stop-daemon --start --pidfile $pidfile --quiet \
			--exec $DAEMON -- --pid-file=$pidfile $opt $mnt $rest
	done
	echo "."
	;;
    stop)
	echo -n 'Stopping automounter: '
	start-stop-daemon --stop --quiet --signal USR2 --exec $DAEMON
	any=0
	for file in /var/run/autofs/*.pid
	do
	    if [ -e "$file" ]
	    then
	    	any=1
		pid=`head -n 1 $file`
		command=`get_command_from_pid $pid`
		if [ -z "`ps --no-heading $pid`" ]
		then
		    echo -n -e "\n  Stopped $pid($command)"
		    rm -f $file
		else
		    echo -n -e "\n  Couldn't stop $pid($command)"
		fi
	    fi
	done
        if [ $any -eq 1 ]; then
		echo
        fi
	echo "done."
	;;
    reload)
	echo -n "Reloading automounter: checking for changes..."
	TMP=/var/run/autofs.tmp
	getmounts | sed 's/ -- / /' | sed 's/  / */g' >$TMP

	any=0
	for i in /var/run/autofs/*.pid
	do
		pid=`head -n 1 $i 2>/dev/null`
		[ "$pid" = "" ] && continue
		command=`get_command_from_pid $pid`
		if ! grep -q "^$command" $TMP
		then
	                any=1
			echo -n -e "\n  Stopping automounter: $command"
			kill -USR2 $pid
			rm -f $i
		fi
	done
	if [ $any -eq 1 ]; then
		echo
	fi
	echo "done."
	rm -f $TMP
	$thisscript start
	;;
    force-reload|restart)
	$0 stop
	$0 start
	;;
    status)
	status
	;;
    getmounts)
	getmounts | sed 's/ -- / /'
	;;
    active)
	active
	;;
    *)
	echo "Usage: $initdir/autofs {start|stop|restart|reload|force-reload|status|getmounts|active}" >&2
	exit 1
	;;
esac
}

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

exit 0
