#!/usr/bin/ksh
#
# SAMPLE NAME: stopCMVC [familyName]
#
# FUNCTIONS:   This sample shell script stops all daemons for the specified
#              CMVC family.  Both the cmvcd and notifyd daemons will be
#              stopped.
#              This sample shell also cleans up shared memory and semaphores,
#              if necessary.
#
#              This script must be run from the family account on the CMVC
#              server.
#
#              NOTE: 
#              * The behavior of this module has been modified to 
#                minimize use of memory intensive routines such as
#                'awk' and to try to avoid possible truncation during
#                'ps' on SunOS
#              * For Oracle, to avoid unnecessary error messages in the syslog
#                just kill the children and this action will kill the parents.
#
# ENVIRONMENT
# VARIABLE(S): n/a
#
# ORIGINS:     27
#
# 5765-039 (C) COPYRIGHT International Business Machines Corp. 1991,1993
# 5765-069 (C) COPYRIGHT International Business Machines Corp. 1991,1993
# 5765-207 (C) COPYRIGHT International Business Machines Corp. 1993,1998
# 5765-202 (C) COPYRIGHT International Business Machines Corp. 1993,1998
# 5622-063 (C) COPYRIGHT International Business Machines Corp. 1993,1998
# 5765-397 (C) COPYRIGHT International Business Machines Corp. 1994,1998
# All Rights Reserved
# Licensed Materials - Property of IBM
#
# US Government Users Restricted Rights - Use, duplication or
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
#
#
#           NOTICE TO USERS OF THE SOURCE CODE EXAMPLES
#
# INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THE SOURCE CODE
# EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, "AS IS" WITHOUT
# WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
# LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
# OF THE SOURCE CODE EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS,
# IS WITH YOU.  SHOULD ANY PART OF THE SOURCE CODE EXAMPLES PROVE
# DEFECTIVE, YOU (AND NOT IBM OR AN AUTHORIZED RISC System/6000* WORKSTATION
# DEALER) ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR
# CORRECTION.
#
# * RISC System/6000 is a trademark of International Business Machines
#   Corporation.
#
# /usr/lpp/cmvc/samples/stopCMVC
#

#-------------------------------------------------------+
# Return a string identifying the operating system.
# Output:  OPSYS = (AIX, HP-UX, SunOS, Solaris)
#-------------------------------------------------------+
get_opsys()
{
raw=`uname -a`
OPSYS=`echo $raw | cut -f1 -d' '`

# Test for Solaris (5... or higher) or SunOS (4...)
# The problem is that the Solaris op-sys is identified as SunOS, and
# there is no string that indicates that is "Solaris". The distinction
# is done only by the version number.

if [ "$OPSYS" = "SunOS" ]
then
   var=`echo $raw | cut -f3 -d' ' | cut -c1-1`
   if [ $var -ne 4 ]
     then
       OPSYS="Solaris"
   fi
fi
export OPSYS
#   print "get_opsys: " $OPSYS
}

#---------------------------------------------------------------------+
#  Returns a string identifying the database that is used by the
#  CMVC cmvcd executable which is found first in the PATH.
#  OUTPUT:   CMVCDB = (DB2, DB2V2, Oracle, Sybase, Informix)
#---------------------------------------------------------------------+
get_database()
{
# First, determine which is the actual cmvcd that is executed.
# This is important because the family might be using a cmvcd executable
# that does not reside in /usr/lpp/cmvc/bin.

if [ "$OPSYS" = "HP-UX" ]
then
   which_cmvcd=`whence cmvcd`
else
   which_cmvcd=`which cmvcd`
fi

# Then get the line that mentions the database name. The format should
# be "cmvc Database: name".
# If the string is not found, then this means that the CMVC version is
# earlier than 2.3 (that is, 2.1 or 2.2, which did not have the necessary
# what strings).

database_row=`what $which_cmvcd | grep "Database: "`
if [ "$database_row" = "" ]
then
   print "The cmvcd version is not 2.3, and it does not contain \n"
   print "the explicit information about which database is used.\n"
   print "Therefore, there will not be a special handling for Oracle,\n"
   print "which means that some warning messages may be added to the\n"
   print "syslog when killing the parent daemons.\n"
#  Assume DB2, which will NOT do the special processing for Oracle
   export CMVC_DB=`DB2`
else
#  Finally, get the actual database name.
   export CMVC_DB=`echo $database_row | cut -d" " -f3`
fi

#   print "get_database: " $CMVC_DB
}

#---------------------------------------------------------------------+
# Check whether a process has died and if not, wait until it is dead.
#---------------------------------------------------------------------+
check_process()
{
  CHECK_PID="$1"
  check1=1
  while [ check1 -eq 1 ]
    do
     case "$UNAME" in
     AIX)
     #-----------------------------------------------------
     # Fixed a bug where the process dies very fast and the
     # PID is re-used by some other user.    CDC  18 Apr 97
     #-----------------------------------------------------
     check1=`ps -p $CHECK_PID -o ruser | grep " $FAMILY "`
     ;;
     Solaris)
     #-----------------------------------------------------
     # Fixed a bug where the process dies very fast and the
     # PID is re-used by some other user.    CDC  18 Apr 97
     #-----------------------------------------------------
     check1=`ps -p $CHECK_PID -o ruser | grep "$FAMILY"`
     ;;
     HP-UX)
     #-----------------------------------------------------
     # Fixed a bug where the process dies very fast and the
     # PID is re-used by some other user.    CDC  18 Apr 97
     #-----------------------------------------------------
     check1=`ps -p $CHECK_PID | grep -v PID`
     ;;
     SunOS)
      check1=`ps -aux | grep -v grep | grep $CHECK_PID`
     ;;
     esac

    if [ -n "$check1" ]
      then
              check1=1
              sleep 1
    else
              check1=0
    fi
  done
}

#-------------------------------------------------------+
# Main part begins
#-------------------------------------------------------+

get_opsys    # get operating system in variable OPSYS
get_database # get name of database used by the cmvcd executable

if [ $# -gt 1 ] 
then
   print "\nusage: $0 familyName\n"
   print "This sample shell script stops all daemons for the specified"
   print "CMVC family. Both the cmvcd and notifyd daemons will be"
   print "stopped.\n"
   print "This script must be run from the family account on the CMVC"
   print "server.\n"
   exit 1
else
   if [ $# -eq 0 ]
   then
      FAMILY=`echo $CMVC_FAMILY | cut -d"@" -f1`
   else
      FAMILY="$1"
   fi
   print "stopCMVC: beginning the process to stop the CMVC family daemons and"
   print "          to cleanup shared memory and semaphores, if needed, for"
   print "          family: $FAMILY"
   print ""
fi

# Initialize list variables
notifydPIDs=""
parentDaemonPIDs=""
childDaemonPIDs=""

# -------------------------------------------------------------------
# Search for and gracefully terminate the notifyd daemon
# -------------------------------------------------------------------
print "Searching for the notify daemon for CMVC family $FAMILY"

UNAME=$OPSYS    # obtained by get_opsys()

case "$UNAME" in
AIX|HP-UX|Solaris)

   # Find all notifyd processes (less chance of truncation with this ps)
   # - just return processes
   # - limit to userid (for speed)
   psList=`ps -fu $FAMILY | grep "notifyd" | grep -v "grep" | awk '{ printf " %d \n", $2 }'`

   # Get list of running processes for notifyd
   # - Narrow list to specific users shells 
   # - only need pid
   # - can narrow to exact match for speed
   ps -fu $FAMILY | grep "notifyd" | awk '{ printf "%d\n", $2 }' > /tmp/stopCMVC.$FAMILY
;;
SunOS)

   # Find all notifyd processes (less chance of truncation with this ps)
   # - just return processes
   psList=`ps -ax | grep "notifyd" | grep -v "grep" | awk '{ printf " %d \n", $1 }'`

   # Get list of running processes for notifyd
   # - Narrow list to specific users shells 
   # - only need pid
   ps -aux | grep $FAMILY | awk '{ printf "%d\n", $2 }' > /tmp/stopCMVC.$FAMILY
;;
esac

# Read through list of processes, and append matches for notifyd to
# appropriate lists
while read pid 
do
   # Check for notifyd process
   x=`echo "$psList" | grep " $pid "`

   if [ "$x" != "" ]
   then
      notifydPIDs="$notifydPIDs$pid "
   fi
done < /tmp/stopCMVC.$FAMILY

if [ -n "$notifydPIDs" ]
then
	print "The following notify daemon will be gracefully terminated:"
	print "$notifydPIDs"
	print "Working...please wait"
        kill -15 $notifydPIDs
        # -------------------------------------------
        # Check that these daemons have terminated
        # -------------------------------------------
        for daemonPID in $notifydPIDs
        do
             check_process $daemonPID
        done
	found=1
else
        print "The notify daemon was not running for CMVC family $FAMILY"
fi


# -------------------------------------------------------------------
# Search for all cmvcd daemons
# -------------------------------------------------------------------
print " "
print "Searching for all cmvcd daemons for CMVC family $FAMILY"

case "$UNAME" in
AIX|HP-UX)

   # Find all "cmvcd" processes for userid specified ($FAMILY)
   # - select ps options least likely to truncate command string
   #   (e.g. notify instead of notifyd)
   # - return process number and owner
   # - exclude grep
   # - inserting space to insure exact match for grep in loop below
   psList=`ps -fu $FAMILY | grep "cmvcd" | grep "$FAMILY" | grep -v "grep" | awk '{ printf "  %d \n", $2 }'`

   # Get list of running processes
   # - Narrow list to specific users to improve performance
   ps -fu $FAMILY | grep "cmvcd" | awk '{ printf "%d %d\n", $3, $2 }' > /tmp/stopCMVC.$FAMILY
;;
Solaris)

   # Find all "cmvcd $FAMILY" processes 
   # - select ps options least likely to truncate command string
   #   (e.g. notify instead of notifyd)
   # - return process number and owner
   # - exclude grep
   # - inserting space to insure exact match for grep in loop below
   psList=`ps -ef | grep "cmvcd" | grep "$FAMILY" | grep -v "grep" | awk '{ printf "  %d \n", $2 }'`

   # Get list of running processes
   # - Narrow list to specific users to improve performance
   ps -ef | grep "cmvcd" | grep "$FAMILY" | grep -v "grep" | awk '{ printf "%d %d\n", $3, $2 }' > /tmp/stopCMVC.$FAMILY
;;
SunOS)

   # Find all "cmvcd" processes for userid specified ($FAMILY)
   # - select ps options least likely to truncate command string 
   #   (e.g. notify instead of notifyd)
   # - return process number and owner
   # - exclude grep 
   # - inserting space to insure exact match for grep in loop below
   psList=`ps -ax | grep "cmvcd" | grep "$FAMILY" | grep -v "grep" | awk '{ printf " %d \n", $1 }'`

   # Get list of running processes
   # - Narrow list to specific users 
   # - order by ppid, pid
   ps -ajx | awk '{ printf "%d %d\n", $1, $2 }' > /tmp/stopCMVC.$FAMILY
;;
esac

# Read through list of processes, and append matches for cmvcd to
# appropriate lists
while read ppid pid 
do
   # Check for cmvcd process in current parent-child combination
   # - space in grep is required for exact match
   x=`echo "$psList" | grep " $pid "`

   # Non-blank is a match
   if [ "$x" != "" ]
   then
       # if ppid = 1, process is a parent, otherwise it is a child
       if [ "$ppid" = "1" ]
       then
          parentDaemonPIDs="$parentDaemonPIDs$pid "
       else
          childDaemonPIDs="$childDaemonPIDs$pid "
       fi
   fi
done < /tmp/stopCMVC.$FAMILY

# remove file once done
rm -f /tmp/stopCMVC.$FAMILY



# -------------------------------------------------------------------
# Gracefully terminate all parent cmvcd daemons
# If using Oracle, skip it.
# -------------------------------------------------------------------

if [ "$CMVC_DB" = "Oracle" ] || [ "$CMVC_DB" = "Informix" ]
then
   print " "
   print "When using Oracle or Informix, skip killing the parent daemons "
   print "to avoid unnecessary messages in the syslog."
else
   print " "
   if [ -n "$parentDaemonPIDs" ]
   then
	print "The following cmvc parent daemons will be gracefully terminated:"
	print "$parentDaemonPIDs"
	print "Working...please wait"
        kill -15 $parentDaemonPIDs
	# -------------------------------------------
	# Check that these daemons have terminated 
	# -------------------------------------------
        for daemonPID in $parentDaemonPIDs
        do
             check_process $daemonPID
        done
   else
        print "No cmvc parent daemons were running for CMVC family $FAMILY"
   fi
fi

# -------------------------------------------------------------------
# Gracefully terminate all child cmvcd daemons
# If using Oracle, then this action will kill the parents.
# -------------------------------------------------------------------

print " "
if [ -n "$childDaemonPIDs" ]
then
	print "The following cmvc child daemons will be gracefully terminated:"
	print "$childDaemonPIDs"
	print "Working...please wait"
        kill -15 $childDaemonPIDs
        # -------------------------------------------
        # Check that these daemons have terminated
        # -------------------------------------------
        for daemonPID in $childDaemonPIDs
        do
             check_process $daemonPID
        done
else
        print "No cmvc child daemons were running for CMVC family $FAMILY"
fi


# -------------------------------------------------------------------
# For shared memory and semaphores cleanup
# -------------------------------------------------------------------

print " "
print "Cleaning up shared memory and semaphores, if necessary."

for type in m s q
do
   # Identify type for user
   if [ "$type" = "m" ]
   then
      print "   Shared memory:"
   elif [ "$type" = "s" ]
   then
      print "   Semaphores:"
   else
      print "   Queues:"
   fi

   # Identify which owned by user - $FAMILY
   ilist=`ipcs -${type} | grep " $FAMILY " | tr -d 'msq' | awk '{ printf("%s ",$1) }' - `
   if [ "$ilist" != "" ] 
   then 
      # Delete all owned by user - $FAMILY
      for sem_num in $ilist
      do
         print "      Cleaning $sem_num"
         ipcrm -${type} $sem_num
      done 
   else
      print "      No updates"
   fi
done

# end of file
