#!/bin/sh
#
# Copyright 2007 SAS Institute Inc.
# SAS Campus Drive, Cary, North Carolina 27513, USA.
# All rights reserved.
#
#set -v
#echo "running sas.servers"
#
# Sample boot-time script for SAS 9.1.3 SP4 BI Servers
# Version V0.1 for RHEL 4
#
# This script assumes that all listed SAS servers will be run on this
# same platform. We do not check for, nor start SAS servers on remote
# platforms.
#
# The SAS Metadata Server must start successfully before attempts are
# made to start the other dependent servers. 
#
# The script is intended to run at boot level 3 or 5.
#
# Put a copy of this script in /etc/init.d and set permissions to 0744, 
# owner=root. Add a hard link in /etc/rc3.d or rc5.d to this script from:
#   S99sas.servers
# and a hard link in /etc/rc0.d to this script from:
#   K99sas.servers
#
# The "99" insures that the SAS Servers script is one of the last to 
# execute at boot, allowing NFS, etc. to start up first. The "S" link
# be executed at startup and the "K" link will be executed at shutdown.
# Runlevel 5 is network and gui. Runlevel 3 is network and command line. 
#
#*****
#
# The following sets of variables will be automatically set by the 
# installer in 9.2+ installs. They must be set by hand at present. 
#
#*****

#*****
# Each variable should be set to "yes" if that server type is installed,
# or nothing if the particular server is not installed, for example:
#
#  HAS_OLAP_SERVER=
#
#*****
HAS_METADATA_SERVER=yes
HAS_OLAP_SERVER=
HAS_OBJECT_SPAWNER=yes
HAS_SHARE_SERVER=
HAS_CONNECT_SERVER=

#*****
# To avoid protection issues with installs mounted over NFS, this
# script has to run under the same UID as that which owns the installed
# SAS code. Define that UID here.
#*****
SASUID="sastux"

#*****
#
# Configuration-dependent (pick one to uncomment)
#
#*****
#Logmsg=Debug_Logmsg
#Logmsg=Mandriva_Logmsg
Logmsg=RHEL_Logmsg
#Logmsg=SUSE_Logmsg
#Logmsg=AIX_Logmsg
#Logmsg=H6I_Logmsg
#Logmsg=SOL9_Logmsg
#Logmsg=SOL10_Logmsg
#Logmsg=HPUX_Logmsg

#*****
# Uncomment for Solaris,
#*****
#WHOAMI="/usr/ucb/whoami"
#TAIL="/usr/xpg4/bin/tail -n "  # syntax different from deprecated /usr/bin/tail
#*****
# Uncomment for others
#*****
WHOAMI="/usr/bin/whoami"
TAIL="/usr/bin/tail -n "

#*****
#
# Where the SAS Metadata Server files live - this is installation-dependent.
# Set the appropriate install directory for your configuration. The
# double-quotes are important.
#
#*****
METADATA_SERVER_DIR="/usr/local/SAS/Config/Lev1/SASMain/MetadataServer"
METADATA_SERVER_LOGS="$METADATA_SERVER_DIR/logs"

#*****
#
# Where other SAS servers live - these are installation-dependent.
# Set the appropriate install directories for your configuration.
#
#*****
OLAP_SERVER_DIR="/usr/local/SAS/Config/Lev1/SASMain/OLAPServer"
OLAP_SERVER_LOGS="$OLAP_SERVER_DIR/logs"

CONNECT_SERVER_DIR="/usr/local/SAS/Config/Lev1/SASMain/ConnectServer"
CONNECT_SERVER_LOGS="$CONNECT_SERVER_DIR/logs"

SHARE_SERVER_DIR="/usr/local/SAS/Config/Lev1/SASMain/ShareServer"
SHARE_SERVER_LOGS="$SHARE_SERVER_DIR/logs"

OBJECT_SPAWNER_DIR="/usr/local/SAS/Config/Lev1/SASMain/ObjectSpawner"
OBJECT_SPAWNER_LOGS="$OBJECT_SPAWNER_DIR/logs"

#*****
# The following variable sets the number of, and delay between attempts
# to start each SAS server. Each number is the sleep seconds to delay 
# before the next try. You probably don't need to change these.
#*****
RETRY_SERIES="2 2 2 5 5 5 5 5 5 5 5"


#*****
#
# That is all that you should need to manually configure.
#
#*****












#*****
#
# Don't change anything beyond here.
#
#*****

#
# The last thing that the server does when it comes up is log a listener
# connection. Check for that string.
#
METADATA_SERVER_UP="Defined server listen connection"
OLAP_SERVER_UP="Defined server listen connection"
OBJECT_SPAWNER_UP="Objspawn has completed initialization"

#
# Subroutines/Functions
#

#
# Check server status. We could invoke each server script with "status",
# but it's quicker to do this directly. Note that if the status check
# paradigm changes in the server scripts, those changes will need to
# be propagated to here.
#
# This uses the cheap-but-quick approach that simply checks for
# alive server PIDs.
#
server_status()
{
    if [ -n "$HAS_METADATA_SERVER" ];
    then
    {
      if [ -f $METADATA_SERVER_DIR/server.pid ];
      then
      {
        pid=`cat $METADATA_SERVER_DIR/server.pid`
        kill -0 $pid >/dev/null 2>&1
        if [ $? -eq 0 ]; then
           $Logmsg "SAS Metadata Server (pid $pid) is running..."
        fi
      }
      else
        $Logmsg "SAS Metadata Server is stopped"
      fi
    }
    fi

    if [ -n "$HAS_OLAP_SERVER" ];
    then
    {
      if [ -f $OLAP_SERVER_DIR/server.pid ];
      then
      {
        pid=`cat $OLAP_SERVER_DIR/server.pid`
        kill -0 $pid >/dev/null 2>&1
        if [ $? -eq 0 ]; then
           $Logmsg "SAS OLAP Server (pid $pid) is running..."
        fi
      }
      else
        $Logmsg "SAS OLAP Server is stopped"
      fi
    }
    fi

    if [ -n "$HAS_OBJECT_SPAWNER" ];
    then
    {
      if [ -f $OBJECT_SPAWNER_DIR/server.pid ];
      then
      {
        pid=`cat $OBJECT_SPAWNER_DIR/server.pid`
        kill -0 $pid >/dev/null 2>&1
        if [ $? -eq 0 ]; then
           $Logmsg "SAS Object Spawner (pid $pid) is running..."
        fi
      }
      else
        $Logmsg "SAS Object Spawner is stopped"
      fi
    }
    fi

    if [ -n "$HAS_SHARE_SERVER" ];
    then
    {
      if [ -f $SHARE_SERVER_DIR/server.pid ];
      then
      {
        pid=`cat $SHARE_SERVER_DIR/server.pid`
        kill -0 $pid >/dev/null 2>&1
        if [ $? -eq 0 ]; then
           $Logmsg "SAS Share Server (pid $pid) is running..."
        fi
      }
      else
        $Logmsg "SAS Share Server is stopped"
      fi
    }
    fi

    if [ -n "$HAS_CONNECT_SERVER" ];
    then
    {
      if [ -f $CONNECT_SERVER_DIR/server.pid ];
      then
      {
        pid=`cat $CONNECT_SERVER_DIR/server.pid`
        kill -0 $pid >/dev/null 2>&1
        if [ $? -eq 0 ]; then
           $Logmsg "SAS Connect Server (pid $pid) is running..."
        fi
      }
      else
        $Logmsg "SAS Connect Server is stopped"
      fi
    }
    fi
}

is_server_up()
{
#
# SAS servers typically write log information into a server-related 
# subdirectory, using logfile names that have the date encoded in them,
# and rotate to a new logfile each day. The name format is typically of
# the form:
#
#    SomeServer_YYYY.MM.DD.log
#
#
# A few servers still use a fixed name, e.g. "objspawn.log"
#
# Returns 1 if server is up, 0 if failure
#
######
# Take as inputs the environment variables:
#
# LOGNAME    prefix name of the server logfile, e.g. "MetadataServer"
# LOGDIR     directory where the logfiles are found
# SERVER_UP  log message that indicates that the server is alive
#
# The quick-and-dirty way to see if the server is up is to issue a
# "kill -0 pid" against it. The following is a bit more robust in that
# it checks the server log file to see if the server made it all the
# way to the "listening for connections" stage.
#

#
# Generate a log file name given today's date.
#
#echo generate log
#echo scripttime $SCRIPT_TIME
#echo logname $LOGNAME
  CHKLOG="`echo $LOGNAME $SCRIPT_TIME | awk '{ printf "%s_%s.%s.%s.log", $1, substr($2,1,4),substr($2,5,2),substr($2,7,2) }'`"

#echo "logfile name is" $CHKLOG
#
#
# Let the server come up to speed, then retry checking the log
# a few times before deciding the server didn't make it up.
# The numbers in RETRY_SERIES are sleep times (in seconds) before retry.
#
  MATCH=
  for st in $RETRY_SERIES
  do
    sleep $st
#echo do grep
    grep "$SERVER_UP" "$LOGDIR/$CHKLOG" > /dev/null 2>&1
    if [ "$?" -eq 0 ];
    then
    {
#echo
#echo
#echo grep match
#echo SERVER_UP is "$SERVER_UP"
#echo LOG is "$LOGDIR/$CHKLOG"

#
# In some instances the last log line isn't terminated with
# a newline. Some OS tail commands will combine this with the last line that 
# did have a newline, for example if you execute 
#    cat foo | tail -n 1
#
# To fix this, there is an embedded awk in the pipe to add newlines
#
      MATCH=`grep "$SERVER_UP" "$LOGDIR/$CHKLOG" | awk '{ printf "%s\n", $0 }' | ${TAIL}1`;
#echo checking $MATCH

      check_match; 
      if [ "$?" -eq 1 ];
      then return 1;  # found a matching entry and it's newer than this run
      fi
    }
    fi
  done
#
# Last chance, the day may have rolled over while this script was running.
# Check one more time using the new day's log file (if any).
#
  new_day_match;
  if [ "$?" -eq 1 ];
  then return 1;   # got a valid match
  else return 0;
  fi
}

is_server_up_nostamp()
{
#
# SAS servers typically write log information into a server-related 
# subdirectory, using logfile names that have the date encoded in them,
# and rotate to a new logfile each day.
#
# A few servers still use a fixed name, e.g. "objspawn_console.log", so
# we have a special-case routine to check if they're up. Note that not
# only does the log name not get timestamped, but the log entries don't
# either. Just check to see if the desired string is present in whatever
# current logfile exists. If we find the string, see if the associated
# server PID file results in an active PID.
#
# Returns 1 if server is up, 0 if failure
#
######
# Take as inputs the environment variables:
#
# LOGNAME    prefix name of the server logfile, e.g. "MetadataServer"
# LOGDIR     directory where the logfiles are found
# SERVER_UP  log message that indicates that the server is alive
# SERVER_PID_FILE  file where the server's PID is stored at startup
#

  CHKLOG="$LOGNAME.log"
#echo "logfile name is" $CHKLOG
#
#
# Let the server come up to speed, then retry checking the log
# a few times before deciding the server didn't make it up.
# The numbers n RETRY_SERIES are sleep times (in seconds) before retry.
#
  MATCH=
  for st in $RETRY_SERIES
  do
    sleep $st
#echo do grep
    grep "$SERVER_UP" "$LOGDIR/$CHKLOG" > /dev/null 2>&1
    if [ "$?" -eq 0 ];
    then
    {
#echo
#echo
#echo grep match
      if [ -f $SERVER_PID_FILE ]; # got a PID file?
      then
      {
        pid=`cat $SERVER_PID_FILE`
        kill -0 $pid >/dev/null 2>&1
        if [ $? -eq 0 ]; then
	  return 1;  # PID is active
        else
          return 0;  # PID not active
        fi
      }
      else # can't access PID file
        continue; # try again
      fi
    }
    fi
  done
#
# Fell out of the loop; assume that either the logfile doesn't exist
# or the desired string wasn't there. In either case, the server must
# not be up.

  return 0;
}

check_match ()
{
#
# If MATCH is non-null, we found the target string in the log file.
# Now make sure that it was logged *after* we started this script (there
# could be pre-existing successful starts since the logs get appended to).
#
# Passed in environment:
#   $LOGNAME is the server log name prefix
#   $LOGDIR is the directory where the log files are found.
#   $MATCH contains the line found in the logfile via grep.
#   $SCRIPT_TIME contains the date string from when this script was invoked.
#
# Returns 0 on failure (too old), 1 on success
#
  MATCHDATE="`echo $MATCH | awk '{ printf "%s%s%s%s",substr($1,1,8),substr($1,10,2),substr($1,13,2),substr($1,16,2) }'`"
  SCRIPTDATE="`echo $SCRIPT_TIME | awk '{ printf "%s%s%s%s",substr($1,1,8),substr($1,9,2),substr($1,11,2),substr($1,13,2) }'`"


#echo Match is "$MATCHDATE"
#echo ScriptDate is "$SCRIPTDATE"
#echo ScriptTime is "$SCRIPT_TIME"

  if [ $SCRIPTDATE -lt $MATCHDATE ];
  then
    return 1; # Good match
  else
    return 0; # Bad match
  fi
}

new_day_match ()
{
#
# There is a very slight possibility that the date
# rolled over between the time that the boot script started and the
# time that the server created the log file. See if the day changed.
# If so, reset the logfile pointer and check one final time.
#
# Passed in environment:
#   $LOGNAME is the server log name prefix
#   $LOGDIR is the directory where the log files are found.
#   $SERVER_UP is the pattern used by grep to search the log file.
#   $SCRIPT_TIME contains the date string from wheh this script was invoked.
#
# Returns 0 on match failure, 1 on success
#
  CURDAY=`date +%d`
  SCRIPT_DAY="`echo $SCRIPT_TIME | awk '{ printf substr($1,7,2) }'`"

  if [ "$SCRIPT_DAY" != "$CURDAY" ]; # day must have rolled over
  then
  {
    CHKLOG="`echo $LOGNAME $SCRIPT_TIME $CURDAY | awk '{ printf "%s_%s.%s.%s.log",$1,substr($2,1,4),substr($2,5,2),$3 }'`"
#echo Curday CHKLOG is "$CHKLOG"

    if [ -r "$LOGDIR/$CHKLOG" ]; # does a new log file exist?
    then
    {
      MATCH=`grep "$SERVER_UP" "$LOGDIR/$CHKLOG"`;
      #
      # Find any "server up" indication?
      #
      if [ -z "$MATCH" ];
        then return 0;  # No. 
        else return 1;  # Yes, by definition, this instance is newer than
      fi                #   the boot script run time, so server is up.
    }
    else
      return 0; # No such log file
    fi
  }
  fi

  return 0; # Day didn't roll over
}

start_metadata_server()
{
#
# Start SAS Metadata Server
#
#echo Start metadata
  if [ -x $METADATA_SERVER_DIR/MetadataServer.sh ];
  then
  {
#echo do metadata script
    $METADATA_SERVER_DIR/MetadataServer.sh start >/dev/null 2>&1

    if [ "$?" -ne 0 ]; 
      then return 1;
    fi
#echo do logname
    LOGNAME="MetadataServer"
    LOGDIR="$METADATA_SERVER_LOGS"
    SERVER_UP="$METADATA_SERVER_UP"

#echo calling is_up
    is_server_up;
    if [ "$?" -eq 1 ]; 
      then return 0;  # Yes
      else return 1;  # No
    fi
  }
  fi
  return 1;
}

start_olap_server()
{
  if [ -x $OLAP_SERVER_DIR/OLAPServer.sh ];
  then
  {
    $OLAP_SERVER_DIR/OLAPServer.sh start >/dev/null 2>&1
    if [ "$?" -ne 0 ]; 
      then return 1;
    fi
    LOGNAME="OLAPServer"
    LOGDIR="$OLAP_SERVER_LOGS"
    SERVER_UP="$OLAP_SERVER_UP"

    is_server_up;
    if [ "$?" -eq 1 ]; 
      then return 0;  # Yes
      else return 1;  # No
    fi
  }
  fi
  return 1;
}

start_object_spawner()
{
  if [ -x $OBJECT_SPAWNER_DIR/ObjectSpawner.sh ];
  then
  {
    $OBJECT_SPAWNER_DIR/ObjectSpawner.sh start >/dev/null 2>&1
    if [ "$?" -ne 0 ]; 
      then return 1;
    fi
    LOGNAME="objspawn_console"
    LOGDIR="$OBJECT_SPAWNER_LOGS"
    SERVER_UP="$OBJECT_SPAWNER_UP"
    SERVER_PID_FILE="$OBJECT_SPAWNER_DIR/server.pid"
#
# ObjectSpawner is a special case: it doesn't timestamp entries in
# its logfile. The best we can do at present is check for an "alive"
# message, then check for an active PID associated with the task.
#
    is_server_up_nostamp;
    if [ "$?" -eq 1 ]; 
      then return 0;  # Yes
      else return 1;  # No
    fi
  }
  fi
  return 1; # can't execute the server script
}

start_share_server()
{
  if [ -x $SHARE_SERVER_DIR/ShareServer.sh ];
  then
  {
    $SHARE_SERVER_DIR/ShareServer.sh start >/dev/null 2>&1
    rc=$?;
    return $rc;
  }
  fi
  return 1;
}

start_connect_server()
{
  if [ -x $CONNECT_SERVER_DIR/ConnectServer.sh ];
  then
  {
    $CONNECT_SERVER_DIR/ConnectServer.sh start >/dev/null 2>&1
    rc=$?;
    return $rc;
  }
  fi
  return 1;
}

stop_metadata_server()
{
  if [ -x $METADATA_SERVER_DIR/MetadataServer.sh ];
  then
  {
    $METADATA_SERVER_DIR/MetadataServer.sh stop >/dev/null 2>&1
    rc=$?;
    return $rc;
  }
  fi
  return 1;
}

stop_olap_server()
{
  if [ -x $OLAP_SERVER_DIR/OLAPServer.sh ];
  then
  {
    $OLAP_SERVER_DIR/OLAPServer.sh stop >/dev/null 2>&1
    rc=$?;
    return $rc;
  }
  fi
  return 1;
}

stop_object_spawner()
{
  if [ -x $OBJECT_SPAWNER_DIR/ObjectSpawner.sh ];
  then
  {
    $OBJECT_SPAWNER_DIR/ObjectSpawner.sh stop >/dev/null 2>&1
    rc=$?;
    return $rc;
  }
  fi
  return 1;
}

stop_share_server()
{
  if [ -x $SHARE_SERVER_DIR/ShareServer.sh ];
  then
  {
    $SHARE_SERVER_DIR/ShareServer.sh stop >/dev/null 2>&1
    rc=$?;
    return $rc;
  }
  fi
  return 1;
}

stop_connect_server()
{
  if [ -x $CONNECT_SERVER_DIR/ConnectServer.sh ];
  then
  {
    $CONNECT_SERVER_DIR/ConnectServer.sh stop >/dev/null 2>&1
    rc=$?;
    return $rc;
  }
  fi
  return 1;
}

Debug_Logmsg() 
{
  echo "$*"
}

Mandriva_Logmsg() 
{
  echo "$*"
}

RHEL_Logmsg() 
{
  echo "$*"
}

SUSE_Logmsg() 
{
  echo "$*"
}

AIX_Logmsg() 
{
  echo "$*"
}

H6I_Logmsg() 
{
  echo "$*"
}

SOL9_Logmsg() 
{
  echo "$*"
}

SOL10_Logmsg() 
{
  echo "$*"
}

HPUX_Logmsg() 
{
  echo "$*"
}

start_servers ()
{
  #
  # We use the current time to figure out which log file to check
  #
  # This could break if the system is rebooted right at midnight, since the date
  # may wrap. We'll check for that if the initial log file existence fails.
  #
  SCRIPT_TIME=`date +%Y%m%d%H%M%S`

  #
  # Crank everything up
  #

  $Logmsg "Starting SAS servers"

  #
  # SAS Metadata server has to precede the others.
  #
#echo has_meta $HAS_METADATASERVER
  if [ -z "$HAS_METADATA_SERVER" ];
  then
  {
  #
  # if no MetadataServer is installed, nothing else should be started.
  #
    $Logmsg "SAS Metadata Server is NOT installed."
    $Logmsg "The following SAS servers will NOT be started as a result:"
    SRVLIST="  "
    if [ -n "$HAS_OLAP_SERVER" ]; then SRVLIST="$SRVLIST OLAP"; fi
    if [ -n "$HAS_OBJECT_SPAWNER" ]; then SRVLIST="$SRVLIST OBJECT_SPAWNER"; fi
    if [ -n "$HAS_SHARE_SERVER" ]; then SRVLIST="$SRVLIST SHARE_SERVER"; fi
    if [ -n "$HAS_CONNECT_SERVER" ]; then SRVLIST="$SRVLIST CONNECT_SERVER"; fi
    $Logmsg "$SRVLIST";
    return 1;
  }
  else
  {
    start_metadata_server;
#echo back from start meta
    if [ "$?" -eq 0 ];
      then
      {
        $Logmsg "SAS Metadata Server is UP";
      }
      else
      {
        $Logmsg "SAS Metadata Server is NOT up";
        $Logmsg "The following SAS servers will NOT be started as a result:"
        SRVLIST="  "
        if [ -n "$HAS_OLAP_SERVER" ]; then SRVLIST="$SRVLIST OLAP"; fi
        if [ -n "$HAS_OBJECT_SPAWNER" ]; then SRVLIST="$SRVLIST OBJECT_SPAWNER"; fi
        if [ -n "$HAS_SHARE_SERVER" ]; then SRVLIST="$SRVLIST SHARE_SERVER"; fi
        if [ -n "$HAS_CONNECT_SERVER" ]; then SRVLIST="$SRVLIST CONNECT_SERVER"; fi
        $Logmsg "$SRVLIST";
        return 1;
      }
    fi
  }
  fi
  #
  # If we got here, Metadata is up, so try to start the additonal servers.
  # Note that even if one of these fails to start, the process will continue
  # starting the others. Success/Failure is sent to the log.
  #
  if [ -n "$HAS_OLAP_SERVER" ]
  then
  {
    start_olap_server;
    if [ "$?" -eq 0 ];
    then $Logmsg "SAS OLAP Server is UP";
    else $Logmsg "SAS OLAP Server is NOT up";
    fi;
  }
  fi

  if [ -n "$HAS_OBJECT_SPAWNER" ]
  then
  {
    start_object_spawner;
    if [ "$?" -eq 0 ];
    then $Logmsg "SAS Object Spawner is UP";
    else $Logmsg "SAS Object Spawner is NOT up";
    fi;
  }
  fi

  if [ -n "$HAS_SHARE_SERVER" ]
  then
  {
    start_share_server;
    if [ "$?" -eq 0 ];
    then $Logmsg "SAS Share Server is UP";
    else $Logmsg "SAS Share Server is NOT up";
    fi;
  }
  fi

  if [ -n "$HAS_CONNECT_SERVER" ]
  then
  {
    start_connect_server;
    if [ "$?" -eq 0 ];
    then $Logmsg "SAS Connect Server is UP";
    else $Logmsg "SAS Connect Server is NOT up";
    fi;
  }
  fi
}


stop_servers ()
{
  #
  # Shut everything down
  # We assume that the assorted "stop" scripts will succeed.
  #

  $Logmsg "Stopping SAS servers"

  if [ -n "$HAS_OLAP_SERVER" ]
  then stop_olap_server; fi;

  if [ -n "$HAS_OBJECT_SPAWNER" ]
  then stop_object_spawner; fi;

  if [ -n "$HAS_SHARE_SERVER" ]
  then stop_share_server; fi;

  if [ -n "$HAS_CONNECT_SERVER" ]
  then stop_connect_server; fi;

  #
  # stop Metadata last since some of the other servers depend on it.
  #
  if [ -n "$HAS_METADATA_SERVER" ];
  then stop_metadata_server; fi;
}

#
# Main processing routine
#

# To avoid protection issues for installs mounted over NFS, rerun
# ourselves as the UID that owns the installed SAS code.
#
#echo UID is `$WHOAMI`

if [ `$WHOAMI` != "$SASUID" ];
then
{
#echo Invoking su $SASUID -c $0 $1

  su "$SASUID" -c "$0 $1"
  exit $?
}
fi

case "$1" in
  start)
    start_servers;
    exit $?
    ;;

  stop)
    stop_servers;
    ;;

  restart|reload)
    stop_servers;
    start_servers;
    exit $?
    ;;

  status)
    server_status;
    exit $?
    ;;

  *)
    $Logmsg "$0: Unknown option"
    exit 1;

esac