#! /bin/sh
#
# Copyright (c) 2002-2015 by Symas Corporation
# All rights reserved.
#
# The script will source the file pointed to by $SOL_CONF_FILE,
# which can change any of several variables that control the
# way this script behaves.
#
# LSB-style init information:
### BEGIN INIT INFO
# Provides: slapd
# Required-Start: $network $syslog
# Required-Stop:  $network $syslog
# Default-Start:  
# Default-Stop:   
# Description:    Symas OpenLDAP
### END INIT INFO
#
# chkconfig-style init information:
# chkconfig:  60 60
# description: Symas OpenLDAP

# set path so HP-UX basename is visible for USAGE
PATH=/usr/bin:$PATH
CONF_DIR=/opt/symas/etc/openldap
SOL_CONF_FILE=$CONF_DIR/symas-openldap.conf
SLAPD_CONF_FILE=$CONF_DIR/slapd.conf
SLAPD_CONF_DYNDIR=$CONF_DIR/slapd.d
PROD_NAME="Symas OpenLDAP LDAP services"
USAGE="Usage: `basename $0` {start|stop|status|try-restart|condrestart|restart|force-reload|reload|probe|start_msg|stop_msg} [--gdb {attach|backtrace|core-grab|core-wait|script SCRIPT_PATH}] [-d n]\n"

# Sane values for things that are usually set in
# symas-openldap.conf. They'll be overridden when symas-openldap.conf
# is sourced.
RUN_SLAPD=Y
SLAPD_USER=root
# set SLAPD_GROUP below for AIX/OSX customization
# SLAPD_GROUP=root
HOST_LIST="ldap:///"
SLAPD_TIMEOUT=60

GDB_PATH="`which gdb 2>/dev/null`"
GDB_ARGS="-nx -q"
GDB_EXTRA_ARGS=""
GDB_SCRIPT_DIR="/opt/symas/lib64/gdb"
GDB_ATTACH_SCRIPT="$GDB_SCRIPT_DIR/default_attach.gdb"
GDB_BT_SCRIPT="$GDB_SCRIPT_DIR/all_threads_full_bt.gdb"
GDB_CORE_GRAB="$GDB_SCRIPT_DIR/core_grab.gdb"
GDB_CORE_WAIT="$GDB_SCRIPT_DIR/core_wait.gdb"
GDB_ON_START='N'

SYSTEMCTL=`which systemctl 2>/dev/null`

USAGE="Usage: `basename $0` {start|stop|status|try-restart|condrestart|restart|force-reload|reload|probe|start_msg|stop_msg} [-d n]"
if [ -x "$GDB_PATH" ]; then
  USAGE="$USAGE [--gdb {attach|backtrace|core-grab|core-wait|script SCRIPT_PATH}]\n"
else
  USAGE="$USAGE\n\t\tNote: Unable to find gdb binary so some options are not available for use.\n"
fi

# basic sanity checking
if [ $# -lt 1 ]; then
  echo $USAGE
  exit 1
fi

# What are we running on?
UNAME=`uname`
if [ "$UNAME" = Linux ]; then
  DIST=unknown
  if [ -r /etc/SuSE-release ]; then
    DIST=SuSE
    test -r /etc/rc.config && . /etc/rc.config
    if [ -r /etc/rc.status ]; then
      . /etc/rc.status
      rc_reset
    fi
  fi
  if [ -r /etc/redhat-release ]; then
    DIST=Redhat
    if [ -r /etc/rc.d/init.d/functions ]; then
      . /etc/rc.d/init.d/functions
    fi
      if [ -f /etc/sysconfig/network ] ; then
        . /etc/sysconfig/network
        [ "${NETWORKING}" = "no" ] && exit 0
      fi
  fi
  # Debian requires no specialization at this time
  if [ -r /etc/debian_version ]; then
    DIST=Debian
  fi
fi

if [ "$UNAME" = AIX ]; then
  SLAPD_GROUP=system
elif [ "$UNAME" = Darwin ]; then
  SLAPD_GROUP=wheel
elif [ "$UNAME" = FreeBSD ]; then
  SLAPD_GROUP=wheel
else
  SLAPD_GROUP=root
fi

if [ "$UNAME" = Darwin ]; then
  SU=/usr/bin/su
else
  SU=/bin/su
fi

if [ "$UNAME" = Linux ]; then
  PRELOAD_STMT="LD_PRELOAD=\$SOL_PRELOAD;export LD_PRELOAD"
elif [ "$UNAME" = SunOS ]; then
  PRELOAD_STMT="LD_PRELOAD=\$SOL_PRELOAD;export LD_PRELOAD"
elif [ "$UNAME" = HP-UX ]; then
  PRELOAD_STMT="LD_PRELOAD=\$SOL_PRELOAD;export LD_PRELOAD"
elif [ "$UNAME" = Darwin ]; then
  PRELOAD_STMT="DYLD_INSERT_LIBRARIES=\$SOL_PRELOAD;DYLD_FORCE_FLAT_NAMESPACE=1;export LD_PRELOAD;export DYLD_FORCE_FLAT_NAMESPACE"
fi

# Save off the command and remove it from the cmd line
CMD="$1"
shift

# "portably" echo without a newline
pecho () {
  if [ "x$(echo -n foo\cbar)x" = "x-n foox" ]; then
    # ancient bourne shells only have \c
    echo $1\\c
  elif [ "x$(echo -n foo\\cbar)x" = "x-n foox" ]; then
    # some shells unquote differently
    echo $1\\c
  elif [ "x$(echo -n foo\cbar)x" = "xfoocbarx" ]; then
    # bash likes it csh style
    echo -n $1
  elif [ "x$(echo -n foo\\cbar)x" = "xfoocbarx" ]; then
    # some shells unquote differently
    echo -n $1
  elif [ "$UNAME" = "SunOS" ]; then
    # sun echo works different inside `` or $()
    echo $1\\c
  else
    # ouch
    echo $1
  fi
}

# signal a failure for our UNAME and DIST
exit_failed () {
  if [ "$UNAME" = Linux -a "$DIST" = SuSE ]; then
    rc_failed $1
    rc_status -v
    rc_exit
  elif [ "$UNAME" = Linux -a "$DIST" = Redhat ]; then
    echo_failure
    echo
    exit 1
  else
    echo "...  failed."
    exit 1
  fi
}

# signal failure but exit with success
exit_disabled () {
  echo "...  ignoring."
  exit 0
}

# signal a success for our UNAME and DIST
exit_success () {
  if [ "$UNAME" = Linux -a "$DIST" = SuSE ]; then
    rc_status -v
    rc_exit
  elif [ "$UNAME" = Linux -a "$DIST" = Redhat ]; then
    echo_success
    echo
    exit 0
  else
    echo "...  done."
    exit 0
  fi
}

EXEC_DIR=/opt/symas/lib64
SOL_LIB=/opt/symas/lib64

case `basename $0` in
  *solserver*|*SOLServer*)
    PROC=slapd
    if [ ! -r $SLAPD_CONF_FILE ] && [ ! -d $SLAPD_CONF_DYNDIR ]; then
      pecho "$PROD_NAME $PROC has not been configured"
      exit_disabled
    fi
    ;;

  *)
    pecho "Symas OpenLDAP: $0 is not a recognized link for this script"
    exit_failed 1
    ;;
esac

# Check the current and soon-to-be new default locations for the slapd PID
# file.
PID_FILE=/var/symas/${PROC}.pid

if [ -f /var/symas/run/${PROC}.pid ]; then
  PID_FILE=/var/symas/run/${PROC}.pid
fi

# Determine if Symas OpenLDAP is configured. The installer only installs
# symas-openldap.conf.default, so a missing symas-openldap.conf is an
# indicator no one's configured Symas OpenLDAP. Otherwise, go ahead and
# source the file.
if [ ! -f $SOL_CONF_FILE ]; then
  pecho "$PROD_NAME $PROC has not been configured"
  exit_disabled
else
  . $SOL_CONF_FILE
fi

# Pick up values that may have changed in SOL_CONF_FILE. $* is at the end
# of ARGS so that an alternative -g and -u values can be specified on the
# command line. ARGS gets set again the same way after the GDB code.
RUN=$RUN_SLAPD
ARGS="-u $SLAPD_USER -g $SLAPD_GROUP $*"

# Determine if the daemon is running. This will set the $PID variable
# to the process ID of the proc if it is, otherwise it'll make it zero
# length.
if [ -f $PID_FILE ]; then
  PID=`cat $PID_FILE`
  ps -p $PID | grep $PROC > /dev/null
  if [ "$?" -ne 0 ]; then
    PID=""
  fi
fi

# Set up optional GDB Loading
if [ "$CMD" = '--gdb' -o "$1" = '--gdb' ]; then

  if [ ! -x "$GDB_PATH" ]; then
    pecho "Could not find executable gdb. Is gdb installed?"
    exit_failed 1
  fi

  if [ ! -n "$GDB_SCRIPT_DIR" ]; then
    GDB_SCRIPT_DIR="/opt/symas/lib64/gdb"
  fi

  # TODO: Add support for other methods. e.g. 'restart'. requires refactoring of prior code.
  if [ $CMD = 'start' ]; then

    if [ $# -lt 1 ]; then echo $USAGE; exit_failed 1; fi
    shift

    case "$1" in
      attach|backtrace)
        ARGS_REQ=1
        GDB_MODE_ARGS="--gdb $1"
        ;;

      core-grab)
        pecho "Core Dumps at server start not supported."
        exit_failed 1
        ;;

      core-wait)
        ARGS_REQ=1
        GDB_MODE_ARGS="--gdb $1"
        ;;

      script)
        ARGS_REQ=2
        GDB_MODE_ARGS="--gdb $1 $2"
        ;;
      *)
        echo $USAGE
        exit_failed 1
        ;;
    esac

    GDB_ON_START=Y

    if [ $# -lt $ARGS_REQ ]; then echo $USAGE; exit_failed 1; fi
    shift $ARGS_REQ

  elif [ $CMD = '--gdb' ]; then # Cases where we attach to slapd

    if [ ! -n "$PID" ]; then
      exit_failed 1
    fi

    case "$1" in

      attach)
        GDB_ARGS="$GDB_ARGS -x $GDB_ATTACH_SCRIPT"
        ;;

      backtrace)
        GDB_ARGS="$GDB_ARGS -batch -x $GDB_BT_SCRIPT"
        ;;

      core-grab)
        GDB_ARGS="$GDB_ARGS -x $GDB_CORE_GRAB"
        ;;

      core-wait)
        GDB_ARGS="$GDB_ARGS -x $GDB_CORE_WAIT"
        ;;

      script)
        if [ $# -lt 1 ]; then echo $USAGE; exit_failed 1; fi
        shift

        if [ -f "$1" ]; then
          GDB_SCRIPT="$1"
        elif [ -f "$GDB_SCRIPT_DIR/$1" ]; then
          GDB_SCRIPT="$GDB_SCRIPT_DIR/$1"
        else
          pecho "$USAGE"
          exit_failed 1
        fi

        GDB_ARGS="$GDB_ARGS -batch -x $GDB_SCRIPT"
        ;;

      *)
        pecho "$USAGE"
        exit_failed 1
        ;;

    esac

    $GDB_PATH $GDB_ARGS $GDB_EXTRA_ARGS $EXEC_DIR/$PROC $PID
    if [ $?    -ne 0 ]; then
      pecho "GDB returned error \"$?\". Do you have appropriate privilegess to attach?"
    else
      exit_success
    fi
  fi
fi


#Set ARGS again, in case we shifted off now processed gdb params.
ARGS="-u $SLAPD_USER -g $SLAPD_GROUP $*"


# Now process the command.
case "$CMD" in
  # Display start/stop messages. HP/UX makes these calls
  start_msg)
    echo "Starting $PROD_NAME $PROC"
    ;;
  stop_msg)
    echo "Stopping $PROD_NAME $PROC"
    ;;

  # Start the server
  start)
    # Check the run flag in the Symas OpenLDAP config file. If not set to
    # "Y", then we say "not configured to run" and exit with
    # a status of success.
    # We'll also exit with success if the process is already
    # running, saying "already running".
    if [ "$RUN" != "Y" ]; then
      pecho "$PROD_NAME $PROC is not configured to run"
      exit_success
    elif [ -n "$PID" ]; then
      pecho "$PROD_NAME $PROC is already running"
      exit_success
    fi
    rm -f ${PID_FILE}
    pecho "$PROD_NAME $PROC starting"
    if [ "$PROC" = slapd ]; then
      # Perform a check to see if a preload is being requested and if
      # preloading is supported.
      if [ -n "$SOL_PRELOAD" -a -z "$PRELOAD_STMT" ]; then
        pecho "$PROD_NAME: pre-loading is not supported on this platform."
        exit_failed 1
      elif [ -n "$SOL_PRELOAD" ]; then
        eval $PRELOAD_STMT
      fi
      if [ -x "$SYSTEMCTL" ]; then
        $SYSTEMCTL start slapd
      else
        "$EXEC_DIR/$PROC" $ARGS -h "$HOST_LIST" $EXTRA_SLAPD_ARGS
      fi
    fi
    ;;

  # This option is for systemd enabled systems only.  It bypasses systemd
  # and starts the daemon directly with optional flags (primarily for debug
  # purposes).
  debug-start)
    # Check the run flag in the Symas OpenLDAP config file. If not set to
    # "Y", then we say "not configured to run" and exit with
    # a status of success.
    # We'll also exit with success if the process is already
    # running, saying "already running".
    if [ "$RUN" != "Y" ]; then
      pecho "$PROD_NAME $PROC is not configured to run"
      exit_success
    elif [ -n "$PID" ]; then
      pecho "$PROD_NAME $PROC is already running"
      exit_success
    fi
    rm -f ${PID_FILE}
    pecho "$PROD_NAME $PROC starting"
    if [ "$PROC" = slapd ]; then
      # Perform a check to see if a preload is being requested and if
      # preloading is supported.
      if [ -n "$SOL_PRELOAD" -a -z "$PRELOAD_STMT" ]; then
        pecho "$PROD_NAME: pre-loading is not supported on this platform."
        exit_failed 1
      elif [ -n "$SOL_PRELOAD" ]; then
        eval $PRELOAD_STMT
      fi
      if [ -x "$SYSTEMCTL" ]; then
        "$EXEC_DIR/$PROC" $ARGS -h "$HOST_LIST" $EXTRA_SLAPD_ARGS
      else
        echo "This command is for systemd enabled systems only."
        echo "Exiting..."
        exit_failed 1
      fi
    fi
    ;;

  # Stop and restart the server
  restart|force-reload)
    $0 stop $* && $0 start $*
    exit $?
    ;;

  # restart the server if it was running
  try-restart|condrestart)
    if [ -z "$PID" ]; then
      pecho "$PROD_NAME $PROC is not running"
      exit_failed 7
    fi
    $0 stop $* && $0 start $*
    exit $?
    ;;

  # Stop the server
  stop)
    if [ -z "$PID" ]; then
      pecho "$PROD_NAME $PROC is not running"
      exit_success
    fi
    pecho "$PROD_NAME $PROC stopping"
    if [ -x "$SYSTEMCTL" ]; then
      $SYSTEMCTL stop slapd 
    else
      kill $PID
      if [ $? -gt 0 ]; then
        pecho "$PROD_NAME $PROC stopping: kill failed"
        exit_failed 1
      fi
      elapsed=0
      if [ "$PROC" = slapd ]; then
        timeout=$SLAPD_TIMEOUT
      fi
      while kill -0 "$PID" 2>/dev/null; do
        pecho "."
        sleep 1
        elapsed=`expr $elapsed + 1`
        if [ $elapsed -gt $timeout ]; then
          exit_failed 1
        fi
      done
      rm -f $PID_FILE 2>/dev/null
    fi
    exit_success
    ;;

  # This option is for systemd enabled systems only.  It bypasses systemd
  # and stops the daemon directly.
  debug-stop)
    if [ -z "$PID" ]; then
      pecho "$PROD_NAME $PROC is not running"
      exit_success
    fi
    pecho "$PROD_NAME $PROC stopping"
    if [ -x "$SYSTEMCTL" ]; then
      kill $PID
      if [ $? -gt 0 ]; then
        pecho "$PROD_NAME $PROC stopping: kill failed"
        exit_failed 1
      fi
      elapsed=0
      if [ "$PROC" = slapd ]; then
        timeout=$SLAPD_TIMEOUT
      fi
      while kill -0 "$PID" 2>/dev/null; do
        pecho "."
        sleep 1
        elapsed=`expr $elapsed + 1`
        if [ $elapsed -gt $timeout ]; then
          exit_failed 1
        fi
      done
      rm -f $PID_FILE 2>/dev/null
    else
        echo "This command is for systemd enabled systems only."
        echo "Exiting..."
        exit_failed 1
    fi
    exit_success
    ;;

  # Report the status of the server
  status)
    if [ -z "$PID" ]; then
      NOT=" not"
    fi
    pecho "$PROD_NAME $PROC is${NOT} running"
    if [ "$UNAME" = Linux -a "$DIST" = SuSE ]; then
      if [ -z "$PID" ]; then
        rc_failed 3
      else
        rc_failed 0
      fi
      rc_status -v
      rc_exit
    else
      echo
      exit 0
    fi
    ;;

  # OpenLDAP has dynamic configuration, but not in a fashion
  # usable by an init script
  reload)
    pecho "$PROD_NAME $PROC must use restart"
    exit_failed 3
    ;;

  probe)
    if [ "$UNAME" = Linux ]; then
      # -nt is a bashism
      if [ "$SLAPD_CONF_FILE" -nt "$PID_FILE" ]; then
        echo restart
      fi
    else
      # well, no one else is likely to call probe, but...
      echo restart
    fi
    exit 0
    ;;

  # For starting directly under init, like AIX
  underinit)
    exec "$EXEC_DIR/$PROC" -d 0 $ARGS -h "$HOST_LIST"
    exit 1
    ;;

  *)
    echo $USAGE
    exit 1
    ;;
esac

if [ "$?" != 0 ]; then
  exit_failed 1
else
  if [ $GDB_ON_START = "Y" ]; then
    $0 $GDB_MODE_ARGS
    exit_success
  else
    exit_success
  fi
fi
exit 0
