#!/bin/sh # # $Id: nsr_shutdown.sh,v 6.66 2005/12/20 23:57:40 tompkb1 Exp $ Copyright 2005 EMC Corporation. # # # Copyright (c) 2005 EMC Corporation. # # All rights reserved. This is an UNPUBLISHED work, and # comprises proprietary and confidential information of EMC. # Unauthorized use, disclosure, and distribution are strictly # prohibited. Use, duplication, or disclosure of the software # and documentation by the U.S. Government is subject to # restrictions set forth in a license agreement between the # Government and EMC or other written agreement specifying # the Government's rights to use the software and any applicable # FAR provisions, such as FAR 52.227-19. # PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb; export PATH UNIX95=Y; export UNIX95 NSR_RUN=/nsr/run NSR_TMP=/nsr/tmp/sec NSR_SERVICES=$NSR_TMP/services NSR_KILLED=$NSR_TMP/killed PROG=`basename $0` PIDFILE=$NSR_TMP/$PROG.pid PIDFILE_EXPIRATION=300 MODE=NORMAL TIMETOKILL=180 case `uname` in AIX | HP-UX | IRIX* | OSF1 | SunOS ) PSOPS="eo pid,ppid,pgid,comm";; Linux ) PSOPS="eo pid,ppid,pgrp,comm";; Darwin ) PSOPS="axco pid,ppid,pgid,command";; esac Usage() { printf "%s: Usage: %s [ -fq | -n | -l ] [ -t timeout ] [ service ... ]\n" \ $PROG $PROG >&2 exit 1 } Cleanup() { rm -f $NSR_SERVICES \ $NSR_SERVICES.tmp \ $NSR_KILLED \ $NSR_TMP/*.dep \ $PIDFILE } GetTime() { set -- `date -u '+%Y %j %H %M %S'` CURRENT_MINS=`expr 60 \* $3 + $4` CURRENT_SECS=`expr 3600 \* $3 + 60 \* $4 + $5` YEARSSINCE1970=`expr $1 - 1970` YEARSSINCE1969=`expr $1 - 1969` LEAPYEARS=`expr $YEARSSINCE1969 / 4` EPOCH_DAYS=`expr 365 \* $YEARSSINCE1970 + $LEAPYEARS + $2 - 1` EPOCH_MINS=`expr 1440 \* $EPOCH_DAYS + $CURRENT_MINS` EPOCH_SECS=`expr 86400 \* $EPOCH_DAYS + $CURRENT_SECS` echo $EPOCH_SECS } GetPIDsFromProcess() { ps -$PSOPS | grep $1 | while read PID pPID PGID COMM; do if [ "`basename $COMM`" = "$1" ] && [ $PID -eq $PGID ]; then echo $PID fi done } GetChildPIDsFromPPID() { ps -$PSOPS | grep $1 | while read PID pPID PGID COMM; do if [ $pPID -eq $1 ] || \ [ $pPID -eq 1 -a $PGID -eq $1 -a $PID -ne $1 ]; then echo $PID fi done } GetPIDsFromGPID() { ps -$PSOPS | grep $1 | while read PID pPID PGID COMM; do if [ $PGID -eq $1 ]; then echo $PID fi done } GetProcessFromPID() { ps -$PSOPS | grep $1 | while read PID pPID PGID COMM; do if [ $PID -eq $1 ]; then echo `basename $COMM` fi done } GetNameFromRunfile() { echo $1 | cut -f1 -d. } GetPIDFromRunfile() { echo $1 | cut -f2 -d. } AlreadyRunning() { if [ -f $PIDFILE ]; then read PID CREATION < $PIDFILE if [ "`GetProcessFromPID $PID`" -a \ `expr $CREATION + $PIDFILE_EXPIRATION` -gt `GetTime` ]; then echo $PID else rm -f $PIDFILE fi fi } ListProcessTree() { if [ ! "$3" ] || \ [ ! "`GetProcessFromPID $3`" -a ! "`GetPIDsFromGPID $3`" ]; then return elif [ $1 -eq 0 ]; then if [ "$MODE" != "LIST" ]; then printf "$3\n" else printf "+--o %s " $2 [ "`GetProcessFromPID $3`" ] && printf "(%d)\n" $3 || \ printf "(%s)\n" "???" fi for PID in `GetChildPIDsFromPPID $3`; do ListProcessTree `expr $1 + 1` `GetProcessFromPID $PID` $PID done else DEPTH=`expr $1 + 1` OFFSET=`expr $DEPTH \* 4` if [ "$MODE" != "LIST" ]; then printf "$3\n" else printf "%`expr $OFFSET - 1`s %s (%d)\n" "+--o" \ `GetProcessFromPID $PID` $PID fi for PID in `GetChildPIDsFromPPID $3`; do ListProcessTree $DEPTH `GetProcessFromPID $PID` $PID done fi } RemoveService() { rm -f $NSR_TMP/$1.dep for DEPFILE in `find $NSR_TMP -name *.dep 2> /dev/null`; do sed -e s/$1//g $DEPFILE > $DEPFILE.tmp mv -f $DEPFILE.tmp $DEPFILE done if [ -f "$NSR_SERVICES" ]; then cat $NSR_SERVICES | grep -v $1 > $NSR_SERVICES.tmp mv -f $NSR_SERVICES.tmp $NSR_SERVICES fi } KillService() { [ -f "$NSR_TMP/$1.$2.dep" ] && DEPENDS="`cat $NSR_TMP/$1.$2.dep`" || \ DEPENDS="" if [ ! "`GetProcessFromPID $2`" -a ! "`GetPIDsFromGPID $2`" ]; then [ "$MODE" != "QUIET" ] && [ "`grep $1.$2 $NSR_SERVICES`" ] && \ printf "Service %s (%d) shutdown.\n" $1 $2 RemoveService $1.$2 rm -f $NSR_RUN/$1.$2 elif [ "$DEPENDS" ]; then for SERVICE in $DEPENDS; do if [ -f "$NSR_TMP/$SERVICE.dep" ] && \ [ "`grep $1.$2 $NSR_TMP/$SERVICE.dep`" ]; then printf \ "%s: Circular dependency found between services %s and %s.\n"\ $PROG `GetNameFromRunfile $SERVICE` $1 printf "%s: Removing service %s from %s's dependency file.\n" \ $PROG `GetNameFromRunfile $SERVICE` $1 sed -e s/$1.$2//g $NSR_TMP/$1.$2.dep > $NSR_TMP/$1.$2.dep.tmp mv -f $NSR_TMP/$1.$2.dep.tmp $NSR_TMP/$1.$2.dep else for RUNFILE in $NSR_RUN/$SERVICE.*; do KillService `GetNameFromRunfile $SERVICE` \ `GetPIDFromRunfile $SERVICE` done fi done elif [ ! "`grep $1.$2 $NSR_KILLED`" ]; then [ "$MODE" != "QUIET" ] && printf "Stopping service: %s (%s)\n" $1 $2 echo $1.$2 >> $NSR_KILLED if [ "$MODE" = "NORUN" ]; then RemoveService $1.$2 else if [ "`GetProcessFromPID $2`" = "$1" ]; then /bin/kill $2 elif [ ! "`GetProcessFromPID $2`" ]; then /bin/kill -TERM -$2 else RemoveService $1.$2 rm -f $NSR_RUN/$1.$2 fi fi else [ "$MODE" != "QUIET" ] && \ printf "Waiting for service: %s (%s)\n" $1 $2 fi } if [ "`whoami`" != "root" ]; then printf "%s: You must be root to execute %s.\n" $PROG $PROG >&2 exit 1 fi trap "Cleanup" 1 2 13 15 TIMESTAMP=`GetTime` while getopts Aacdflnst:qv ARG do case $ARG in f) FORCE=TRUE;; l) [ "$MODE" != "NORUN" ] && [ "$MODE" != "QUIET" ] \ && MODE=LIST || Usage;; n) [ "$MODE" != "LIST" ] && [ "$MODE" != "QUIET" ] \ && MODE=NORUN || Usage;; t) [ `echo $OPTARG | awk '{print $1 + 0}'` -ne 0 ] || Usage; TIMETOKILL=$OPTARG;; q) [ "$MODE" != "LIST" ] && [ "$MODE" != "NORUN" ] \ && MODE=QUIET || Usage;; A | a | c | d | s | v) printf "%s: Option no longer supported -- %s\n" $PROG $ARG >&2 && \ Usage;; \?) Usage;; esac done umask 022 if [ -d "$NSR_RUN" ]; then printf "" > $NSR_SERVICES.tmp printf "" > $NSR_SERVICES for SERVICE in `ls $NSR_RUN`; do [ "$SERVICE" = ".nsr" ] && continue ENTRY=`echo $SERVICE | \ sed -n "/^[a-zA-Z][a-zA-Z]*\.[0-9][0-9]*$/p" ` if [ -f "$NSR_RUN/$ENTRY" ]; then printf "%s\n" $ENTRY >> $NSR_SERVICES.tmp else if [ "$MODE" != "QUIET" ]; then printf "%s: Removing corrupt/illegal run file: %s\n" \ $PROG $SERVICE >&2 fi rm -f $NSR_RUN/$SERVICE fi done else if [ "$MODE" != "QUIET" ]; then printf \ "%s: /nsr directory hierarchy does not exist or is incomplete.\n" \ $PROG >&2 fi exit 1 fi if [ ! "`cat $NSR_SERVICES.tmp`" ]; then if [ "$MODE" != "QUIET" ]; then printf "%s: There are currently no running NetWorker processes.\n" \ $PROG >&2 fi exit 1 fi PID="`AlreadyRunning`" if [ "$PID" ]; then printf "Found %s process (%d) already running.\n" $PROG $PID >&2 exit 1 else printf "%d %d" $$ `GetTime` > $PIDFILE fi printf "" > $NSR_KILLED shift `expr $OPTIND - 1` if [ "$*" ]; then for SERVICE in $*; do SERVICE=`basename $SERVICE` cat $NSR_SERVICES.tmp | sed -n "/^$SERVICE\.[0-9][0-9]*$/p" \ >> $NSR_SERVICES ADDED=`grep "^$SERVICE\.[0-9]" $NSR_SERVICES` if [ ! "$ADDED" ]; then printf "%s: Invalid service or parent process: %s\n" \ $PROG `basename $SERVICE` >&2 fi done else mv $NSR_SERVICES.tmp $NSR_SERVICES fi for SERVICE in `cat $NSR_SERVICES`; do rm -f $NSR_TMP/$SERVICE.dep for DEPENDENCY in `cat $NSR_RUN/$SERVICE`; do for LISTING in $NSR_RUN/$DEPENDENCY.*; do if [ -f "$LISTING" ]; then LISTING=`basename $LISTING` echo $LISTING >> $NSR_TMP/$SERVICE.dep fi done done done TIMEOUT=`expr $TIMESTAMP + $TIMETOKILL` case $MODE in LIST ) if [ "`cat $NSR_SERVICES`" ]; then for SERVICE in `cat $NSR_SERVICES`; do ListProcessTree 0 `GetNameFromRunfile $SERVICE` \ `GetPIDFromRunfile $SERVICE` RemoveService $SERVICE done exit 0 else exit 1 fi ;; * ) while [ "`cat $NSR_SERVICES`" ] && [ $TIMEOUT -gt `GetTime` ]; do while read SERVICE; do KillService `GetNameFromRunfile $SERVICE` \ `GetPIDFromRunfile $SERVICE` done <$NSR_SERVICES if [ "$MODE" != "NORUN" ]; then sleep 5 fi done;; esac [ -f "$NSR_SERVICES" ] && LIVING_SERVICES=`cat $NSR_SERVICES` Cleanup if [ "$LIVING_SERVICES" ]; then for SERVICE in $LIVING_SERVICES; do PID=`GetPIDFromRunfile $SERVICE` NAME=`GetNameFromRunfile $SERVICE` if [ "$FORCE" = "TRUE" ]; then if [ "$MODE" != "QUIET" ]; then printf "Forcefully killing service: %s (%s)\n" $NAME $PID fi for PID in `ListProcessTree 0 $NAME $PID`; do /bin/kill $PID done sleep 2 for PID in `ListProcessTree 0 $NAME $PID`; do /bin/kill -KILL $PID done RemoveService $SERVICE rm -f $NSR_RUN/$SERVICE else printf "%s: Failed to shutdown service: %s (%d)\n" $PROG $NAME \ $PID >&2 exit 1 fi done fi exit 0