#!/bin/sh # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000-2008 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Start or Stop the Performance Co-Pilot Collection Daemon (PMCD) # # The following is for chkconfig on RedHat based systems # chkconfig: 2345 95 05 # description: pmcd is the collection daemon for the Performance Co-Pilot (PCP) # # The following is for insserv(1) based systems, # e.g. SuSE, where chkconfig is a perl script. ### BEGIN INIT INFO # Provides: pmcd # Required-Start: $local_fs # Should-Start: $network $remote_fs $syslog $time # Required-Stop: $local_fs # Should-Stop: $network $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Control pmcd (the collection daemon for PCP) # Description: Configure and control pmcd (the collection daemon for the Performance Co-Pilot) ### END INIT INFO . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/rc-proc.sh PMCD=$PCP_BINADM_DIR/pmcd PMCDOPTS=$PCP_PMCDOPTIONS_PATH PCPLOCAL=$PCP_PMCDRCLOCAL_PATH RUNDIR=$PCP_LOG_DIR/pmcd prog=$PCP_RC_DIR/`basename $0` # search for your mail agent of choice ... # MAIL='' for try in Mail mail email do if which $try >/dev/null 2>&1 then MAIL=$try break fi done tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 status=1 trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 case "$PCP_PLATFORM" in mingw) # nothing we can usefully do here, skip the test # IAM=0 ;; *) # standard Unix/Linux style test # ID=id IAM=`$ID -u 2>/dev/null` if [ -z "$IAM" ] then # do it the hardway # IAM=`$ID | sed -e 's/.*uid=//' -e 's/(.*//'` fi ;; esac _pmcd_logfile() { default=$RUNDIR/pmcd.log $PCP_AWK_PROG <$PMCDOPTS ' BEGIN { logf = "'$default'" } $1 == "-l" { if (NF > 1) logf = $2 } END { print logf }' } _reboot_setup() { # base directories and house-keeping for daemon processes # # For most packages, $PCP_RUN_DIR is included in the package, # but for Debian and cases where /var/run is a mounted filesystem # it may not exist, so create it here before it is used to create # any pid/lock files # # $PCP_RUN_DIR creation is also done in pmlogger_daily, but if pmcd # is running, we'd expect do this one first # if [ ! -d "$PCP_RUN_DIR" ] then mkdir -p -m 775 "$PCP_RUN_DIR" chown $PCP_USER:$PCP_GROUP "$PCP_RUN_DIR" fi # setup and clean up base directories and house-keeping for tracking # pmlogger instances ... needs to be done here because pmcd needs the # information, even if no pmlogger instances are started (and even if # $PCP_RC_DIR/pmlogger is not run) # if [ ! -d "$PCP_TMP_DIR/pmlogger" ] then mkdir -p -m 777 "$PCP_TMP_DIR/pmlogger" chown $PCP_USER:$PCP_GROUP "$PCP_TMP_DIR/pmlogger" else rm -rf $tmp/ent $tmp/pid here=`pwd` cd "$PCP_TMP_DIR/pmlogger" rm -f primary vcr _get_pids_by_name pmlogger | sort >$tmp/pid ls [0-9]* 2>&1 | sed -e '/\[0-9]\*/d' \ | sed -e 's/[ ][ ]*//g' | sort >$tmp/ent # remove entries without a pmlogger process # rm -f `comm -23 $tmp/ent $tmp/pid` rm -f $tmp/ent $tmp/pid cd "$here" fi # Rebuild PMNS? # PMNSDIR=$PCP_VAR_DIR/pmns rebuild=false if [ -d $PMNSDIR -a \( -f $PMNSDIR/.NeedRebuild -o ! -f $PMNSDIR/root \) ] then rebuild=true else num=`find $PMNSDIR -newer $PMNSDIR/root -iname 'root_*' 2>/dev/null | wc -l` [ "$num" -gt 0 ] && rebuild=true fi if $rebuild then if [ -x $PMNSDIR/Rebuild ] then $ECHO $PCP_ECHO_N "Rebuilding PMNS ..." "$PCP_ECHO_C" here=`pwd` cd $PMNSDIR ./Rebuild -du $REBUILDOPT $RC_STATUS -v # The 'root' file does not get updated when data did not change, # so we must touch it to update date. [ $? -eq 0 ] && { rm -f .NeedRebuild; touch root; } cd "$here" fi fi } _pmda_setup() { # Auto-Install PMDAs? # if [ -d $PCP_PMDAS_DIR ] then here=`pwd` cd $PCP_PMDAS_DIR for file in */.NeedInstall do [ "$file" = '*/.NeedInstall' ] && break pmda=`dirname $file` if [ -d "$pmda" -a -f "$pmda/.NeedInstall" ] then cd $pmda $PCP_ECHO_PROG "Installing $pmda PMDA ..." # rename .NeedInstall _before_ calling Install because # Install can call this start script (recursively) and # we don't want to get stuck in an infinite loop. # rm -f .NeedInstall.sav mv .NeedInstall .NeedInstall.sav if ./Install /dev/null then # success $PCP_BINADM_DIR/pmpost "PMDA setup: automated install: $pmda" rm -f .NeedInstall.sav else # put the file back, maybe we'll be luckier next time $PCP_BINADM_DIR/pmpost "PMDA setup: automated install FAILED (exit=$?): $pmda" mv .NeedInstall.sav .NeedInstall fi cd $PCP_PMDAS_DIR fi done cd "$here" fi } _start_pmcheck() { if [ ! -z "$PMCD_WAIT_TIMEOUT" ] then wait_option="-t $PMCD_WAIT_TIMEOUT" else wait_option='' fi if pmcd_wait $wait_option then : else status=$? $PCP_BINADM_DIR/pmpost "pmcd_wait failed in $prog: exit status: $status" if [ ! -z "$MAIL" ] then echo "pmcd_wait exit status: $status" | $MAIL -s "pmcd_wait failed in $prog" root else echo "$prog: pmcd_wait failed: exit status: $status" fi fi } # Use $PCP_PMCDCONF_PATH to find and terminate pipe/socket PMDAs. # (First join up continued lines in config file) # _killpmdas() { if [ ! -f $PCP_PMCDCONF_PATH ] then echo "$prog:"' Warning: pmcd control file '"$PCP_PMCDCONF_PATH"' is missing, cannot identify PMDAs to be terminated.' return fi # Give each PMDA 2 seconds after a SIGTERM to die, then SIGKILL for pmda in `$PCP_AWK_PROG <$PCP_PMCDCONF_PATH ' /\\\\$/ { printf "%s ", substr($0, 0, length($0) - 1); next } { print }' \ | $PCP_AWK_PROG ' $1 ~ /^#/ { next } tolower($3) == "pipe" && NF > 4 { print $5; next } tolower($3) == "socket" && NF > 5 { print $6; next }' \ | sort -u` do pmsignal -a -s TERM `basename $pmda` > /dev/null 2>&1 & done sleep 2 for pmda in `$PCP_AWK_PROG <$PCP_PMCDCONF_PATH ' /\\\\$/ { printf "%s ", substr($0, 0, length($0) - 1); next } { print }' \ | $PCP_AWK_PROG ' $1 ~ /^#/ { next } tolower($3) == "pipe" && NF > 4 { print $5; next } tolower($3) == "socket" && NF > 5 { print $6; next }' \ | sort -u` do pmsignal -a -s KILL `basename $pmda` > /dev/null 2>&1 & done wait } _shutdown() { # Is pmcd running? # _get_pids_by_name pmcd >$tmp/tmp if [ ! -s $tmp/tmp ] then [ "$1" = verbose ] && echo "$prog: pmcd not running" rm -f $PCP_RUN_DIR/pmcd.pid $PCP_RUN_DIR/pmcd.socket return 0 fi # If pmcd is running but we can't find a pidfile, or a logfile at the # configured or default location, assume this script is being run via # a chroot build environment (and hence we do not want to signal pmcd). # logf=`_pmcd_logfile` [ -f $logf ] || logf=$RUNDIR/pmcd.log if [ ! -f $PCP_RUN_DIR/pmcd.pid -a ! -f $logf ] then pmcdpid=`cat $tmp/tmp` echo "PMCD process ... $pmcdpid" echo "$prog: Warning: found no $PCP_RUN_DIR/pmcd.pid and no $logf. Assuming an uninstall from a chroot: pmcd not killed. If this is incorrect, \"pmsignal -s TERM $pmcdpid\" can be used." exit elif [ -f $PCP_RUN_DIR/pmcd.pid ] then TOKILL=`cat $PCP_RUN_DIR/pmcd.pid` if grep "^$TOKILL$" $tmp/tmp >/dev/null then : else echo "PMCD process ... "`cat $tmp/tmp` echo "$prog: Warning: process ID in $PCP_RUN_DIR/pmcd.pid is $TOKILL. Check logfile $logf. When you are ready to proceed, remove $PCP_RUN_DIR/pmcd.pid before retrying." exit fi else TOKILL= fi # Send pmcd a SIGTERM, which is noted as a pending shutdown. # When finished the currently active request, pmcd will close any # connections, wait for any agents, and then exit. # On failure, resort to SIGKILL. # $ECHO $PCP_ECHO_N "Waiting for pmcd to terminate ...""$PCP_ECHO_C" delay=200 # tenths of a second for SIG in TERM KILL do if [ "x$TOKILL" = "x" ] then pmsignal -a -s $SIG pmcd > /dev/null 2>&1 else pmsignal -s $SIG $TOKILL >/dev/null 2>&1 rm -f $PCP_RUN_DIR/pmcd.pid $PCP_RUN_DIR/pmcd.socket fi while [ $delay -gt 0 ] do _get_pids_by_name pmcd >$tmp/tmp [ ! -s $tmp/tmp ] && break 2 pmsleep 0.1 delay=`expr $delay - 1` [ "$SIG" = "TERM" ] && [ `expr $delay % 10` -eq 0 ] \ && $ECHO $PCP_ECHO_N ".""$PCP_ECHO_C" done echo echo "Process ..." if [ "$SIG" = "TERM" ] then $PCP_PS_PROG $PCP_PS_ALL_FLAGS >$tmp/ps sed 1q $tmp/ps for pid in `cat $tmp/tmp` do $PCP_AWK_PROG <$tmp/ps "\$2 == $pid { print }" done echo "$prog: Warning: Forcing pmcd to terminate!" delay=20 else cat $tmp/tmp echo "$prog: Warning: pmcd won't die!" exit fi done _killpmdas $RC_STATUS -v $PCP_BINADM_DIR/pmpost "stop pmcd from $prog" } _usage() { echo "Usage: $prog [-v] {start|restart|condrestart|stop|status|reload|force-reload}" } VERBOSE_CTL=on while getopts v c do case $c in v) # force verbose ... for historical reasons only as $VERBOSE_CTL # is always "on" ;; *) _usage exit 1 ;; esac done shift `expr $OPTIND - 1` if [ $VERBOSE_CTL = on ] then # For a verbose startup and shutdown ECHO=$PCP_ECHO_PROG REBUILDOPT='' VFLAG='-v' else # For a quiet startup and shutdown ECHO=: REBUILDOPT=-s VFLAG= fi if [ "$IAM" != 0 -a "$1" != "status" ] then if [ -n "$PCP_DIR" ] then : running in a non-default installation, do not need to be root else echo "$prog:"' Error: You must be root (uid 0) to start or stop the Performance Co-Pilot pmcd.' exit fi fi # First reset status of this service $RC_RESET # Return values acc. to LSB for all commands but status: # 0 - success # 1 - misc error # 2 - invalid or excess args # 3 - unimplemented feature (e.g. reload) # 4 - insufficient privilege # 5 - program not installed # 6 - program not configured # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signalling is not supported) are # considered a success. case "$1" in 'start'|'restart'|'condrestart'|'reload'|'force-reload') if [ "$1" = "condrestart" ] && ! is_chkconfig_on pmcd then status=0 exit fi _shutdown quietly # Clean the environment for PMCD: # PMCD and PMDA messages should go to stderr, not the GUI notifiers # Clients in these scripts should test PMCD status without TLS/SSL. # unset PCP_STDERR PCP_SECURE_SOCKETS _reboot_setup if [ -x $PMCD ] then if [ ! -f $PCP_PMCDCONF_PATH ] then echo "$prog:"' Error: pmcd control file '"$PCP_PMCDCONF_PATH"' is missing, cannot start pmcd.' exit fi if [ ! -d "$RUNDIR" ] then mkdir -p -m 775 "$RUNDIR" chown $PCP_USER:$PCP_GROUP "$RUNDIR" fi cd "$RUNDIR" # salvage the previous versions of any PMCD and PMDA logfiles # for log in pmcd `sed -e '/^#/d' -e '/\[access\]/q' -e 's/[ ].*//' <$PCP_PMCDCONF_PATH` do if [ -f $log.log ] then rm -f $log.log.prev mv $log.log $log.log.prev fi done $ECHO $PCP_ECHO_N "Starting pmcd ..." "$PCP_ECHO_C" # only consider lines which start with a hyphen # get rid of the -f option # ensure multiple lines concat onto 1 line OPTS=`sed <$PMCDOPTS 2>/dev/null \ -e '/^[^-]/d' \ -e 's/^/ /' \ -e 's/$/ /' \ -e 's/ -f / /g' \ -e 's/^ //' \ -e 's/ $//' \ | tr '\012' ' ' ` $PMCD $OPTS $RC_STATUS -v $PCP_BINADM_DIR/pmpost "start pmcd from $prog" _pmda_setup # force removal of primary pmlogger link ... if primary # pmlogger is started, this will re-create the link # rm -f "$PCP_TMP_DIR/pmlogger/primary" # site-local customisations after PMCD startup # [ -x $PCPLOCAL ] && $PCPLOCAL $VFLAG start fi status=0 ;; 'stop') # site-local customisations before pmcd shutdown # [ -x $PCPLOCAL ] && $PCPLOCAL $VFLAG stop _shutdown verbose status=0 ;; 'status') # NOTE: $RC_CHECKPROC returns LSB compliant status values. $ECHO $PCP_ECHO_N "Checking for pmcd:" "$PCP_ECHO_C" if [ -r /etc/rc.status ] then # SuSE $RC_CHECKPROC $PMCD $RC_STATUS -v status=$? else # not SuSE $RC_CHECKPROC $PMCD status=$? if [ $status -eq 0 ] then $ECHO running else $ECHO stopped fi fi ;; *) _usage ;; esac