#!/bin/sh
#
# Copyright (c) 2014-2019 VMware, Inc.  All rights reserved.
#
# Author: Laxmikant Gunda, 2014
#
# Basic support for IRIX style chkconfig
# chkconfig: 235 99 01
# description: VMware Guest Introspection Service
# processname: vsepd
# pidfile: /var/run/vsep.pid

### BEGIN INIT INFO
# Provides:             vsepd
# Required-Start:       $network $remote_fs $syslog $time
# Required-Stop:        $network $remote_fs $syslog $time
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    VMware Guest Introspection Service
# Description:          Manages the service need to run VMware
#                       Guest Introspection
### END INIT INFO

VSEP_NAME=vsep
VSEP_BIN=/usr/sbin/$VSEP_NAME
VSEP_CONFIG=/etc/vsep/vsep.cfg
VSEP_CONF=/etc/vsep/vsep.conf
LOCK_FILE=/var/lock/subsys/vsepd
SYSCTL=/sbin/sysctl
VSEP_PID=/var/run/vsep.pid
VSEP_STOP_TIME=3

# Check for missing binaries
if [ ! -f $VSEP_BIN ] ; then
   echo "$VSEP_BIN not installed"
   if [ "$1" = "stop" ] ; then
      exit 0
   else
      exit 5
   fi
fi

#
# Enable this when we have a config file
# Check for missing config file
[ -e ${VSEP_CONFIG} ] && . ${VSEP_CONFIG}

if [ -n "${VSEP_INOTIFY_USER_WATCHES}" ]; then
   ${SYSCTL} -wq fs.inotify.max_user_watches=${VSEP_INOTIFY_USER_WATCHES}
fi

# Determine OS type based on the functions library path
OS=""
if [ -f /etc/init.d/functions ] ; then
   OS="Redhat"
   . /etc/init.d/functions

   DAEMON_COREFILE_LIMIT='ulimited'
   alias START_DAEMON=daemon
   alias STOP_DAEMON=killproc
   alias STATUS=status
   alias LOG_SUCCESS=success
   alias LOG_FAILURE=failure
   alias LOG_WARNING=warning
   alias BLANK_LINE=echo
   MODPROBE_PARAM=""
elif [ -f /lib/lsb/init-functions ] && [ -f /etc/rc.status ] ; then
   OS="Suse"
   . /lib/lsb/init-functions

   alias START_DAEMON=start_daemon
   alias STOP_DAEMON=killproc
   alias STATUS=checkproc
   alias LOG_SUCCESS=log_success_msg
   alias LOG_FAILURE=log_failure_msg
   alias LOG_WARNING=log_warning_msg
   alias BLANK_LINE='echo'
   MODPROBE_PARAM="--allow-unsupported-modules"
elif [ -f /lib/lsb/init-functions ] ; then
   OS="Ubuntu"
   . /lib/lsb/init-functions

   alias START_DAEMON=start_daemon
   alias STOP_DAEMON=killproc
   alias STATUS=status_of_proc
   alias LOG_SUCCESS=log_success_msg
   alias LOG_FAILURE=log_failure_msg
   alias LOG_WARNING=log_warning_msg
   alias BLANK_LINE='echo'
   MODPROBE_PARAM=""
else
   OS="Unsupported OS, exiting."
   LOG_FAILURE $OS
   exit 1
fi

# Start the service
start () {
   if [ "`id -u`" -ne 0 ] ; then
      LOG_FAILURE "User has insufficient privilege."
      exit 4
   fi

   #
   # Check if there's already running instance of vsep, using lock_file
   # and using pidof command.. so at any time we will run only one instance
   #
   if [ -f $LOCK_FILE -a -n "`pidof $VSEP_BIN`" ] ; then
      if [ "$OS" = "Suse" ] ; then
         STATUS $VSEP_BIN
         rc_status -v
      elif [ "$OS" = "Redhat" ] ; then
         STATUS $VSEP_BIN
      elif [ "$OS" = "Ubuntu" ] ; then
         STATUS $VSEP_BIN
      fi
      exit 7;
   fi

   echo "Starting $VSEP_NAME service"

   START_DAEMON $VSEP_BIN
   if [ "$?" -eq 0 ] ; then
      ### Create the lock file ###
      mkdir -p /var/lock/subsys
      touch $LOCK_FILE

   else
      LOG_FAILURE "$VSEP_NAME service startup error: $?"
   fi

   BLANK_LINE
}

# Stop the service
stop() {
   if [ "`id -u`" -ne 0 ] ; then
      LOG_FAILURE "User has insufficient privilege."
      exit 4
   fi
   # vsepshut.service will send SIGUSR2 to thin agent. This signal needs to be
   # processed by thin agent before SIGTERM. Linux system does not guarantee
   # the order in which the signals will be delivered. Hence sleep for 1
   # second before sending SIGTERM to thin agent.
   sleep 1
   echo "Stopping $VSEP_NAME service"

   STOP_DAEMON $VSEP_BIN -TERM
   if [ "$?" -eq 0 ] ; then
      # Now, delete the lock file ###
      rm -f $LOCK_FILE

      # Sleep for few seconds, wait for thin-agent to stop
      # For restart case, wait for the MUX connection to get refreshed
      sleep $VSEP_STOP_TIME
   else
      LOG_FAILURE "$VSEP_NAME service stop error: $?"
   fi
   BLANK_LINE
}

### main logic ###
case "$1" in
   start)
      start
      if [ "$OS" = "Suse" ] ; then
         rc_status -v
      fi
      ;;
   stop)
      stop
      if [ "$OS" = "Suse" ] ; then
         rc_status -v
      fi
      ;;
   status)
      echo -n "Checking for $VSEP_NAME service: "
      if [ "$OS" = "Suse" ] ; then
         STATUS $VSEP_BIN
         rc_status -v
      elif [ "$OS" = "Redhat" ] ; then
         STATUS $VSEP_BIN
      elif [ "$OS" = "Ubuntu" ] ; then
         STATUS $VSEP_BIN
      fi
      ;;
   restart|force-reload)
      stop
      start
      if [ "$OS" = "Suse" ] ; then
         rc_status
      fi
      ;;
   shut)
      pid=`ps -ef | grep [v]sep | grep usr | awk '{print $2}'`
      echo $pid
      kill -12 $pid
      # Since thin agent is going to check the legitimacy of SIGUSR2 this
      # process needs to be running when it checks the /proc system for
      # process name, etc. Hence sleep for 1 second.
      sleep 1
      ;;
   refresh-logging)
      usage="Usage: /etc/vsep/vsepd refresh-logging <dest> <<level>
      sub-component-name> where dest: [1-2] level: [1-7] sub-component-name:
      one or more of transport timer file network process system"
      transport=0x1
      timer=0x2
      file=0x4
      network=0x8
      process=0x10
      system=0x20
      mask=0x0

      if [ $# -lt 4 ] ; then
         echo $usage
         exit 1
      fi

      if [ $2 -ne 1 ] && [ $2 -ne 2 ] ; then
         echo "Invalid dest $2. $usage"
         exit 1
      fi

      if [ $3 -lt 1 ] || [ $3 -gt 7 ] ; then
         echo "Invalid level $3. $usage"
         exit 1
      fi

      command='s/DEBUG_DEST=.*/DEBUG_DEST='$2'/'
      echo "Changing destination level to: $2"
      sed -i $command $VSEP_CONF
      command='s/DEBUG_LEVEL=.*/DEBUG_LEVEL='$3'/'
      echo "Changing logging level to: $3"
      sed -i $command $VSEP_CONF

      i=0
      #Ignore 3 from number of input parameters. 1 - refresh-logging, 1 dest, 1 level
      for var in "$@"
      do
         i=`expr $i + 1`
         if [ $i -gt 3 ]
         then
            echo "Enabling $var"
            case "$var" in
               transport)
                  mask=$(($mask | $transport))
                  ;;
               timer)
                  mask=$(($mask | $timer))
                  ;;
               file)
                  mask=$(($mask | $file))
                  ;;
               network)
                  mask=$(($mask | $network))
                  ;;
               process)
                  mask=$(($mask | $process))
                  ;;
               system)
                  mask=$(($mask | $system))
                  ;;
               *)
                  echo "Invalid sub component name: $var"
                  ;;
            esac
         fi
      done
      if [ $mask -eq 0 ]
      then
         echo "Mask not set. Enabling all module masks"
         mask=$(($transport | $timer | $file | $network | $process | $system))
      fi
      echo "Changing sub component mask to: $mask"
      command='s/DEBUG_MODULE_MASK=.*/DEBUG_MODULE_MASK='$mask'/'
      sed -i $command $VSEP_CONF
      if test -f "$VSEP_PID"; then
         pid=`cat $VSEP_PID`
         echo "Notifying thin agent"
         sleep 1
         kill -10 $pid
      fi
      ;;
   *)
      echo "Usage: $0 {start|stop|restart|status|force-reload|refresh-logging}"
      exit 1
esac
exit 0
