#!/bin/sh
#
# Portable SysV init script for the Zabbix agent or server.
# Currently tested in Linux, AIX 5.3 and 7.1, Solaris 10 and HP-UX 11.31.
#

### BEGIN INIT INFO
# Provides:          zabbix-agent
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# chkconfig:         2345 99 01
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Zabbix Agent
# Description:       Zabbix agent for remote monitoring
### END INIT INFO

# The following comments exemplify using this as a zabbix-agent init script.
# For zabbix-server, simply use zabbix-server instead in the examples below.
#
# This file should live as /etc/init.d/zabbix-agent
# For AIX that would be /etc/rc.d/init.d/zabbix-agent
# For HP-UX that would be /sbin/init.d/zabbix-agent
#
# Debian/Ubuntu usage (as root).
#  * enable service at boot:
#      update-rc.d zabbix-agent defaults
#  * manually start the service:
#      service zabbix-agent start
#  * manually stop the service:
#      service zabbix-agent stop
#
# RedHat/CentOS/SUSE usage (as root).
#  * enable service at boot:
#      chkconfig --add zabbix-agent
#  * manually start the service:
#      service zabbix-agent start
#  * manually stop the service:
#      service zabbix-agent stop
#
# AIX usage (as root).
#  * enable service at boot:
#      ln -s /etc/rc.d/init.d/zabbix-agent /etc/rc.d/rc2.d/S90zabbix-agent
#  * manually start the service:
#      /etc/rc.d/init.d/zabbix-agent start
#  * manually stop the service:
#      /etc/rc.d/init.d/zabbix-agent stop
#
# Solaris usage (as root).
#  * enable service at boot:
#      ln -s /etc/init.d/zabbix-agent /etc/rc3.d/S90zabbix-agent
#  * manually start the service:
#      /etc/init.d/zabbix-agent start
#  * manually stop the service:
#      /etc/init.d/zabbix-agent stop
#
# HP-UX usage (as root).
#  * enable service at boot:
#      ln -s /sbin/init.d/zabbix-agent /sbin/rc3.d/S900zabbix-agent
#  * manually start the service:
#      /sbin/init.d/zabbix-agent start
#  * manually stop the service:
#      /sbin/init.d/zabbix-agent stop

# Do NOT "set -e".

# These values must match your Zabbix installation.
DAEMON_USER="zabbix"
DAEMON_NAME="zabbix_agentd"
DAEMON_BIN="/opt/zabbix-agent/sbin/$DAEMON_NAME"
DAEMON_CONF="/opt/zabbix-agent/conf/$DAEMON_NAME.conf"
DAEMON_ARGS="-c $DAEMON_CONF"

# These values must match the configuration from the above daemon conf file.
LOG_DIR="/var/log/zabbix"
PID_DIR="/var/run/zabbix"
PID_FILE="$PID_DIR"/$DAEMON_NAME.pid

# Things to customize for your needs.
SERVICE_NAME="Zabbix agent"
# Seconds to wait for a successful status when starting/stopping the daemon.
TIMEOUT_SECONDS=10

# For HP-UX's ps to accept '-o' arguments, the 2003 UNIX standard has to be set.
# Also, to use external utilities during boot, PATH should be exported.
test x`uname` = x'HP-UX' && export UNIX_STD=2003 PATH=/usr/sbin:/usr/bin:/sbin

#
# Needed directories are created when starting this init script.
#
create_dir_as_needed() {
    if [ ! -d "$1" ]; then
        mkdir "$1" && chown $DAEMON_USER "$1"
    fi
}

#
# Function used to check for a predetermined number of seconds if a certain
# error code is generated by status_service(). It takes two arguments: the
# error code to check for and the command to execute otherwise.
#
timedout_check() {
    error_code="$1"
    else_command="$2"

    i=0
    while [ $i -lt $TIMEOUT_SECONDS ]; do
        status_service 2>/dev/null
        if [ $? -eq $error_code ]; then
            printf " Done.\n"
            exit 0
        else
            $else_command
        fi
        sleep 1
        printf "."
        i=`expr $i + 1`
    done
}

#
# Starts the service if properly stopped and waits for it to launch
# successfully for a predefined number of seconds.
#
start_service() {
    status_service 2>/dev/null
    case $? in
        0)
            printf "$SERVICE_NAME is already running, nothing to start.\n"
            exit 0
            ;;
        1|4)
            printf "$SERVICE_NAME was not properly stopped, not starting!\n"
            exit 1
            ;;
    esac
    if [ ! -x "$DAEMON_BIN" ]; then
        printf "$DAEMON_BIN executable not present!\n" >&2
        exit 5
    fi
    create_dir_as_needed "$PID_DIR"
    create_dir_as_needed "$LOG_DIR"
    printf "Starting $SERVICE_NAME: "
    "$DAEMON_BIN" $DAEMON_ARGS
    timedout_check 0 "true"
    printf "\nCould not properly start $SERVICE_NAME!\n" >&2
    exit 1
}

#
# Stops the service if properly running and waits for it to stop
# successfully for a predefined number of seconds.
#
stop_service() {
    status_service
    case $? in
        3)
            printf "$SERVICE_NAME is not running, nothing to stop.\n"
            exit 0
            ;;
        1|4)
            printf "$SERVICE_NAME is not properly running, not stopping!\n"
            exit 1
            ;;
    esac
    printf "Stopping $SERVICE_NAME: "
    timedout_check 3 "kill $SAVED_PID"
    printf "\nCould not properly stop $SERVICE_NAME!\n" >&2
    exit 1
}

#
# Forcefully stops the service by attempting to kill all running processes.
# Useful when the PID file is not present anymore on the disk. Or when a
# -9/-SIGKILL parameter is needed for killing the running processes.
#
forcedstop_service() {
    status_service
    case $? in
        3)
            printf "$SERVICE_NAME is not running, nothing to forcefully stop.\n"
            exit 0
            ;;
        0)
            printf "$SERVICE_NAME is running fine, initiating normal stop...\n"
            $0 stop
            exit $?
            ;;
    esac
    printf "$SERVICE_NAME is not properly running, killing it nicely first: "
    timedout_check 3 "kill $IN_MEM_PIDS"
    printf "$SERVICE_NAME still running, killing it forcefully: "
    timedout_check 3 "kill -9 $IN_MEM_PIDS"
    printf "\nCould not forcefully stop $SERVICE_NAME!\n" >&2
    exit 1
}

#
# This implements a crude but portable status action for the init script
# without using LSB functions, although respecting the LSB 4.1 error codes.
#
status_service() {
    # A portable ps invocation to get the pids and commands for all processes
    # running as relevant user (without the usual ps headers).
    in_mem_pids_comms=`ps -U $DAEMON_USER -o pid= -o comm= | grep "$DAEMON_NAME"`
    # Check for processes running under the relevant name.
    if [ -z "$in_mem_pids_comms" ] ; then
        printf "No $DAEMON_NAME process is running as user $DAEMON_USER.\n" >&2
        return 3
    fi
    IN_MEM_PIDS=`printf "$in_mem_pids_comms" | awk '{print $1}' | xargs`
    # Check for problems related to the PID read from $PID_FILE.
    if [ ! -s "$PID_FILE" ]; then
        printf "Problems reading PID from file $PID_FILE.\n" >&2
        return 4
    fi
    SAVED_PID=`cat "$PID_FILE"`
    matched_pid=`printf "$in_mem_pids_comms" | awk '{print $1}' | grep "$SAVED_PID"`
    if [ ! "$matched_pid" = "$SAVED_PID" ]; then
        printf "PID from $PID_FILE doesn't match running processes.\n" >&2
        return 4
    fi
    # Check that the corresponding process is responding.
    if kill -0 "$SAVED_PID"; then
        (exit 0)
    else
        printf "$SERVICE_NAME is not responding or wrong PID: $SAVED_PID.\n" >&2
        return 1
    fi
}



#
# main
#

# A crude check for a sane installation and configuration.
if [ ! -r "$DAEMON_CONF" ]; then
    printf "Configuration file $DAEMON_CONF not present!\n" >&2
    exit 6
fi

# Check for the user's existence.
if id $DAEMON_USER >/dev/null 2>&1; then
    (exit 0)
else
    printf "$DAEMON_USER user not present!\n" >&2
    exit 6
fi

# Do not use stop_service() and start_service() for restart/force-reload.
case "$@" in
    start)
        start_service
        ;;
    stop)
        stop_service
        ;;
    restart|force-reload)
        $0 stop
        $0 start
        ;;
    force-stop)
        forcedstop_service
        ;;
    status)
        status_service
        ret_val=$?
        case $ret_val in
            0)
                printf "$SERVICE_NAME is running.\n"
                ;;
            3)
                printf "$SERVICE_NAME is not running!\n"
                ;;
            *)
                printf "$SERVICE_NAME is not properly running!\n"
                ;;
        esac
        exit $ret_val
        ;;
    start_msg)
        # Emit a _short_ message relating to running this script with the "start"
        # argument; this message appears as part of the checklist in HP-UX.
        printf "Starting $SERVICE_NAME"
        ;;

    stop_msg)
        # Emit a _short_ message relating to running this script with the "stop"
        # argument; this message appears as part of the checklist in HP-UX.
        printf "Stopping $SERVICE_NAME"
        ;;
    *)
        printf "Usage: $0 {start|stop|restart|force-reload|force-stop|status}\n" >&2
        exit 2
        ;;
esac
