#!/bin/sh

# flowcap start/control script
#
# /etc/init.d/flowcap
# chkconfig: - 20 95
# description: SiLK network flow collecting daemon
# processname: flowcap
### BEGIN INIT INFO
# Provides: flowcap
# Required-Start: $local_fs $remote_fs $network $named $syslog $time
# Required-Stop: $local_fs $remote_fs $network $named $syslog $time
# Short-Description: start and stop SiLK flowcap daemon
# Description: SiLK daemon to capture network flow data and write the
#              data to temporary files
### END INIT INFO

### Above this is from SiLK's src/flowcap/snippet-flowcap_header.init.sh
### Below this from SiLK's src/startup/snippet-init_header.sh

PROGRAM_NAME="flowcap"

# Extract an addendum from the filename. For example, an init script
# named 'flowcap-secondary' would look for a config file named
# 'flowcap'-secondary.conf  and produce log and pid files with
# '-secondary' in their names.

SCRIPT_BASE_NAME="$( basename -- "$0" | sed -e 's/\.init\.d$//' -e 's/\.sh$//' )"
INIT_SCRIPT_SUFFIX="$(
    echo "$SCRIPT_BASE_NAME" |
    sed -ne "/^${PROGRAM_NAME}-/ s/^${PROGRAM_NAME}// p"
)"

# The INIT_SCRIPT_SUFFIX is used as part of the filename of the config
# file, as well as the PID file and log file base name.

SCRIPT_CONFIG_FILENAME="${PROGRAM_NAME}${INIT_SCRIPT_SUFFIX}.conf"

### Below this from SiLK's src/startup/snippet-common_prelude.sh

# PROGRAM_NAME and SCRIPT_CONFIG_FILENAME should be set before this point.

# PROGRAM_NAME is the name of the executable program being managed by
# this script.

# SCRIPT_CONFIG_FILENAME is the name of the configuration file from
# which to read environment variables. Typically some variation on
# "${PROGRAM_NAME}.conf".

# SCRIPT_CONFIG_LOCATION is the directory where the
# ${SCRIPT_CONFIG_FILENAME} config file is located. It can be set via an
# environment variable. If the envar is not set, then /usr/etc is
# used.

# If $SCRIPT_CONFIG_LOCATION/sysconfig/$SCRIPT_CONFIG_FILENAME exists, a
# warning will be emitted (since the default location of these files has
# changed on some systems.)

SCRIPT_CONFIG="${SCRIPT_CONFIG_LOCATION:=/usr/etc}/${SCRIPT_CONFIG_FILENAME}"
DEPRECATED_SCRIPT_CONFIG="${SCRIPT_CONFIG_LOCATION}/sysconfig/${SCRIPT_CONFIG_FILENAME}"

if [ -f "$DEPRECATED_SCRIPT_CONFIG" ]; then
    echo "$0: *** WARNING: Config files should be placed directly in '${SCRIPT_CONFIG_LOCATION}', but '${DEPRECATED_SCRIPT_CONFIG}' exists." 1>&2
    echo "$0: *** WARNING: Move any existing configuration from '${DEPRECATED_SCRIPT_CONFIG}' to '${SCRIPT_CONFIG}'." 1>&2
fi

if [ ! -f "${SCRIPT_CONFIG}" ] ; then
    echo "$0: '${SCRIPT_CONFIG}' does not exist, exiting."
    exit 0
fi

. "${SCRIPT_CONFIG}"

if [ "x$ENABLED" = "x" ] ; then
    echo "$0: Not enabled in '${SCRIPT_CONFIG}', exiting." 1>&2
    exit 0
fi

#######################################################################
# SHELL FUNCTIONS

# check_empty VARNAME VALUE
#
#    Verifies that VALUE has a value.  If it doesn't, a message is
#    printed that the VARNAME variable is unset and script exits.
check_empty()
{
    if [ "x$2" = "x" ] ; then
        echo "$0: the \${$1} variable has not been set."
        exit 1
    fi
}

# check_dir VARNAME DIR
#
#    Verifies that VARNAME is set.  Next, verifies that the directory
#    DIR exists.  If not and if $CREATE_DIRECTORIES is set, the
#    directory is created.  Otherwise, an error is printed and the
#    script exits.
check_dir()
{
    check_empty "$1" "$2"
    if [ ! -d "$2" ] ; then
        if [ "${CREATE_DIRECTORIES}" = "yes" ] ; then
            mkdir -p "$2" || { echo "$0: Could not create $2" ; exit 1 ; }
            chown -h "${USER}" "$2" || { echo "$0: Could not chown $2 to ${USER}"; exit 1 ; }
        else
            echo "$0: the $2 directory does not exist."
            exit 1
        fi
    else
        chown -h "${USER}" "$2" || { echo "$0: Could not chown $2 to ${USER}"; exit 1 ; }
    fi
}

# Variables for building Basic Regular Expressions
TAB="	"                       # Contains a literal tab
WHITE="[ ${TAB}]"
WHITEPLUS="${WHITE}${WHITE}*"
NONWHITE="[^ ${TAB}]"
NONWHITEPLUS="${NONWHITE}${NONWHITE}*"
STRINGWHITE="\\(${NONWHITEPLUS}\\)${WHITEPLUS}"

# ws_strip STRING
#
#   Strips leading and trailing whitespace from STRING and returns it
ws_strip()
{
    echo $1 | sed -e "s/^${WHITE}*\\(${NONWHITEPLUS}\\(${WHITE}*${NONWHITEPLUS}\\)*\\)${WHITE}*\$/\\1/"
}

# cut_1 STRING
#
#    Returns first "token" from STRING or the empty string for an
#    empty STRING
cut_1()
{
    expr "x$1" : "x\\(${NONWHITE}*\\)"
}

# cut_2 STRING
#
#    Returns second "token" from STRING
cut_2()
{
    expr "x$1" : "x${NONWHITEPLUS}${WHITEPLUS}\\(${NONWHITEPLUS}\\)"
}

# cut_2rest STRING
#
#    Returns from second "token" to end of STRING
cut_2rest()
{
    expr "x$1" : "x${NONWHITEPLUS}${WHITEPLUS}\\(.*\\)"
}

# cut_3rest STRING
#
#    Returns from third "token" to end of STRING
cut_3rest()
{
    expr "x$1" : "x${NONWHITEPLUS}${WHITEPLUS}${NONWHITEPLUS}${WHITEPLUS}\\(.*\\)"
}

#######################################################################

RETVAL=0

PROGRAM_PATH="${BIN_DIR}/${PROGRAM_NAME}"

PROG_OPTIONS=""

if [ ! -x "${PROGRAM_PATH}" ] ; then
    echo "$0: could not find an executable ${PROGRAM_PATH}."
    exit 1
fi

### Below this from SiLK's src/flowcap/snippet-flowcap_startup.sh

check_empty "SENSOR_CONFIG" "${SENSOR_CONFIG}"
PROG_OPTIONS="${PROG_OPTIONS} --sensor-configuration='${SENSOR_CONFIG}'"

check_empty "MAX_FILE_SIZE" "${MAX_FILE_SIZE}"
PROG_OPTIONS="${PROG_OPTIONS} --max-file-size=${MAX_FILE_SIZE}"

if [ "x${PROBES}" != "x" ] ; then
    PROG_OPTIONS="${PROG_OPTIONS} --probes=${PROBES}"
fi
if [ "x${TIMEOUT}" != "x" ] ; then
    PROG_OPTIONS="${PROG_OPTIONS} --timeout=${TIMEOUT}"
fi
if [ "x${CLOCK_TIME}" != "x" ] ; then
    PROG_OPTIONS="${PROG_OPTIONS} --clock-time=${CLOCK_TIME}"
fi

check_dir "DESTINATION_DIR" "${DESTINATION_DIR}"
PROG_OPTIONS="${PROG_OPTIONS} --destination-directory=${DESTINATION_DIR}"
if [ "x${FREESPACE_MIN}" != "x" ] ; then
    PROG_OPTIONS="${PROG_OPTIONS} --freespace-minimum=${FREESPACE_MIN}"
fi
if [ "x${FULLSPACE_MAX}" != "x" ] ; then
    PROG_OPTIONS="${PROG_OPTIONS} --space-maximum-percent=${FULLSPACE_MAX}"
fi

# Be certain EXTRA_ENVVAR ends with a space when it is non-empty
if [ "x${EXTRA_ENVVAR}" != "x" ]; then
    if [ "x${SILK_IPFIX_PRINT_TEMPLATES}" != "x" ]; then
        EXTRA_ENVVAR="${EXTRA_ENVVAR} SILK_IPFIX_PRINT_TEMPLATES=${SILK_IPFIX_PRINT_TEMPLATES} "
    else
        EXTRA_ENVVAR="${EXTRA_ENVVAR} "
    fi
elif [ "x${SILK_IPFIX_PRINT_TEMPLATES}" != "x" ]; then
    EXTRA_ENVVAR="SILK_IPFIX_PRINT_TEMPLATES=${SILK_IPFIX_PRINT_TEMPLATES} "
fi

### Below this from SiLK's src/startup/snippet-init_footer.sh
### Init startup script footer: Final checks and handling arguments

check_dir   "PID_DIR"  "${PID_DIR}"

PIDFILE="${PID_DIR}/${PROGRAM_NAME}${INIT_SCRIPT_SUFFIX}.pid"
PROG_OPTIONS="${PROG_OPTIONS} --pidfile='${PIDFILE}' --log-level=${LOG_LEVEL}"

LOG_BASENAME="${PROGRAM_NAME}${INIT_SCRIPT_SUFFIX}"
case "${LOG_TYPE}" in
    syslog)
        PROG_OPTIONS="${PROG_OPTIONS} --log-destination=syslog"
        ;;
    legacy)
        check_dir "LOG_DIR" "${LOG_DIR}"
        PROG_OPTIONS="${PROG_OPTIONS} --log-directory='${LOG_DIR}' --log-basename='${LOG_BASENAME}'"
        ;;
    *)
        echo "$0: Unexpected LOG_TYPE ${LOG_TYPE}."
        echo "Set to \"legacy\" or \"syslog\"."
        exit 1
        ;;
esac


#######################################################################

# Check if $pid is running
checkpid() {
    kill -0 $1 >/dev/null 2>&1 && return 0
    return 1
}


# Get the process id from the PID file
getPid() {
    RETVAL=1
    if [ -f "${PIDFILE}" ] ; then
        RETVAL=2
        read pid < "${PIDFILE}"
        if [ "X$pid" != "X" ] ; then
            RETVAL=3
            # Found a pid
            if checkpid $pid ; then
                echo $pid
                RETVAL=0
            fi
        fi
    fi
    echo ""
    return $RETVAL
}


status() {
    if [ $# -gt 0 ] ; then
        doEcho=0
    else
        doEcho=1
    fi

    # first check if the process is running
    pid=`getPid`
    RETVAL=$?

    if [ $doEcho -eq 1 ] ; then
        case "$RETVAL" in
          0)
            echo "${PROGRAM_NAME}${INIT_SCRIPT_SUFFIX} is running with pid $pid"
            ;;
          1)
            echo "${PROGRAM_NAME}${INIT_SCRIPT_SUFFIX} is stopped"
            ;;
          *)
            echo "${PROGRAM_NAME}${INIT_SCRIPT_SUFFIX} is dead but pid file exists"
            ;;
        esac
    fi
    return $RETVAL
}


start() {
    (status 'silent')
    pStat=$?
    if [ $pStat -eq 0 ] ; then
        status
        return 0
    fi

    /bin/echo -n "Starting ${PROGRAM_NAME}${INIT_SCRIPT_SUFFIX}:	"
    /bin/rm -f ${PIDFILE} 2> /dev/null

    if [ X`whoami` = "X${USER}" ] ; then
        eval "${EXTRA_ENVVAR}${PROGRAM_PATH} ${PROG_OPTIONS} ${EXTRA_OPTIONS} &"
    else
        su - ${USER} -c "${EXTRA_ENVVAR}${PROGRAM_PATH} ${PROG_OPTIONS} ${EXTRA_OPTIONS} &"
    fi
    RETVAL=$?
    if [ "$RETVAL" -ne "0" ] ; then
        echo "[Failed]"
    else
        sleep 1
        PID=`getPid`
        if [ "x$PID" = "x" ] ; then
            echo "[Failed]"
            RETVAL=1
        else
            echo '[OK]'
        fi
    fi
    return $RETVAL
}


stop() {
    Pid=`getPid`
    if [ "X${Pid}" = "X" ] ; then
        echo "${PROGRAM_NAME}${INIT_SCRIPT_SUFFIX} not running"
        return 1
    fi
    /bin/echo -n "Stopping ${PROGRAM_NAME}${INIT_SCRIPT_SUFFIX}:	"
    /bin/kill -s TERM $Pid
    for s in 2 3 4 6 7; do
        sleep $s
        if checkpid $Pid ; then
            :
        else
            break;
        fi
    done
    if checkpid $Pid ; then
        # Kill the entire process group
        /bin/kill -s KILL "-$Pid"
        sleep 1
    fi
    (checkpid $Pid)
    RETVAL=$?
    [ "$RETVAL" -eq "1" ] && echo '[OK]' || echo '[FAILED]'
    /bin/rm -f ${PIDFILE} 2> /dev/null
    return $RETVAL
}


restart(){
    (stop)
    (start)
}


case "$1" in
  start)
    (start)
    RETVAL=$?
    ;;

  stop)
    (stop)
    RETVAL=$?
    ;;

  restart)
    (restart)
    RETVAL=$?
    ;;

  force-reload)
    (restart)
    RETVAL=$?
    ;;

  status)
    (status)
    RETVAL=$?
    ;;

  *)
    echo "Usage: $0 {start|stop|status|restart|force-reload}"
    RETVAL=1
    ;;
esac

exit $RETVAL


#######################################################################
# @OPENSOURCE_LICENSE_START@
#
# SiLK 3.24
#
# Copyright 2025 Carnegie Mellon University.
#
# NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE ENGINEERING
# INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON
# UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR
# IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF
# FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS
# OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
# MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT,
# TRADEMARK, OR COPYRIGHT INFRINGEMENT.
#
# Licensed under a GNU GPL 2.0-style license, please see LICENSE.txt or
# contact permission@sei.cmu.edu for full terms.
#
# [DISTRIBUTION STATEMENT A] This material has been approved for public
# release and unlimited distribution.  Please see Copyright notice for
# non-US Government use and distribution.
#
# This Software includes and/or makes use of Third-Party Software each
# subject to its own license.
#
# DM25-0915
#
# @OPENSOURCE_LICENSE_END@
#######################################################################
