#! /bin/bash
#
# BDII system startup script
# $Id: bdii,v 1.9 2009/06/18 14:26:52 lfield Exp $
# chkconfig: - 95 5
# description: BDII Service
# config: /etc/bdii/bdii.conf

### BEGIN INIT INFO
# Provides:          bdii
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Stop:      0 1 2 3 4 5 6
# Short-Description: BDII
# Description:       Berkeley Database Information Index
### END INIT INFO

shopt -s expand_aliases

if [ -f /etc/init.d/functions ]; then
    . /etc/init.d/functions
else
    echo "Error: Cannot source /etc/init.d/functions"
fi

log_success_msg ()
{
  success
  echo
}

log_failure_msg()
{
  failure
  echo
}

prog=bdii

# Debian does not have /run/lock/subsys
if [ -d /run/lock/subsys ] ; then
    LOCK_DIR=/run/lock/subsys
else
    LOCK_DIR=/run/lock
fi

lockfile=${LOCK_DIR}/$prog    # TODO is it necessary??

RUN=yes

if [ -r /etc/default/bdii ] ; then
    . /etc/default/bdii
fi
if [ -r /etc/sysconfig/bdii ] ; then
    . /etc/sysconfig/bdii
fi

if [ "x$RUN" != "xyes" ] ; then
    echo "bdii disabled, please adjust the configuration to your needs "
    echo "and then set RUN to 'yes' in /etc/default/bdii to enable it."
    exit 0
fi

BDII_CONF=${BDII_CONF:-/etc/bdii/bdii.conf}

if [ -f "${BDII_CONF}" ]; then
    . "${BDII_CONF}"
fi

UPDATE_LOCK_FILE=${UPDATE_LOCK_FILE:-${LOCK_DIR}/bdii-update}
SLAPD_LOCK_FILE=${SLAPD_LOCK_FILE:-${LOCK_DIR}/bdii-slapd}
UPDATE_PID_FILE=${BDII_PID_FILE:-/run/bdii/bdii-update.pid}
BDII_USER=${BDII_USER:-ldap}
BDII_VAR_DIR=${BDII_VAR_DIR:-/var/lib/bdii}
BDII_UPDATE=${BDII_UPDATE:-/usr/sbin/bdii-update}
SLAPD=${SLAPD:-/usr/sbin/slapd}
SLAPD_CONF=${SLAPD_CONF:-/etc/bdii/bdii-slapd.conf}
SLAPD_HOST=${SLAPD_HOST:-0.0.0.0}
SLAPD_PORT=${SLAPD_PORT:-2170}
BDII_IPV6_SUPPORT=${BDII_IPV6_SUPPORT:-no}
SLAPD_HOST6=${SLAPD_HOST6:-::}
SLAPD_DB_DIR=${SLAPD_DB_DIR:-$BDII_VAR_DIR/db}
SLAPD_PID_FILE=${SLAPD_PID_FILE:-/run/bdii/db/slapd.pid}
DB_CONFIG=${DB_CONFIG:-/etc/bdii/DB_CONFIG}
DELAYED_DELETE=${DELAYED_DELETE:-${BDII_VAR_DIR}/delayed_delete.pkl}
BDII_RAM_SIZE=${BDII_RAM_SIZE:-1500M}


if [ "x${BDII_IPV6_SUPPORT}" == "xyes" ]; then 
   SLAPD_HOST_STRING="'ldap://${SLAPD_HOST}:${SLAPD_PORT} ldap://[${SLAPD_HOST6}]:${SLAPD_PORT}'" 
else
   SLAPD_HOST_STRING="ldap://${SLAPD_HOST}:${SLAPD_PORT}"
fi

if [ -x /sbin/runuser ] ; then
    RUNUSER=/sbin/runuser
else
    RUNUSER=su
fi

# Return code
# 0 process is running
# 1 process has been stopped (correctly)
# 2 process has been aborted
function check_slapd(){
    if [ ! -f "${SLAPD_PID_FILE}" ] ; then
        [ ! -f "${SLAPD_LOCK_FILE}" ] || return 2
        return 1
    fi
    ps $(cat ${SLAPD_PID_FILE}) >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        return 0
    fi
    if [ -n "${1}" -a "${1}" == "reset" ]; then
        rm -f ${SLAPD_PID_FILE}
        rm -f ${SLAPD_LOCK_FILE}
    fi
    return 2
}

function check_updater(){
    if [ ! -f "${UPDATE_PID_FILE}" ]; then
        [ ! -f "${UPDATE_LOCK_FILE}" ] || return 2
        return 1
    fi
    ps $(cat ${UPDATE_PID_FILE}) >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        return 0
    fi
    if [ -n "${1}" -a "${1}" == "reset" ]; then
        rm -f ${UPDATE_PID_FILE}
        rm -f ${UPDATE_LOCK_FILE}
    fi
    return 2
}

function check_updater_hanging(){
    # Check for hanging process
    response=$(ldapsearch -LLL -x -h ${SLAPD_HOST} -p ${SLAPD_PORT} -b o=infosys objectClass=UpdateStats modifyTimestamp 2>/dev/null | grep modifyTimestamp )
    if [ $? -eq 0 ]; then
	    time_stamp=$(echo ${response} | cut -d" " -f2)
	    time_string=$(echo ${time_stamp} | sed 's/^\([0-9][0-9][0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\).*/\1-\2-\3 \4:\5/')
	    time_int=$(date --utc --date "${time_string}" +%s)
	    let time_threshold=${time_int}+1200
	    time_now=$(date --utc +%s)
	    if [ ${time_now} -gt ${time_threshold} ]; then
	        return 1
	    fi
    fi
    return 0   # TODO failsafe?
}

function start(){

    # Check status
    check_slapd reset
    RETVAL1=$?

    check_updater reset
    RETVAL2=$?

    if [ $RETVAL1 -eq 0 -a $RETVAL2 -eq 0 ] ; then
        echo "BDII already started"
        exit 0
    fi

    # Create RAM Disk
    if [ "${BDII_RAM_DISK}" = "yes" ]; then
	mkdir -p ${SLAPD_DB_DIR}
	mount -t tmpfs -o size=${BDII_RAM_SIZE},mode=0744 tmpfs ${SLAPD_DB_DIR}
    fi

    # Remove delayed_delete.pkl if it exists
    if [ -f "${DELAYED_DELETE}" ] ; then
	rm -f ${DELAYED_DELETE}
    fi

    #Initialize the database directory.
    mkdir -p ${SLAPD_DB_DIR}/stats
    mkdir -p ${SLAPD_DB_DIR}/glue
    mkdir -p ${SLAPD_DB_DIR}/grid
    mkdir -p ${BDII_VAR_DIR}/archive

    chown -R ${BDII_USER}:${BDII_USER} ${BDII_VAR_DIR}
    chown -R ${BDII_USER}:${BDII_USER} ${SLAPD_DB_DIR}
    [ -x /sbin/restorecon ] && /sbin/restorecon -R ${BDII_VAR_DIR}

    mkdir -p /run/bdii/db
    chown -R ${BDII_USER}:${BDII_USER} /run/bdii
    [ -x /sbin/restorecon ] && /sbin/restorecon -R /run/bdii/db

    $RUNUSER -s /bin/sh ${BDII_USER} -c "rm -f ${SLAPD_DB_DIR}/stats/* 2>/dev/null"
    $RUNUSER -s /bin/sh ${BDII_USER} -c "rm -f ${SLAPD_DB_DIR}/glue/* 2>/dev/null"
    $RUNUSER -s /bin/sh ${BDII_USER} -c "rm -f ${SLAPD_DB_DIR}/grid/* 2>/dev/null"
    $RUNUSER -s /bin/sh ${BDII_USER} -c "rm -f ${BDII_VAR_DIR}/old.ldif 2>/dev/null"
    $RUNUSER -s /bin/sh ${BDII_USER} -c "ln -sf ${DB_CONFIG} ${SLAPD_DB_DIR}/grid/"
    $RUNUSER -s /bin/sh ${BDII_USER} -c "ln -sf ${DB_CONFIG} ${SLAPD_DB_DIR}/stats/"
    $RUNUSER -s /bin/sh ${BDII_USER} -c "ln -sf ${DB_CONFIG} ${SLAPD_DB_DIR}/glue/"
 
    if [ ${SLAPD_CONF} = "/etc/bdii/bdii-top-slapd.conf" ] ; then
	$RUNUSER -s /bin/sh ${BDII_USER} -c "ln -sf ${DB_CONFIG}_top ${SLAPD_DB_DIR}/grid/DB_CONFIG"
	$RUNUSER -s /bin/sh ${BDII_USER} -c "ln -sf ${DB_CONFIG}_top ${SLAPD_DB_DIR}/stats/DB_CONFIG"
	$RUNUSER -s /bin/sh ${BDII_USER} -c "ln -sf ${DB_CONFIG}_top ${SLAPD_DB_DIR}/glue/DB_CONFIG"
        $RUNUSER -s /bin/sh ${BDII_USER} -c "rm -f ${BDII_VAR_DIR}/gip/cache/gip/top-urls.conf/* 2>/dev/null"
        $RUNUSER -s /bin/sh ${BDII_USER} -c "rm -f ${BDII_VAR_DIR}/gip/cache/gip/top-urls.conf-glue2/* 2>/dev/null"
    else
        if [ -r "${BDII_VAR_DIR}/gip/cache" ]; then
             $RUNUSER -s /bin/sh ${BDII_USER} -c "rm -f ${BDII_VAR_DIR}/gip/cache/gip/site-urls.conf/* 2>/dev/null"
             $RUNUSER -s /bin/sh ${BDII_USER} -c "rm -f ${BDII_VAR_DIR}/gip/cache/gip/site-urls.conf-glue2/* 2>/dev/null" 
        fi
    fi

    if [ $RETVAL1 -ne 0 ] ; then
        cd /tmp

        echo -n "Starting BDII slapd: "
        COMMAND="${SLAPD} -f ${SLAPD_CONF} -h ${SLAPD_HOST_STRING} -u ${BDII_USER}"
        eval ${COMMAND}
        touch ${SLAPD_LOCK_FILE}
        [ -f "${SLAPD_PID_FILE}" ] || sleep 2

        check_slapd reset
        RETVAL=$?

        if [ ${RETVAL} -gt 0 ]; then
            echo -n "BDII slapd failed to start" 1>&2
            eval log_failure_msg

            # TODO check a sysconfig option DEBUG_MODE
            echo "${COMMAND} -d 256"
            ${COMMAND} -d 256
            return 1
        else
            eval log_success_msg
        fi
    fi

    if [ $RETVAL2 -ne 0 ] ; then
        cd /tmp

        echo -n "Starting BDII update process: "
        export SLAPD_CONF=${SLAPD_CONF}
        $RUNUSER -s /bin/sh ${BDII_USER} -c "sh -l -c '${BDII_UPDATE} -c ${BDII_CONF} -d'"
        touch ${UPDATE_LOCK_FILE}
        [ -f ${UPDATE_PID_FILE} ] || sleep 2

        check_updater reset
        RETVAL=$?

        if [ ${RETVAL} -gt 0 ]; then
            echo -n "BDII update process failed to start" 1>&2
            eval log_failure_msg
            return 1
        else
            eval log_success_msg
        fi
    fi

    touch $lockfile
    return 0
}

function stop(){

    check_slapd
    RETVAL1=$?

    check_updater
    RETVAL2=$?

    RETVAL=0

    echo -n "Stopping BDII update process: "

    if [ $RETVAL1 -gt 0 ] ; then
        echo -n "already stopped" 1>&2
        eval log_success_msg
    else
        UPDATE_PID=$(cat ${UPDATE_PID_FILE})

        $RUNUSER -s /bin/sh ${BDII_USER} -c "kill -15 ${UPDATE_PID} 2>/dev/null"
        ps ${UPDATE_PID} >/dev/null 2>&1
        if [ $? = 0 ]; then
            sleep 2
            ps ${UPDATE_PID} >/dev/null 2>&1
            if [ $? = 0 ]; then
                $RUNUSER -s /bin/sh ${BDII_USER} -c "kill -9 ${UPDATE_PID} 2>/dev/null"
                sleep 2
                ps ${UPDATE_PID} >/dev/null 2>&1
                if [ $? = 0 ]; then
                    echo -n "Could not kill BDII update process ${UPDATE_PID}" 1>&2
                    eval log_failure_msg
                    RETVAL=1
                fi
            fi
        fi

        if [ ${RETVAL} = 0 ];  then
            rm -f ${UPDATE_PID_FILE}
            rm -f ${UPDATE_LOCK_FILE}
            eval log_success_msg
        fi
    fi

    echo -n "Stopping BDII slapd: "

    if [ $RETVAL1 -gt 0 ] ; then
        echo -n "already stopped" 1>&2
        eval log_success_msg
    else
        SLAPD_PID=$(cat ${SLAPD_PID_FILE})

        $RUNUSER -s /bin/sh ${BDII_USER} -c "kill -15 ${SLAPD_PID} 2>/dev/null"
        ps ${SLAPD_PID} >/dev/null 2>&1
        if [ $? = 0 ]; then
            sleep 2
            ps ${SLAPD_PID} >/dev/null 2>&1
            if [ $? = 0 ]; then
                $RUNUSER -s /bin/sh ${BDII_USER} -c "kill -9 ${SLAPD_PID} 2>/dev/null"
                sleep 2
                ps ${SLAPD_PID} >/dev/null 2>&1
                if [ $? = 0 ]; then
                    echo -n "Could not kill BDII slapd process ${SLAPD_PID}" 1>&2
                    eval log_failure_msg
                    RETVAL=2
                fi
            fi
        fi

        if [ ${RETVAL} -ne 2 ];  then
            rm -f ${SLAPD_PID_FILE}
            rm -f ${SLAPD_LOCK_FILE}
            eval log_success_msg
        fi
    fi

    if [ ${RETVAL} -ne 0 ];  then
        return 1
    else
	    mountpoint -q ${SLAPD_DB_DIR} && umount ${SLAPD_DB_DIR}
        rm -f $lockfile
        return 0
    fi
}

function status(){

    check_slapd
    RETVAL1=$?

    check_updater
    RETVAL2=$?

    if [ $RETVAL1 -eq 1 ] ; then
        echo -n "BDII slapd stopped" 1>&2
        eval log_success_msg
    elif [ $RETVAL1 -eq 2 ] ; then
        echo -n "BDII slapd aborted" 1>&2
        eval log_failure_msg
    else
        echo -n "BDII slapd running "
        eval log_success_msg
    fi

    if [ $RETVAL2 -eq 1 ] ; then
        echo -n "BDII updater stopped" 1>&2
        eval log_success_msg
    elif 
        [ $RETVAL2 -eq 2 ] ; then
        echo -n "BDII updater aborted" 1>&2
        eval log_failure_msg
    else
        check_updater_hanging
        RETVAL=$?
        if [ $RETVAL -eq 1 ] ; then
	        echo -n "BDII update process hanging" 1>&2
	        eval log_failure_msg
        else
            echo -n "BDII updater running "
            eval log_success_msg
        fi
    fi

    if [ $RETVAL1 -eq 1 -a $RETVAL2 -eq 1 ] ; then
        return 3
    fi

    if [ $RETVAL1 -eq 2 -o $RETVAL2 -eq 2 ] ; then
        return 1
    fi

    return 0
}

case "$1" in
    start)
        start
        RETVAL=$?
        ;;
    stop)
        stop
        RETVAL=$?
        ;;
    status)
        status
        RETVAL=$?
        ;;
    reload)
        ;;
    restart | force-reload)
        stop
        start
        RETVAL=$?
        ;;
    condrestart | try-restart)
        if [ -f ${SLAPD_LOCK_FILE} ] || [ -f ${UPDATE_LOCK_FILE} ]; then
            stop
            start
            RETVAL=$?
        fi
        ;;
    *)
        echo $"Usage: $0 {start|stop|restart|status|condrestart}"
        RETVAL=1
esac

exit ${RETVAL}
