#!/bin/sh

# Generic cross-platform init script logic
# Copyright (c) Likewise Software, Inc.
# All rights reserved.
#
# Authors: Jerry Carter (gcarter@likewisesoftware.com)
#          Kyle Stemen (kstemen@likewisesoftware.com)
#          Brian Koropoff (bkoropoff@likewisesoftware.com)

# Implict arguments to this script when sourced:
#
# PROG_DESC - English description of program/service
# PROG_BIN - path to the program binary
# PROG_ARGS - additional arguments to pass to program on startup
# PROG_ERR - file where error diagnostics are logged
# PIDFILE - file where pid is stored (or empty/unset if a pid file is not created)
# SCRIPTNAME - the name of the init script

## Have to set the path for HP-UX boot process
PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
export PATH

alias_replacement()
{
    # Simulates the alias builtin function. It does this by creating a function
    # with the name of what should be aliased. So if it was run like this:
    #   alias_replacement myecho='echo my'
    # Then the alias would be emulated like this:
    #   myecho()
    #   {
    #      echo my "$@"
    #   }
    if [ "$#" -ne 1 ]; then
        echo "alias takes 1 argument"
        return 1
    fi
    # This function is passed something like abc=xyz . The name variable gets
    # set to abc, and value gets set to xyz .
    name="`expr "$1" : '^\(.*\)='`"
    value="`expr "$1" : '.*=\(.*\)$'`"
    eval "$name() { $value \"\$@\"; }"
}

alias aliastest=echo
type aliastest 1>/dev/null 2>/dev/null
alias_works=$?

_test_alias() { false; }
alias _test_alias="true"
case a in a) _test_alias; alias_case_works=$?;; esac
eval '_test_alias >/dev/null 2>&1'
alias_eval_works=$?

if [ $alias_works -ne 0 -o $alias_case_works -ne 0 ]
then
    ( alias() { true; } ) >/dev/null 2>&1
    can_overwrite_builtins=$?
    unset alias >/dev/null 2>&1

    if [ $alias_eval_works -eq 0 -a $can_overwrite_builtins -ne 0 ]; then
        # This is HP-UX. The alias command only takes effect when the file
        # is read. Furthermore, HP-UX won't let us redefine shell
        # builtins as system functions. So we'll have to alias
        # whatever shell builtins we need to now, and reread the file. The
        # alias_replacement function can realias the shell builtins after
        # they are renamed.
        echo_rename()
        {
            echo "$@"
        }
        alias echo=echo_rename
        alias alias=alias_replacement
        # It would cause problems if these aliases are left around for
        # when this script is resourced.
        unalias _test_alias
        unalias aliastest
        # Resource this script
        . /opt/likewise/bin/init-base.sh
        exit $?
    fi

    # This platform doesn't have a working alias (at all). It needs to be
    # replaced. This is primarily for Solaris and FreeBSD.
    alias()
    {
        alias_replacement "$@"
    }
fi


##
## Determine what platform we are on
##
PLATFORM=""
if [ -f /etc/init.d/functions ]; then
    . /etc/init.d/functions
    PLATFORM="REDHAT"
elif [ -f /etc/rc.status ]; then
    . /etc/rc.status
    PLATFORM="SUSE"
elif [ -f /etc/debian_version ]; then
    . /lib/lsb/init-functions
    PLATFORM="DEBIAN"
elif [ "`uname -s`" = 'AIX' ]; then
    PLATFORM="AIX"
elif [ "`uname -s`" = 'HP-UX' ]; then
    PLATFORM="HP-UX"
elif [ "`uname -s`" = 'SunOS' ]; then
    PLATFORM="SOLARIS"
elif [ "`uname -s`" = 'VMkernel' ]; then
    PLATFORM="ESXI"
elif [ "`uname`" = "FreeBSD" -o "`uname`" = "Isilon OneFS" ]; then
    PLATFORM="FREEBSD"
else
    PLATFORM="UNKNOWN"
fi

if [ -f /etc/rc.subr ]; then
    . /etc/rc.subr
fi

if [ $PLATFORM = "HP-UX" -o $PLATFORM = "SOLARIS" -o $PLATFORM = "FREEBSD" ]; then
    LOCKFILE="/var/run/${SCRIPTNAME}.lock"
else
    LOCKFILE="/var/lock/subsys/${SCRIPTNAME}"
fi

type printf 1>/dev/null 2>/dev/null
if [ $? -ne 0 ]; then
    # Usually printf is a shell built in, but on HPUX it is a program located
    # at /bin/printf. During system startup and shutdown the path is only
    # /sbin, so we need to manually find printf
    if [ -x /bin/printf ]; then
        alias printf=/bin/printf
    else
        echo "WARNING: unable to find printf program"
    fi
fi

# echo_replacement emulates echo for all platforms using printf. printf is a
# shell builtin that exists on all platforms.
echo_replacement()
{
    if [ "$1" = "-n" ]; then
        shift;
        printf %s "$*"
    else
        printf %s\\n "$*"
    fi
}

# 'echo -n' works with bash, but not with sh on Solaris, HPUX, and AIX.
if [ "`echo -n`" = "-n" ]; then
    alias echo=echo_replacement
fi

seq_replacement()
{
    FIRST=1
    INCREMENT=1
    case "$#" in
        0)
            echo too few arguments
            return 1
            ;;
        1)
            LAST="$1"
            ;;
        2)
            FIRST="$1"
            LAST="$2"
            ;;
        3)
            FIRST="$1"
            INCREMENT="$2"
            LAST="$3"
            ;;
        *)
            echo too many arguments
            return 1
            ;;
    esac
    i="$FIRST"
    while [ "$i" -le "$LAST" ]; do
        echo "$i"
        i="`expr "$i" + "$INCREMENT"`"
    done
    return 0;
}

# seq doesn't exist on HPUX or FreeBSD
type seq 2>/dev/null 1>/dev/null
if [ $? -ne 0 ]; then
    alias seq=seq_replacement
fi

##
## small wrapper functions around distro specific calls
##

status_success() {
    case "${PLATFORM}" in 
        REDHAT)
            echo_success
            echo
            ;;
        SUSE)
            rc_reset
            rc_status -v
            ;;
        DEBIAN)
            ;;
        AIX | HP-UX | SOLARIS | FREEBSD | ESXI | UNKNOWN)
            echo "...ok"
            ;;
    esac
}

status_failed() {
    status=$1
    case "${PLATFORM}" in 
        REDHAT)
            echo_failure
            echo
            ;;
        SUSE)
            rc_failed $status
            rc_status -v
            ;;
        DEBIAN)
            ;;
        AIX | HP-UX | SOLARIS | ESXI | UNKNOWN)
            echo "...failed"
            ;;
    esac
}

print_status () {
    status=$1

    if [ $status = 0 ]; then
        status_success
    else
        status_failed $status
    fi
}

generic_status()
{
    #Uses return codes specified in
    # http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
    pids="`generic_pid`"
    #Take the list of pids and get just the last one
    pid=""
    for i in $pids; do
        pid="$i"
    done

    if [ -n "$pid" ]
    then
        #Is the pid valid?
        #Does the program with that pid match our program name?
        #HP-UX needs UNIX95 set to support the -o option
        if [ "${PLATFORM}" = "ESXI" ]; then
	if kill -0 $pid > /dev/null 2>&1 ; then
		# pid is valid. have to assume it's the right program
		return 0
	else
		return 1
	fi
        fi
	pid_comm="`UNIX95=1 ps -p "$pid" -o args= 2>/dev/null | awk '{print $1}'`"
	if [ "$pid_comm" = "<defunct>" ]; then
            #It is a zombie process
            return 4
	fi
	if [ "$pid_comm" = "${PROG_BIN}" ]; then
            #If the system keeps cmdline files, check it
            if [ -f /proc/${pid}/cmdline ]; then
                #We can't check the exe file because we may be looking
                #at a version of the program that has been overwritten
		grep -q ${PROG_BIN} /proc/${pid}/cmdline && return 0
            else
		return 0
            fi
	fi
	
        #Program is dead, but lock file exists
	[ -f "${LOCKFILE}" ] && return 2
	
        #Program is dead, but pid file exists
	return 1
    else
	return 3
    fi
}

generic_pid()
{
    if [ -n "${PIDFILE}" -a -f "${PIDFILE}" ]
    then
	cat "${PIDFILE}"
    else
	case "${PLATFORM}" in
	    FREEBSD)
		pgrep -f "^${PROG_BIN}"
		;;
	    ESXI)
		( ps | grep "^[0-9]* [0-9]* `basename ${PROG_BIN}` *${PROG_BIN}" | awk '{ print $1 };' | head -1 )
		;;
	    HP-UX)
		( UNIX95= ps -e -o pid= -o args= | grep "^ *[0123456789]* *${PROG_BIN}" | awk '{ print $1 };' )
		;;
	    *)
		( UNIX95=1; ps -e -o pid= -o args= | grep "^ *[0123456789]* *${PROG_BIN}" | awk '{ print $1 };' )
		;;
	esac
    fi
}

daemon_start() {

    if [ -f "${PROG_ERR}" ]; then
	/bin/rm -f $PROG_ERR;
    fi

    if [ -n "${STARTHOOK}" ]; then
	${STARTHOOK}
    fi

    case "${PLATFORM}" in 
        REDHAT)
            echo -n $"Starting `basename ${PROG_BIN}`: "
            daemon ${PROG_BIN} ${PROG_ARGS}
            status=$?
            ;;
        SUSE)
            echo -n "Starting $PROG_DESC"
            startproc ${PROG_BIN} ${PROG_ARGS}
            status=$?
            ;;
        DEBIAN)
            log_daemon_msg "Starting $PROG_DESC" "`basename $PROG_BIN`"
            start-stop-daemon --start --exec ${PROG_BIN} -- ${PROG_ARGS}
            status=$?
            log_end_msg $status
            sleep 1
            ;;
        AIX)
            echo -n "Starting $PROG_DESC"
            if (lssrc -s dhcpcd | grep active >/dev/null); then
                # Wait up to 30 seconds for an ip address
                for i in `seq 30`; do
                    ifconfig -a | grep inet | grep -v 127.0.0 | grep -v 0.0.0.0 | grep -v ::1/0 >/dev/null && break
                    sleep 1
                done
            fi
            ${PROG_BIN} ${PROG_ARGS}
            status=$?
            if [ $status -eq 0 ]; then
                status=1
                for i in `seq 5`; do
                    #Did the program start?
                    generic_status
                    status=$?
                    [ $status -eq 0 ] && break
                    sleep 1
                done
            fi
            ;;
        HP-UX | SOLARIS | FREEBSD | ESXI)
            echo -n "Starting $PROG_DESC"
            if [ ${PLATFORM} = "ESXI" ]; then
                # reduce default stack size
                ulimit -s 100
                # start likewise in resource pool
                ${PROG_BIN} ${PROG_SCHED_PARAM} ${PROG_ARGS}
            else
                ${PROG_BIN} ${PROG_ARGS}
            fi
            status=$?
            if [ $status -eq 0 ]; then
                status=1
                for i in `seq 5`; do
                    #Did the program start?
                    generic_status
                    status=$?
                    [ $status -eq 0 ] && break
                    sleep 1
                done
            fi
            ;;
        UNKNOWN)
            ${PROG_BIN} ${PROG_ARGS}
            status=$?
            ;;
    esac

    if [ -n "${POSTSTARTHOOK}" ]; then
	${POSTSTARTHOOK}
    fi

    [ $status = 0 ] && [ ${PLATFORM} != "DEBIAN" ] && touch ${LOCKFILE}
    return $status
}

daemon_stop() {
    case "${PLATFORM}" in 
        REDHAT)
            echo -n $"Stopping `basename ${PROG_BIN}`: "
            killproc `basename ${PROG_BIN}`
            status=$?
            ;;
        SUSE)
            echo -n "Stopping $PROG_DESC "
            killproc -TERM ${PROG_BIN}
            status=$?
            ;;
        DEBIAN)
            log_daemon_msg "Stopping $PROG_DESC " "`basename $PROG_BIN`"
            status=1
            #only try to stop the daemon if it is running
            if generic_status; then
                kill -TERM "`generic_pid`"
		# Forget our pidfile since it will now be invalid
		# if is still present.  This means generic_status
		# will fall back on ps to see if the daemon is still
		# running.  This is important on LinuxThreads-based
		# systems where other threads can still be in the process
		# of shutting down even when the main thread has exited
		PIDFILE=""
                #Wait up to 5 seconds for the program to end
                for i in `seq 5`; do
                    #Did the program end?
                    generic_status
                    # Make sure the agent is not running and is not a zombie
                    # process.
                    [ $? -ne 0 -a $? -ne 4 ] && status=0 && break
                    # use the following line instead after bug 3634 is fixed
                    #[ $? -eq 3 -o $? -eq 2 ] && status=0 && break
                    sleep 1
                done
            fi
            log_end_msg $status
            ;;
        AIX | HP-UX | SOLARIS | FREEBSD | ESXI)
            echo -n "Stopping $PROG_DESC"
            status=1
            #only try to stop the daemon if it is running
            if generic_status; then
                pid="`generic_pid`"
                kill -TERM $pid

                #Wait up to 5 seconds for the program to end
                for i in `seq 5`; do
                    #Did the program end?
                    generic_status
                    # Make sure the agent is not running and is not a zombie
                    # process.
                    [ $? -ne 0 -a $? -ne 4 ] && status=0 && break
                    # use the following line instead after bug 3634 is fixed
                    #[ $? -eq 3 -o $? -eq 2 ] && status=0 && break
                    sleep 1
                done
            fi
            ;;
        UNKNOWN)
            killall -TERM `basename ${PROG_BIN}`
            status=$?
            ;;
    esac

    [ $status = 0 ] && /bin/rm -f ${LOCKFILE}
    return $status
}

daemon_status() {
    case "${PLATFORM}" in
        REDHAT)
            status ${PROG_BIN}
            ;;
        SUSE)
            checkproc ${PROG_BIN}
            rc_status -v
            ;;
        AIX | HP-UX | SOLARIS | DEBIAN | FREEBSD | ESXI)
            generic_status
            status=$?
            case "$status" in
                0)
                    echo "running";
                    ;;
                1)
                    echo "stopped";
                    #Use the bellow line instead after bug 3634 is fixed
                    #echo "died leaving pid file";
                    ;;
                2)
                    echo "died leaving lock file";
                    ;;
                3)
                    echo "stopped";
                    ;;
            esac
            return $status
        ;;
        UNKNOWN)
            echo "Not implemented."
            ;;
    esac
}

#Sends the signal specified by the first parameter to all instances
#of $PROG_BIN
generic_killall()
{
    #This gets the list of all current running instances of PROG_BIN,
    #but it can't tell which directory the program was run from. If
    #cmdline is available in the proc pseudo-filesystem, we'll verify
    #the pids.
    unverified_pids=`generic_pid`
    pids=
    for pid in $unverified_pids; do
        #If the system keeps cmdline files, check them
        if [ -f /proc/${pid}/cmdline ]; then
            #We can't check the exe file because we may be looking
            #at a version of the program that has been overwritten
            grep -q ${AUTHD_BIN} /proc/${pid}/cmdline && pids="$pids $pid"
        else
            pids="$pids $pid"
        fi
    done

    for pid in $pids; do
        [ ! -z "`UNIX95=1 ps -p $pid -o pid=`" ] && kill "$1" $pid
    done

    #The manpage of killall says it returns 0 if at least one process is
    #killed. I can't get it to return anything other than 0. Even if no
    #processes die with SIGTERM. We'll just return 0 here too
    return 0
}

####################################################################
## Main init script code
##

if type run_rc_command >/dev/null 2>&1; then
    # Looks like this is a FreeBSD based system. We should use their arg
    # parsing instead of our own.
    name="$SCRIPTNAME"
    rcvar="`set_rcvar`"
    command="$PROG_BIN"
    command_args="$PROG_ARGS"
    pidfile="$PIDFILE"
    eval "${name}_enable=YES"

    load_rc_config "$name"
    [ "$1" = "start" -a -n "${STARTHOOK}" ] && ${STARTHOOK}
    run_rc_command "$1" || exit $?
    [ "$1" = "start" -a -n "${POSTSTARTHOOK}" ] && ${POSTSTARTHOOK}
    exit 0
fi

case "$1" in 
    start)
        daemon_start
        ret=$?
        print_status $ret
        ;;

    stop)
        daemon_stop
        ret=$?
        print_status $ret
        ;;

    # HP-UX calls this
    stop_msg)
        echo "Stopping $PROG_DESC"
        exit 0
        ;;

    # HP-UX calls this
    start_msg)
        echo "Starting $PROG_DESC"
        exit 0
        ;;

    restart)
        daemon_stop
        ret=$?
        print_status $ret
        daemon_start
        ret=$?
        print_status $ret
        ;;
        
    status)
        daemon_status
        ;;

    reload)
        echo -n "Reloading $PROG_DESC configuration file"
        if [ ${PLATFORM} = "AIX" -o ${PLATFORM} = "HP-UX" -o ${PLATFORM} = "SOLARIS" ]; then
            #killall on AIX cannot search for a program name. We have to use
            #our own
            generic_killall -HUP
        else
            killall -HUP `basename ${PROG_BIN}`
        fi

        ret=$?
        print_status $ret
        ;;

    *)
        echo "Usage: $0 {start|stop|restart|status|reload}"
        exit 1
        ;;
esac
