#!/bin/sh
# Do NOT "set -e"

# ----- BEGIN CONFIGURATION -----

# This is the name of the user account that will run the process.
USERNAME=root

# ----- END OF CONFIGURATION -----

MODULENAME=lora
MODULEPATH=/opt/${MODULENAME}
DEFAULTSFILE=$MODULEPATH/etc/defaults
SETTINGSFILE=$MODULEPATH/etc/settings

if [ -f /sbin/iptables ]; then
  IPTABLES=/sbin/iptables
elif [ -f /usr/sbin/iptables ]; then
  IPTABLES=/usr/sbin/iptables
else
  IPTABLES=
fi

# PATH should only include /usr/* if it runs after the mountnfs.sh script.
PATH=$MODULEPATH/sbin:$MODULEPATH/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

DESC="Really Small Message Broker"
NAME=mosquitto
DAEMON=$MODULEPATH/sbin/$NAME

PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=$0

DATAPATH=/var/data/$MODULENAME
DAEMON_ARGS="-c $DATAPATH/broker.cfg"

LOGFILE=/var/log/$NAME.log

check_requirements()
{
  # This daemon uses the following libraries from the router's firmware.
  REQUIRED="/lib/libc.so.6"
  for FILE in $REQUIRED; do
    if [ ! -f "$FILE" ]; then
      logger -p "daemon.warning" -t "${NAME}[$$]" "A required file was not found: $FILE."
    fi
  done
}

# Add a new chain to the firewall.
#
# $1 is the module name
# $2 is the protocol (tcp)
# $3 is the port number
#
# More information is available in the Programming of User Modules Application Note.
# http://www.bb-smartcellular.com/user-modules/
#
add_chain()
{
  # Must have 3 or more arguments.
  [ $# -ge 3 ] || return 2

  # $IPTABLES must not be an empty string.
  [ -n "$IPTABLES" ] || return 2

  # Must have execute permission on $IPTABLES.
  [ -x "$IPTABLES" ] || return 2

  # Add firewall rule to accept packet.
  # - create a new chain with name $1
  # - append rule to end of chain $1 protocol $2 port $3 jump to ACCEPT
  # - append rule to end of chain 'in_mod' jump to $1
  #
  $IPTABLES -N $1 2>&1 >/dev/null || return 2
  $IPTABLES -A $1 -p $2 --dport $3 -j ACCEPT 2>&1 >/dev/null || return 2
  $IPTABLES -A in_mod -j $1 2>&1 >/dev/null || return 2

  # Add firewall rule to prevent forwarding packet to default server.
  # - In table nat, add a new chain with name $1
  # - In table nat, append rule to end of chain $1 protocol $2 port $3 jump to ACCEPT
  # - In table nat, append rule to end of chain 'pre_mod' jump to $1
  #
  $IPTABLES -t nat -N $1 2>&1 >/dev/null || return 2
  $IPTABLES -t nat -A $1 -p $2 --dport $3 -j ACCEPT 2>&1 >/dev/null || return 2
  $IPTABLES -t nat -A pre_mod -j $1 2>&1 >/dev/null || return 2

  return 0
}

# Remove the specified chain from the firewall.
#
# $1 is the module name
#
# More information is available in the Programming of User Modules Application Note.
# http://www.bb-smartcellular.com/user-modules/
#
#
del_chain()
{
  # Must have 1 or more arguments.
  [ $# -ge 1 ] || return 2

  # $IPTABLES must not be an empty string.
  [ -n "$IPTABLES" ] || return 2

  # Must have execute permission on $IPTABLES.
  [ -x "$IPTABLES" ] || return 2

  # Remove firewall rule to accept packet.
  # - Delete rule from chain 'in_mod' jump to $1
  # - Flush chain 'in_mod'
  # - Delete chain $1
  #
  $IPTABLES -n -L $1 2>&1 >/dev/null
  if [ $? -eq 0 ]; then
    $IPTABLES -D in_mod -j $1 2>&1 >/dev/null
    $IPTABLES -F $1 2>&1 >/dev/null
    $IPTABLES -X $1 2>&1 >/dev/null
  fi

  # Remove firewall rule to prevent forwarding packet to default server.
  # - In table nat, delete rule from chain 'pre_mod' jump to $1
  # - In table nat, flush chain $1
  # - In table nat, delete chain $1
  #
  $IPTABLES -t nat -n -L $1 2>&1 >/dev/null
  if [ $? -eq 0 ]; then
    $IPTABLES -t nat -D pre_mod -j $1 2>&1 >/dev/null
    $IPTABLES -t nat -F $1 2>&1 >/dev/null
    $IPTABLES -t nat -X $1 2>&1 >/dev/null
  fi

  return 0
}

do_defaults()
{
  return 0
}

do_status()
{
  if [ -r "$PIDFILE" ]; then
    kill -0 `cat $PIDFILE` || return 2
    return 0
  fi
  return 2
}

# A function to generate the software-specific configuration file
# from the Spectre v2 user-module settings file.
#
do_make_config()
{
    # If the path to the configuration file does not exist, create the path.
    [ -d "$DATAPATH" ] || mkdir -p "$DATAPATH"

    ${MODULEPATH}/bin/create_broker_cfg
}

# Remove temporary files.
#
do_cleanup()
{
    # Remove the first failure data capture files.
    rm -f $MODULEPATH/bin/*.dmp

    # Remove the persistent messages.
    #
    rm -f $DATAPATH/*.rms
    rm -f $DATAPATH/*.1ms
    rm -f $DATAPATH/*.2ms

    # Remove the persistent subscriptions
    #
    rm -f $DATAPATH/*.sub
    rm -f $DATAPATH/*.1ub
    rm -f $DATAPATH/*.2ub
}

# A function that starts the daemon (service).
# @retval 0 if daemon has been started.
# @retval 1 if daemon was already running.
# @retval 2 if daemon could not be started.
# @retval other if a failure occurred.
#
do_start()
{
   # Retrieve LORA_MQTT_PORT from $SETTINGSFILE, and then add a firewall rule.
  LORA_MQTT_ENABLE=`cat "$SETTINGSFILE" | awk 'BEGIN{FS="=";found=""}{if($1=="LORA_MQTT_ENABLE")if(NF>=2)if(length($2)>0)found=substr($0,index($0,$2))}END{printf("%s",found)}'`
  [ -n "$LORA_MQTT_ENABLE" ] && [ "$LORA_MQTT_ENABLE" -ne "0" ] || exit 0
  
  # If the daemon is not an executable file, then exit.
  [ -x "$DAEMON" ] || return 3

  check_requirements

  # Cleanup after the last time the daemon was run.
  do_cleanup

  # Make the configuration file from the settings file.
  do_make_config

  # Test whether the daemon is running already or not.
  start-stop-daemon --test --start --quiet --chuid $USERNAME --make-pidfile --pidfile $PIDFILE \
      --background --exec $DAEMON -- $DAEMON_ARGS \
      || return 1

  # Attempt to start the daemon.
  start-stop-daemon --start --quiet --chuid $USERNAME --make-pidfile --pidfile $PIDFILE \
      --background --exec $DAEMON -- $DAEMON_ARGS \
      || return 2

  # Make sure that the daemon is running.
  sleep 1
  kill -0 `cat $PIDFILE` 2>/dev/null || return 2

  LORA_MQTT_PORT=`cat "$SETTINGSFILE" | awk 'BEGIN{FS="=";found=""}{if($1=="LORA_MQTT_PORT")if(NF>=2)if(length($2)>0)found=substr($0,index($0,$2))}END{printf("%s",found)}'`
  [ -n "$LORA_MQTT_PORT" ] && add_chain ${NAME} tcp $LORA_MQTT_PORT 2>&1 1>/dev/null

  return 0
}

# A function that stops the daemon (service).
# @retval 0 if daemon has been stopped.
# @retval 1 if daemon was already stopped.
# @retval 2 if daemon could not be stopped.
# @retval other if a failure occurred.
#
do_stop()
{
  # If the daemon is not an executable file, then exit.
  [ -x "$DAEMON" ] || return 3

  # Attempt to stop the daemon.
  start-stop-daemon --stop --quiet --retry=TERM/10/KILL/5 --pidfile $PIDFILE --exec $DAEMON
  [ $? -lt 2 ] || return $?

  # Wait for children to finish too if this is a daemon that forks
  # and if the daemon is only ever run from this initscript.
  # If the above conditions are not satisfied then add some other code
  # that waits for the process to drop all resources that could be
  # needed by services started subsequently.  A last resort is to
  # sleep for some time.
  start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
  [ $? -lt 2 ] || return $?

  # Many daemons do not remove their pidfiles when they exit. Remove it now.
  rm -f $PIDFILE

  # Remove the firewall rule.
  del_chain ${NAME} 2>&1 1>/dev/null

  return 0
}

case "$1" in
  defaults)
    echo "Restoring defaults for $DESC ($NAME)..."
    do_defaults
    RETVAL=$?
    ;;
  start)
    echo "Starting $DESC ($NAME)..."
    do_start
    RETVAL=$?
    case "$RETVAL" in
        0|1) echo "   Starting $DESC ($NAME) succeeded" ;;
        *)   echo "   Starting $DESC ($NAME) failed" ;;
    esac
    ;;
  status)
    echo "Checking status of $DESC ($NAME)..."
    do_status
    RETVAL=$?
    case "$RETVAL" in
        0) echo "   $DESC ($NAME) is running" ;;
        *) echo "   $DESC ($NAME) is not running" ;;
    esac
    ;;
  stop)
    echo "Stopping $DESC ($NAME)..."
    do_stop
    RETVAL=$?
    case "$RETVAL" in
        0|1) echo "   Stopping $DESC ($NAME) succeeded" ;;
        *)   echo "   Stopping $DESC ($NAME) failed" ;;
    esac
    ;;
  restart|force-reload)
    #
    # If the "reload" option is implemented then remove the
    # 'force-reload' alias
    #
    echo "Restarting $DESC ($NAME)..."
    do_stop
    RETVAL=$?
    case "$RETVAL" in
      0|1)
        do_start
        RETVAL=$?
        case "$RETVAL" in
          0|1) echo "   Restarting $DESC ($NAME) succeeded" ;;
          *)   echo "   Restarting $DESC ($NAME) failed: couldn't start $NAME" ;;
        esac
        ;;
      *)
        echo "   Restarting $DESC ($NAME) failed: couldn't stop $NAME" ;;
    esac
    ;;
  *)
    echo "Usage: $SCRIPTNAME { defaults | force-reload | restart | start | status | stop }" >&2
    RETVAL=3
    ;;
esac
exit $RETVAL

# ---- END OF FILE ----
