#! /bin/bash
# Copyright 2000, International Business Machines Corporation and others.
# All Rights Reserved.
# 
# This software has been released under the terms of the IBM Public
# License.  For details, see the LICENSE file in the top-level source
# directory or online at http://www.openafs.org/dl/license10.html

# AFS	Start and stop AFS components
# 
# 
# chkconfig: 35 60 20
# description:  AFS is a distributed file system which provides location
#		transparency, caching and secure authentication.
#		Additional configuration can be done in the /etc/sysconfig/afs
#		file. Read the documentation in that file for more information.
#
# The following section is used at least by SuSE insserv(8)
### BEGIN INIT INFO
# Provides: afs
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Description:  AFS is a distributed file system which provides location
#              transparency, caching and secure authentication.
#              Additional configuration can be done in the /etc/sysconfig/afs
#              file. Read the documentation in that file for more information.
### END INIT INFO
#
# Note that AFS does not use a pid file in /var/run. It is turned off by
# unmounting /afs.


# check for special bootup functions
if [ -f /etc/rc.d/init.d/functions ] ; then
	. /etc/rc.d/init.d/functions
	afs_rh=1
else
	# special (RedHat) functions not available...
	# so I provide neccessary replacements (e.g. for SuSE)

	function echo_failure () { echo -n " - failed." ; }

	function echo_success () { echo -n " - successful." ; }

	# these are hopefully all functions I use...
fi

runcmd() {
   echo -n "$1 "
   shift
   if [ "$BOOTUP" = "color" ]; then
      $* && echo_success || echo_failure
   else
      $*
   fi
   echo
}

SYSCNF=${SYSCNF:-/etc/sysconfig/afs}
KERNEL_VERSION=`uname -r`

# Gather up options and post startup script name, if present
if [ -f $SYSCNF ] ; then
	. $SYSCNF
fi

CACHEINFO=${CACHEINFO:-/usr/vice/etc/cacheinfo}
CACHE=${CACHEDIR:-/usr/vice/cache}
AFS=${AFSDIR:-/afs}
AFSD=${AFSD:-/usr/vice/etc/afsd}
BOSSERVER=${BOSSERVER:-/usr/afs/bin/bosserver}
BOS=${BOS:-/usr/bin/bos}
KILLAFS=${KILLAFS:-/usr/vice/etc/killafs}

# is_on returns 1 if value of arg is "on"
is_on() {
	if  test "$1" = "on" ; then return 0
	else return 1
        fi
}

on_network() {
    if hash ip 2>/dev/null >/dev/null; then
        IP="ip -4 addr"
    elif hash ifconfg 2>/dev/null >/dev/null; then
        IP="ifconfig -a"
    else
        echo afs: Unable to check interfaces. 1>&2
        return 1
    fi
    ADDRS=`LANG=C ${IP} | grep 'inet ' | grep -v 127.0.0.1 | wc -l`
    if [ "$ADDRS" = "" ]; then
       echo afs: No interfaces with IP address 1>&2
       return 1
    elif [ $ADDRS = 0 ]; then
       echo afs: No interfaces with IP address 1>&2
       return 1
    fi
    return 0
}

# If choose_client can't correctly determine which client to use, set
# LIBAFS manually.
choose_client() {

	# Use the second field of the uname -v output instead of just
	# doing a match on the whole thing to protect against matching
	# a timezone named SMP -- I don't know of one, but let's be
	# paranoid.

	set X `uname -v`; shift
	case $2 in
	SMP) MP=.mp ;;	# MP system
	*)   MP= ;;	# SP system
	esac

	# For now, just use uname -r to get the module version. 
	case $KERNEL_VERSION in
	  [1-2].[0-5].*)
		LIBAFS=libafs-$KERNEL_VERSION$MP.o
		;;
	  *)
		LIBAFS=libafs-$KERNEL_VERSION$MP.ko
		;;
	esac
}

#
# Find prefix symbol to use with insmod.  We find the unregister_filesystem
# string from /proc/ksyms since we know it's there.  If /proc/ksyms does not
# exist, we print that info to the console and use the uname -v output to
# decide on a prefix.
# unregister_filesystem_Rsmp_b240cad8 is a typcial SMP version string from
# a kernel built from ftp.kernel.org
#
case $KERNEL_VERSION in
  [1-2].[0-5].*)
	KSYMS_FILE=/proc/ksyms
	;;
  *)
	KSYMS_FILE=/proc/kallsyms
	;;
esac
SEARCH_STR="unregister_filesystem"
DEFAULT_SMP_PREFIX="smp_" # Redhat kernels need "smp" instead
PREFIX="" # none needed for UP with <= 1Gig memory

set_prefix()
{
	h='[0-9a-fA-F]'
	h8="$h$h$h$h$h$h$h$h"
	prefix_set=0

	set X `egrep "\<$SEARCH_STR" $KSYMS_FILE 2> /dev/null`; shift
	
	case $KERNEL_VERSION in
	  [1-2].[0-5].*)
		str=$2
		;;
	  *)
		str=$3
		;;
	esac
	case $str in
	${SEARCH_STR}_R$h8)
		# No prefix required
		;;
	$SEARCH_STR)
		# No versioning in kernel symbols
		;;
	${SEARCH_STR}_R*$h8)
		suffix=${str#${SEARCH_STR}_R}
		PREFIX=${suffix%$h8}
		;;
	*)
		case $str in
		'')
			echo afsd: Cannot find \"$SEARCH_STR\" in file $KSYMS_FILE
			;;
		*)
			echo afsd: Malformed kernel version symbol \"$str\"
			;;
		esac

		echo Guessing prefix from output of uname -v
		set X `uname -v`; shift
		case $2 in
		SMP)
			PREFIX=$DEFAULT_SMP_PREFIX
			;;
		esac
		;;
	esac
}

MODLOADDIR=${MODLOADDIR:-/usr/vice/etc/modload}
# load_client loads the AFS client module if it's not already loaded. 
load_client() {
	# If LIBAFS is set, use it.
	if [ -z "$LIBAFS" ] ; then
		# Try to determine the right client.
		choose_client
	fi
    
	if [ ! -f "$MODLOADDIR/$LIBAFS" ] ; then
		echo AFS module $MODLOADDIR/$LIBAFS does not exist. Not starting AFS.
		exit 1
	fi

	# We need exportfs in order to access the cache files. Load it, but
	# ignore errors as on some machines it may be built in to the kernel,
	# not a module
	/sbin/modprobe exportfs >/dev/null 2>&1

	if [ -f $KSYMS_FILE ]; then
		# use the prefix command if required
		case $KERNEL_VERSION in
		  [1-2].[0-5].*)
			set_prefix
			/sbin/insmod ${PREFIX:+-P $PREFIX} -f -m $MODLOADDIR/$LIBAFS > $MODLOADDIR/libafs.map 2>&1
			;;
		  *)
			/sbin/insmod $MODLOADDIR/$LIBAFS > $MODLOADDIR/libafs.map 2>&1
			;;
		esac
	else
		/sbin/insmod $MODLOADDIR/$LIBAFS > $MODLOADDIR/libafs.map 2>&1
	fi
}

generate_cacheinfo() {
    if [ "$CACHESIZE" = "AUTOMATIC" ]; then
	LINE=`df -k $CACHE | tail -1`
	PART=`echo $LINE | awk '{ if ( ($NF != "/usr")  && ($NF != "/") ) print $NF; else print "NONE";}'`
	if [ "$PART" = "NONE" ]; then
	    echo "$CACHE or /usr/vice is not a separate partition"
	    echo "you have to change the cachesize in $SYSCNF by hand"
	    echo "AFS will be started with a VERY small cache of 8Mb."
	    CACHESIZE=8000
	else
	    # Check to see if df has pretty-printed for long dev (i.e. LVM)
            FCHAR=`echo $LINE | cut -c 1`
            if [ "$FCHAR" = "/" ]; then
                PARTSIZE=`echo $LINE | awk '{print $2}'`
            else
                PARTSIZE=`echo $LINE | awk '{print $1}'`
	    fi
	    CACHESIZE=`echo $PARTSIZE | awk '{printf "%d",int(($1*.8)/1000)*1000}'`
	fi
    fi
    if [ "x$CACHESIZE" != "x" ]; then
	echo $AFS:$CACHE:$CACHESIZE >$CACHEINFO
	chmod 0644 $CACHEINFO
    else
	CACHESIZE=`awk -F: '{print $3}' < $CACHEINFO`
    fi
}

choose_afsdoptions() {
	if [ -z "$OPTIONS" -o "$OPTIONS" = "AUTOMATIC" ]; then
		if [ $CACHESIZE -lt 131072 ]; then
			OPTIONS=$SMALL
		elif [ $CACHESIZE -lt 524288 ]; then
			OPTIONS=$MEDIUM
		elif [ $CACHESIZE -lt 1048576 ]; then
			OPTIONS=$LARGE
		elif [ $CACHESIZE -lt 2097152 ]; then
			OPTIONS=$XLARGE
		else
			OPTIONS=$XXLARGE
		fi
	fi
	AFSD_OPTIONS="$OPTIONS $VERBOSE"
	if is_on $ENABLE_AFSDB; then
		AFSD_OPTIONS="$AFSD_OPTIONS -afsdb"
	fi
	if is_on $ENABLE_DYNROOT; then
		AFSD_OPTIONS="$AFSD_OPTIONS -dynroot"
	fi
}

case "$1" in 
  start)
    if [ ! "$afs_rh" -o ! -f /var/lock/subsys/afs ]; then
        if [ `echo "$OPTIONS" | grep -c dynroot` = 0 ]; then
            on_network || exit 1
        fi
	# Load kernel extensions
	if  load_client  ; then :
	else
		echo Failed to load AFS client, not starting AFS services.
		exit 1
	fi

	echo "Starting AFS services..... "
	# Start bosserver, it if exists
	if  is_on $AFS_SERVER && test -x $BOSSERVER  ; then
		$BOSSERVER 
		test "$afs_rh" && touch /var/lock/subsys/afs
		if is_on $WAIT_FOR_SALVAGE; then
			# wait for fileserver to finish salvaging
			sleep 10
			while $BOS status localhost fs 2>&1 | grep 'Auxiliary.*salvaging'; do
				echo "Waiting for salvager to finish..... "
				sleep 10
			done
		fi
	fi

	# Start AFS client
	if  is_on $AFS_CLIENT && test -x $AFSD  ; then
		generate_cacheinfo
		choose_afsdoptions
		$AFSD ${AFSD_OPTIONS}
		test "$afs_rh" && touch /var/lock/subsys/afs
		$AFS_POST_INIT
	fi
    fi
	;;

  stop)
    if [ ! "$afs_rh" -o -f /var/lock/subsys/afs ]; then
	# Stop AFS
	echo "Stopping AFS services..... "

	if  is_on $AFS_CLIENT  ; then
		if [ -x $KILLAFS ] ; then
			runcmd "Sending all processes using /afs the TERM signal ..." $KILLAFS TERM
			runcmd "Sending all processes using /afs the KILL signal ..." $KILLAFS KILL
		fi
		umount /afs
	fi

	if  is_on $AFS_SERVER && test -x $BOS ; then
		echo "Stopping AFS bosserver"
		$BOS shutdown localhost -localauth -wait
		killall -HUP bosserver
	fi

	LIBAFS=`/sbin/lsmod | fgrep libafs`
	if [ -n "$LIBAFS" ] ; then
		LIBAFS=`echo $LIBAFS | awk 'BEGIN { FS = " " } { print $1 }'`
		/sbin/rmmod $LIBAFS
	fi

	rm -f /var/lock/subsys/afs
    fi
	;;

  restart)
	# Restart AFS
	$0 stop
	$0 start
	;;

  *)
	echo Usage: 'afs <start|stop|restart>'

esac

exit 0

action fool the Red Hat initscripts
