#!/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 # ### BEGIN INIT INFO # Provides: autofs # Required-Start: $local_fs # Required-Stop: $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: automount daemon # Description: daemon to mount (possibly remote) filesystems # automatically upon entering the mountpoint ### END INIT INFO # For Redhat-ish systems # # chkconfig: 345 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=/usr/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 [ -f /etc/redhat-release ]; then system=redhat fi 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 [ -f /etc/default/autofs ] && . /etc/default/autofs daemonoptions="$daemonoptions --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 # Append the map's options at the _start_ if there are any options already # (ie. myopt -> $2,myopt), otherwise just append them at the end. if [ -z "$2" ]; then /usr/bin/ypcat -k "$map" 2> /dev/null | sed -e '/^#/d' -e '/^$/d' else /usr/bin/ypcat -k "$map" 2> /dev/null | sed -e '/^#/d' -e '/^$/d' \ -e "s/^[ \t]*\([^ \t]\+\)[ \t]\+\([^ \t]\+\)[ \t]\+-\([^ \t]\+\)/\1 \2 $2,\3/" \ -e "s/^[ \t]*\([^ \t]\+\)[ \t]\+\([^ \t]\+\)[ \t]*$/\1 \2 $2/" fi } 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 cat /etc/auto.master | grep '^\+' | sed -e '/^#/d' -e '/^$/d' | ( while read map options; do catnismap `echo "$map" | sed -e 's/^\+//'` $options done ) fi done ) fi } getnismounts() { YPMAP=`catnismap auto.master` if [ -z "$YPMAP" ]; then catnismap else catnismap auto.master fi } getldapmounts() { if [ -x /usr/lib/autofs/autofs-ldap-auto-master ]; then [ ! -z $LDAPURI ] && export LDAPURI="$LDAPURI" [ ! -z $LDAPBASE ] && export LDAPBASE="$LDAPBASE" /usr/lib/autofs/autofs-ldap-auto-master 2> /dev/null /usr/lib/autofs/autofs-ldap-auto-master -m automountMap \ -e automount -n ou -k cn -v automountInformation 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 # If possible, canonicalise the path so it will always unmount # cleanly. link=`readlink -f "$dir"` if [ ! -z "$link" ]; then dir="$link" 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" -o "$map" = "ldap" ] ; 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 "`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 autofs /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 " done." ;; 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 \ --retry USR2/$DAEMON_EXIT_WAIT \ --pidfile $file --name $dname 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 " done." ;; 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