summaryrefslogtreecommitdiff
path: root/src/pmdas/shping
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
committerIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
commit47e6e7c84f008a53061e661f31ae96629bc694ef (patch)
tree648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmdas/shping
downloadpcp-debian.tar.gz
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmdas/shping')
-rw-r--r--src/pmdas/shping/GNUmakefile69
-rwxr-xr-xsrc/pmdas/shping/Install222
-rw-r--r--src/pmdas/shping/README91
-rw-r--r--src/pmdas/shping/Remove38
-rw-r--r--src/pmdas/shping/help137
-rw-r--r--src/pmdas/shping/pmda.c257
-rw-r--r--src/pmdas/shping/pmlogconf.summary6
-rw-r--r--src/pmdas/shping/pmns41
-rw-r--r--src/pmdas/shping/root9
-rw-r--r--src/pmdas/shping/sample.conf46
-rw-r--r--src/pmdas/shping/shping.CPUTime.pmchart11
-rw-r--r--src/pmdas/shping/shping.RealTime.pmchart9
-rw-r--r--src/pmdas/shping/shping.c679
-rw-r--r--src/pmdas/shping/shping.h54
-rw-r--r--src/pmdas/shping/shping.response.pmie67
-rw-r--r--src/pmdas/shping/shping.status.pmie63
16 files changed, 1799 insertions, 0 deletions
diff --git a/src/pmdas/shping/GNUmakefile b/src/pmdas/shping/GNUmakefile
new file mode 100644
index 0000000..73b88da
--- /dev/null
+++ b/src/pmdas/shping/GNUmakefile
@@ -0,0 +1,69 @@
+#
+# Copyright (c) 1995-2001 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.
+#
+
+TOPDIR = ../../..
+include $(TOPDIR)/src/include/builddefs
+
+IAM = shping
+DOMAIN = SHPING
+
+CMDTARGETS = $(IAM)$(EXECSUFFIX)
+HFILES = shping.h
+CFILES = shping.c pmda.c
+OTHERS = README root help pmns sample.conf
+CHARTS = shping.CPUTime.pmchart shping.RealTime.pmchart
+PMIECS = shping.status.pmie shping.response.pmie
+
+LSRCFILES = $(OTHERS) $(CHARTS) $(PMIECS) Install Remove pmlogconf.summary
+LLDLIBS = $(PCP_PMDALIB) $(LIB_FOR_PTHREADS)
+
+PMDADIR = $(PCP_PMDAS_DIR)/$(IAM)
+PMCHART = $(PCP_VAR_DIR)/config/pmchart
+PMIE = $(PCP_VAR_DIR)/config/pmieconf/$(IAM)
+LDIRT = *.log *.dir *.pag so_locations a.out domain.h $(CMDTARGETS)
+
+default: build-me
+
+include $(TOPDIR)/src/include/buildrules
+
+ifneq "$(TARGET_OS)" "mingw"
+build-me: $(CMDTARGETS)
+
+install: build-me
+ $(INSTALL) -m 755 -d $(PMDADIR)
+ $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM)
+ $(INSTALL) -m 755 Install Remove $(PMDADIR)
+ $(INSTALL) -m 644 $(OTHERS) domain.h $(PMDADIR)
+ $(INSTALL) -m 644 shping.CPUTime.pmchart $(PMCHART)/shping.CPUTime
+ $(INSTALL) -m 644 shping.RealTime.pmchart $(PMCHART)/shping.RealTime
+ $(INSTALL) -m 755 -d $(PMIE)
+ $(INSTALL) -m 644 shping.status.pmie $(PMIE)/status
+ $(INSTALL) -m 644 shping.response.pmie $(PMIE)/response
+ $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)
+ $(INSTALL) -m 644 pmlogconf.summary $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/summary
+else
+build-me:
+install:
+endif
+
+$(IAM)$(EXECSUFFIX): $(OBJECTS)
+
+shping.o pmda.o: domain.h
+
+domain.h: ../../pmns/stdpmid
+ $(DOMAIN_MAKERULE)
+
+default_pcp: default
+
+install_pcp: install
diff --git a/src/pmdas/shping/Install b/src/pmdas/shping/Install
new file mode 100755
index 0000000..bcca1b1
--- /dev/null
+++ b/src/pmdas/shping/Install
@@ -0,0 +1,222 @@
+#! /bin/sh
+#
+# Copyright (c) 1997,2003 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.
+#
+# Install the shping PMDA and/or PMNS
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+iam=shping
+pmda_interface=2
+forced_restart=false
+
+# Do it
+#
+pmdaSetup
+
+# controls for installation procedures
+#
+daemon_opt=true # can install as daemon
+dso_opt=false
+pipe_opt=true # supports pipe IPC
+socket_opt=false # force pipe IPC
+check_delay=10 # give the PMDA a chance to set itself up
+
+# be careful that mortals cannot write any configuration files, as
+# these would present a security problem
+#
+umask 022
+
+
+# PMDA variables
+#
+tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1
+configfile=""
+cycle=120
+timeout=20
+debug=0
+
+trap "rm -rf $tmp; exit" 0 1 2 3 15
+
+_quit()
+{
+ rm -rf $tmp
+ exit $1
+}
+
+do_debug=false
+
+_parsedefaults()
+{
+ echo "Extracting options from current installation ..."
+ while getopts D:I:d:l:t: c
+ do
+ case $c in
+ \?) echo "Warning: Unrecognized option in $PCP_PMCDCONF_PATH"
+ echo " Remove line for the $iam PMDA in $PCP_PMCDCONF_PATH and re-run ./Install"
+ _quit 2;;
+ D ) debug=$OPTARG;;
+ I ) cycle=$OPTARG;;
+ t ) timeout=$OPTARG;;
+ * ) ;;
+ esac
+ done
+ eval configfile='$'$OPTIND
+}
+
+if $do_pmda
+then
+
+ # set options from $PCP_PMCDCONF_PATH, if possible
+ #
+ ans=`$PCP_AWK_PROG <$PCP_PMCDCONF_PATH '
+$1 == "'$iam'" { printf "%s",$6
+ for (i=7;i<=NF;i++) printf " %s",$i
+ print ""
+ }'`
+ if [ ! -z "$ans" ]
+ then
+ _parsedefaults $ans
+ fi
+
+ default_configfile=./sample.conf
+ if fgrep "CONFIGURE-ME-PLEASE" $default_configfile >/dev/null
+ then
+ # nslookup(1) may be hiding, like for OpenIndiana
+ #
+ export PATH=$PATH:/usr/sbin
+ nslookup=`which nslookup 2>/dev/null`
+ if [ -z "$nslookup" ]
+ then
+ echo "Warning: cannot find nslookup"
+ nslookup=nslookup
+ fi
+ # sample configuration file needs a little customization
+ #
+ if [ -f /etc/resolv.conf ]
+ then
+ my_dns_server=`$PCP_AWK_PROG </etc/resolv.conf '$1 == "nameserver" { print $2; exit }'`
+ else
+ my_dns_server=`hostname`
+ fi
+ sed <$default_configfile >$tmp/tmp \
+ -e '/CONFIGURE-ME-PLEASE/d' \
+ -e "s@DEFAULT-DNS-SERVER@$my_dns_server@" \
+ -e "s@NSLOOKUP@$nslookup@"
+ cp $tmp/tmp $default_configfile
+ fi
+
+ # go figure out which configuration file to use ...
+ #
+ pmdaChooseConfigFile
+
+ if [ ! -f "$configfile" ]
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to enter commands to create a new configuration file? [y] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" = "Xy" -o "X$ans" = "XY" -o -z "$ans" ]
+ then
+ configfile="$configdir/$iam.conf"
+ if [ -f $configfile ]
+ then
+ echo "Removing old configuration file \"$configfile\""
+ rm -f $configfile
+ if [ -f $configfile ]
+ then
+ echo "Cannot remove \"$configfile\""
+ _quit 1
+ fi
+ fi
+
+ echo
+ echo \
+'Enter one ping specification per line, in the format
+
+tag command line details
+
+where the "tag" is a single unique word (no spaces) and the "command line
+details" are the corresponding sh(1) command. For example
+
+dns-self nslookup `hostname`
+
+An empty line terminates the specification process and there must be at
+least one specification.
+'
+
+ args=""
+ touch $configfile
+ if [ ! -f $configfile ]
+ then
+ echo "Installation aborted."
+ _quit 1
+ fi
+
+ while [ ! -s "$configfile" ]
+ do
+ while true
+ do
+ $PCP_ECHO_PROG $PCP_ECHO_N "Tag Command: ""$PCP_ECHO_C"
+ read tag cmd
+ [ -z "$tag" ] && break
+ if grep "^$tag " $configfile >/dev/null
+ then
+ echo "Sorry, tag \"$tag\" already in use. Please try again."
+ continue
+ fi
+ echo "$tag $cmd" >>$configfile
+ done
+ done
+ else
+ echo ""
+ echo "Error: Abandoning installation as no configuration file was specified."
+ _quit 1
+ fi
+ fi
+
+ echo
+ echo "All commands are run one after another as a group and the group is run"
+ $PCP_ECHO_PROG $PCP_ECHO_N "once per \"cycle\" time. Enter the cycle time in seconds [$cycle] ""$PCP_ECHO_C"
+ read ans
+ if [ ! -z "$ans" ]
+ then
+ cycle=$ans
+ fi
+
+ echo
+ echo "Each command must complete within a timeout period, or it will be aborted"
+ $PCP_ECHO_PROG $PCP_ECHO_N "by the \"$iam\" PMDA. Enter the timeout period (in seconds) [$timeout] ""$PCP_ECHO_C"
+ read ans
+ if [ ! -z "$ans" ]
+ then
+ timeout=$ans
+ fi
+
+ if [ "$do_debug" = true ]
+ then
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Enter the debugging flag (see pmdbg(1)) [$debug] ""$PCP_ECHO_C"
+ read ans
+ if [ ! -z "$ans" ]
+ then
+ debug=$ans
+ fi
+ fi
+
+ args="-I $cycle -t $timeout -D $debug $configfile"
+fi
+
+pmdaInstall
+
+_quit 0
diff --git a/src/pmdas/shping/README b/src/pmdas/shping/README
new file mode 100644
index 0000000..a071cbc
--- /dev/null
+++ b/src/pmdas/shping/README
@@ -0,0 +1,91 @@
+Performance Co-Pilot shping PMDA for General Performance Monitoring
+===================================================================
+
+This PMDA is designed to be configurable to monitor elapsed time and
+CPU time (user and system) for arbitrary applications that can be run
+from the Bourne shell. Each application is assumed to run to completion
+to probe or ping a particular service or dimension of system performance.
+
+The metrics exported from the shping PMDA may be used to quantify of
+service or service availability for both critical system services and
+tasks that well correlated to performance as perceived by end-users.
+
+The sample configuration file includes examples to "ping":
+
+ + sh(1) start up and exit
+ + a simple task, date(1)
+ + sum(1) for some simple user-mode computation
+ + compilation and execution of an antipodean variant of the
+ generic "hullo world" C program
+ + DNS (default server, trivial and error cases)
+ + yp service via ypcat(1)
+ + rpcinfo(1) for RPC registration from portmap/rpcbind
+ + mail delivery (telnet tcp port 25)
+ + Usenet news from nntp (telnet tcp port 119)
+
+Metrics
+=======
+
+The file ./help contains descriptions for all of the metrics exported
+by this PMDA.
+
+Once the PMDA has been installed, the following command will list all
+the available metrics and their explanatory "help" text:
+
+ $ pminfo -fT shping
+
+Installation of the shping PMDA
+===============================
+
+ + # cd $PCP_PMDAS_DIR/shping
+
+ + Check that there is no clash with the Performance Metrics Domain
+ number defined in ./domain.h and the other PMDAs currently in use
+ (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h and choose
+ another domain number.
+
+ + Then run the Install script (as root)
+
+ # ./Install
+
+ and choose both the "collector" and "monitor" installation
+ configuration options.
+
+ Answer the questions, which include the option to specify new or
+ alternate commands to be run. See $PCP_PMDAS_DIR/shping/sample.conf
+ for example specifications of commands.
+
+De-installation
+===============
+
+ + Simply use
+
+ # cd $PCP_PMDAS_DIR/shping
+ # ./Remove
+
+Changing the settings
+=====================
+
+The cycle time and timeout period can be dynamically modified using
+pmstore(1) for the metrics shping.control.cycletime and
+shping.control.timeout respectively.
+
+To make permanent changes, re-run the Install script.
+
+Troubleshooting
+===============
+
+ + After installing or restarting the agent, the PMCD log file
+ ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file
+ ($PCP_LOG_DIR/pmcd/shping.log) should be checked for any warnings
+ or errors.
+
+ + If the Install script reports some warnings when checking the
+ metrics, the problem should be listed in one of the log files.
+
+ + Additional information can be logged if there appears to be
+ problems. The PCP application debug flags will cause the PMDA to
+ report additional information in $PCP_LOG_DIR/pmcd/shping.log. For
+ details about the agent's debug flags, use the comand
+
+ $ pminfo -T shping.control.debug
diff --git a/src/pmdas/shping/Remove b/src/pmdas/shping/Remove
new file mode 100644
index 0000000..b991ac5
--- /dev/null
+++ b/src/pmdas/shping/Remove
@@ -0,0 +1,38 @@
+#! /bin/sh
+#
+# Copyright (c) 1997 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Remove the shping PMDA
+#
+
+# Get standard environment
+. $PCP_DIR/etc/pcp.env
+
+# Get the common procedures and variable assignments
+#
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+# The name of the PMDA
+#
+iam=shping
+
+# Do it
+#
+pmdaSetup
+pmdaRemove
+
+exit 0
diff --git a/src/pmdas/shping/help b/src/pmdas/shping/help
new file mode 100644
index 0000000..69d758c
--- /dev/null
+++ b/src/pmdas/shping/help
@@ -0,0 +1,137 @@
+#
+# Copyright (c) 2000 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.
+#
+# shping PMDA help file in the ASCII format
+#
+# lines beginning with a # are ignored
+# lines beginning @ introduce a new entry of the form
+# @ metric_name oneline-text
+# help test goes
+# here over multiple lines
+# ...
+#
+# the metric_name is decoded against the default PMNS -- as a special case,
+# a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an
+# instance domain identification, and the text describes the instance domain
+#
+# blank lines before the @ line are ignored
+#
+
+@ 19.0 shping command instance domain
+There is one instance for each command run by the shping PMDA.
+
+The external instance name comes from the "tag" in the shping PMDA
+configuration file. The internal instance number is the ordinal
+command number in the configuration file.
+
+@ shping.error command execution error code for shping PMDA
+As each command is executed, if there is a problem, the error
+code or cause is stored in shping.error.
+
+The interpretation of the value for shping.error depends on
+shping.status as follows:
+
+ If shping.status is 1 (the command was run but returned a non-zero
+ exit status) then shping.error is the exit status.
+
+ If shping.status is 2 (the command was run but was terminated by
+ a signal) then shping.error is the signal number.
+
+ If shping.status is 3 (the command did not complete) then
+ shping.error is a PCP error codes: see pmerr(1). Of particular
+ relevance is -1008 (PM_ERR_TIMEOUT) when the command failed to
+ complete in the time specified by shping.control.timeout.
+
+ If shping.status is 4 (the commands was not run) then shping.error
+ is the value of the system error code.
+
+ Otherwise shping.error will be zero.
+
+@ shping.status command execution status for shping PMDA
+As each command is executed, the success or failure is encoded in
+shping.status, using the following values:
+
+ -1 PMDA is initializing and command has not been run yet
+ 0 command completed and exit status was 0
+ 1 command completed and exit status was non-zero
+ 2 command was run but terminated by a signal
+ 3 command was run but did not complete (usually a timeout)
+ 4 command was not run due to some system error or resource
+ availability
+
+@ shping.time.real elapsed time for a command
+This metric records the elapsed time in milliseconds for the most recent
+execution of each command to be run by the shping PMDA.
+
+Care should be used when interpreting the value if the corresponding
+value for shping.status is non-zero, as the command may not have run to
+completion. If the command timed out, shping.time.real will be -1.
+
+@ shping.time.cpu_usr user mode CPU time for a command
+This metric records the user mode CPU time in milliseconds for the most
+recent execution of each command to be run by the shping PMDA.
+
+Care should be used when interpreting the value if the corresponding
+value for shping.status is non-zero, as the command may not have run to
+completion. If the command timed out, shping.time.cpu_usr will be -1.
+
+@ shping.time.cpu_sys system mode CPU time for a command
+This metric records the system mode CPU time in milliseconds for the most
+recent execution of each command to be run by the shping PMDA.
+
+Care should be used when interpreting the value if the corresponding
+value for shping.status is non-zero, as the command may not have run to
+completion. If the command timed out, shping.time.cpu_sys will be -1.
+
+@ shping.cmd commands run by shping PMDA
+The text of each sh(1) command run by the shping PMDA.
+
+@ shping.control.numcmd number of commands in the group to be run by the shping PMDA
+
+@ shping.control.cycles number of times the command group has been run by the shping PMDA
+
+@ shping.control.cycletime shping PMDA cycle time
+All commands are run by the shping PMDA are executed one after another
+in a group, and the group is run once per "cycle" time. This metric
+reports the cycle time in seconds.
+
+The cycle time may be changed dynamically by modifying this metric
+with pmstore(1).
+
+@ shping.control.timeout shping PMDA timeout period
+The number of seconds the shping PMDA is willing to wait before
+considering a single command to have timed out and killing it off.
+
+The time out interval may be changed dynamically by modifying this
+metric with pmstore(1).
+
+@ shping.control.debug shping PMDA debug flag
+The debug flag for the shping PMDA (see pmdbg(1)). All trace and
+diagnostic files are created in $PCP_LOG_DIR/pmcd.
+
+The debug flags DBG_TRACE_APPL0 (2048) and DBG_TRACE_APPL1 (4096)
+may be used as follows:
+
+DBG_TRACE_APPL0 - additional trace messages associated with the running
+ of each command appear in shping.log
+
+DBG_TRACE_APPL1 - the standard output and standard error of each command
+ is appended to shping.out (instead of the default
+ /dev/null)
+
+The debug flags may be changed dynamically by modifying this
+metric with pmstore(1), e.g.
+ $ pmstore shping.control.debug 6144
+would enable both of the diagnostic traces associated with
+DBG_TRACE_APPL0 and DBG_TRACE_APPL1.
+
diff --git a/src/pmdas/shping/pmda.c b/src/pmdas/shping/pmda.c
new file mode 100644
index 0000000..648cec3
--- /dev/null
+++ b/src/pmdas/shping/pmda.c
@@ -0,0 +1,257 @@
+/*
+ * sh(1) ping PMDA
+ *
+ * Copyright (c) 1995-2003 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.
+ */
+
+#include <ctype.h>
+#include "shping.h"
+#include "domain.h"
+
+__uint32_t cycletime = 120; /* default cycle time, 2 minutes */
+__uint32_t timeout = 20; /* response timeout in seconds */
+static char *username; /* user account to run under */
+cmd_t *cmdlist;
+
+#ifdef HAVE_SPROC
+
+/* Signals are only used with sproc, threads will never generate SIGGHLD */
+void
+onchld(int s)
+{
+ int done;
+ int waitStatus;
+ int die = 0;
+
+ while ((done = waitpid(-1, &waitStatus, WNOHANG)) > 0) {
+
+ if (done != sprocpid)
+ continue;
+ die = 1;
+
+ if (WIFEXITED(waitStatus)) {
+
+ if (WEXITSTATUS(waitStatus) == 0)
+ logmessage(LOG_INFO,
+ "Sproc (pid=%d) exited normally\n",
+ done);
+ else
+ logmessage(LOG_CRIT,
+ "Sproc (pid=%d) exited with status = %d\n",
+ done, WEXITSTATUS(waitStatus));
+ }
+ else if (WIFSIGNALED(waitStatus)) {
+
+ if (WCOREDUMP(waitStatus))
+ logmessage(LOG_CRIT,
+ "Sproc (pid=%d) received signal = %d and dumped core\n",
+ done, WTERMSIG(waitStatus));
+ else
+ logmessage(LOG_CRIT,
+ "Sproc (pid=%d) received signal = %d\n",
+ done, WTERMSIG(waitStatus));
+ }
+ else {
+ logmessage(LOG_CRIT,
+ "Sproc (pid=%d) died, reason unknown\n", done);
+ }
+ }
+
+ if (die) {
+ logmessage(LOG_INFO, "Main process exiting\n");
+ exit(0);
+ }
+}
+#endif
+
+void
+usage(void)
+{
+ fprintf(stderr,
+"Usage: %s [options] configfile\n\n\
+Options:\n\
+ -C parse configuration file and exit\n\
+ -d domain use domain (numeric) for metrics domain of PMDA\n\
+ -I interval cycle time in seconds between subsequent executions of each\n\
+ command [default 120 seconds]\n\
+ -l logfile write log into logfile rather than using the default log\n\
+ -t timeout time in seconds before aborting the wait for individual\n\
+ commands to complete [default 20 seconds]\n\
+ -U username run the agent and commands as alternate user [default \"pcp\"]\n",
+ pmProgname);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ pmdaInterface dispatch;
+ int n = 0;
+ int i;
+ int err = 0;
+ int sep = __pmPathSeparator();
+ int line;
+ int numcmd = 0;
+ int parseonly = 0;
+ char *configfile;
+ FILE *conf;
+ char *endnum;
+ char *p;
+ char *tag;
+ char lbuf[256];
+ char mypath[MAXPATHLEN];
+
+ __pmSetProgname(argv[0]);
+ __pmGetUsername(&username);
+
+ snprintf(mypath, sizeof(mypath), "%s%c" "shping" "%c" "help",
+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+ pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, SHPING,
+ "shping.log", mypath);
+
+ while ((n = pmdaGetOpt(argc, argv,"CD:d:I:l:t:U:?",
+ &dispatch, &err)) != EOF) {
+ switch (n) {
+
+ case 'C':
+ parseonly = 1;
+ break;
+
+ case 'I':
+ cycletime = (int)strtol(optarg, &endnum, 10);
+ if (*endnum != '\0') {
+ fprintf(stderr,
+ "%s: -I requires number of seconds as argument\n",
+ pmProgname);
+ err++;
+ }
+ break;
+
+ case 't':
+ timeout = (int)strtol(optarg, &endnum, 10);
+ if (*endnum != '\0') {
+ fprintf(stderr,
+ "%s: -t requires number of seconds as argument\n",
+ pmProgname);
+ err++;
+ }
+ break;
+
+ case 'U':
+ username = optarg;
+ break;
+
+ case '?':
+ err++;
+ }
+ }
+
+ if (err || optind != argc -1) {
+ usage();
+ }
+
+ configfile = argv[optind];
+ if ((conf = fopen(configfile, "r")) == NULL) {
+ fprintf(stderr, "%s: Unable to open config file \"%s\": %s\n",
+ pmProgname, configfile, osstrerror());
+ exit(1);
+ }
+ line = 0;
+
+ for ( ; ; ) {
+ if (fgets(lbuf, sizeof(lbuf), conf) == NULL)
+ break;
+
+ line++;
+ p = lbuf;
+ while (*p && isspace((int)*p))
+ p++;
+ if (*p == '\0' || *p == '\n' || *p == '#')
+ continue;
+ tag = p++;
+ while (*p && !isspace((int)*p))
+ p++;
+ if (*p)
+ *p++ = '\0';
+ while (*p && isspace((int)*p))
+ p++;
+ if (*p == '\0' || *p == '\n') {
+ fprintf(stderr, "[%s:%d] missing command after tag \"%s\"\n",
+ configfile, line, tag);
+ exit(1);
+ }
+
+ numcmd++;
+ if (parseonly)
+ continue;
+ if ((cmdlist = (cmd_t *)realloc(cmdlist, numcmd * sizeof(cmd_t))) == NULL) {
+ __pmNoMem("main:cmdlist", numcmd * sizeof(cmd_t),
+ PM_FATAL_ERR);
+ }
+
+ cmdlist[numcmd-1].tag = strdup(tag);
+ cmdlist[numcmd-1].cmd = strdup(p);
+ cmdlist[numcmd-1].status = STATUS_NOTYET;
+ cmdlist[numcmd-1].error = 0;
+ cmdlist[numcmd-1].real = cmdlist[numcmd-1].usr = cmdlist[numcmd-1].sys = -1;
+
+ /* trim trailing newline */
+ p = cmdlist[numcmd-1].cmd;
+ while (*p && *p != '\n')
+ p++;
+ *p = '\0';
+ }
+
+ fclose(conf);
+
+ if (numcmd == 0) {
+ fprintf(stderr, "%s: No commands in config file \"%s\"?\n",
+ pmProgname, configfile);
+ exit(1);
+ }
+ else if (parseonly)
+ exit(0);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ fprintf(stderr, "Parsed %d commands\n", numcmd);
+ fprintf(stderr, "Tag\tCommand\n");
+ for (i = 0; i < numcmd; i++) {
+ fprintf(stderr, "[%s]\t%s\n", cmdlist[i].tag, cmdlist[i].cmd);
+ }
+ }
+#endif
+
+ /* set up indom description */
+ indomtab.it_numinst = numcmd;
+ if ((indomtab.it_set = (pmdaInstid *)malloc(numcmd*sizeof(pmdaInstid))) == NULL) {
+ __pmNoMem("main.indomtab", numcmd * sizeof(pmdaInstid), PM_FATAL_ERR);
+ }
+ for (i = 0; i < numcmd; i++) {
+ indomtab.it_set[i].i_inst = i;
+ indomtab.it_set[i].i_name = cmdlist[i].tag;
+ }
+
+#ifdef HAVE_SPROC
+ signal(SIGCHLD, onchld);
+#endif
+
+ pmdaOpenLog(&dispatch);
+ __pmSetProcessIdentity(username);
+
+ shping_init(&dispatch);
+ pmdaConnect(&dispatch);
+ pmdaMain(&dispatch);
+
+ exit(0);
+}
diff --git a/src/pmdas/shping/pmlogconf.summary b/src/pmdas/shping/pmlogconf.summary
new file mode 100644
index 0000000..709865e
--- /dev/null
+++ b/src/pmdas/shping/pmlogconf.summary
@@ -0,0 +1,6 @@
+#pmlogconf-setup 2.0
+ident shping PMDA summary information
+probe shping.status exists ? include : exclude
+ shping.status
+ shping.time
+ shping.error
diff --git a/src/pmdas/shping/pmns b/src/pmdas/shping/pmns
new file mode 100644
index 0000000..70003e6
--- /dev/null
+++ b/src/pmdas/shping/pmns
@@ -0,0 +1,41 @@
+/*
+ * Metrics for shping PMDA
+ *
+ * Copyright (c) 2000-2004 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+shping {
+ status SHPING:0:6
+ error SHPING:0:10
+ time
+ cmd SHPING:0:7
+ control
+}
+
+shping.time {
+ real SHPING:0:0
+ cpu_usr SHPING:0:1
+ cpu_sys SHPING:0:2
+}
+
+shping.control {
+ numcmd SHPING:0:3
+ cycles SHPING:0:9
+ cycletime SHPING:0:4
+ timeout SHPING:0:5
+ debug SHPING:0:8
+}
diff --git a/src/pmdas/shping/root b/src/pmdas/shping/root
new file mode 100644
index 0000000..a0e1b52
--- /dev/null
+++ b/src/pmdas/shping/root
@@ -0,0 +1,9 @@
+/*
+ * fake "root" for validating the local PMNS subtree
+ */
+
+#include <stdpmid>
+
+root { shping }
+
+#include "pmns"
diff --git a/src/pmdas/shping/sample.conf b/src/pmdas/shping/sample.conf
new file mode 100644
index 0000000..028a196
--- /dev/null
+++ b/src/pmdas/shping/sample.conf
@@ -0,0 +1,46 @@
+# sample configuration file for shping PMDA
+#
+# Warning: these commands will be run as "root" using sh(1) with the
+# current directory set to $PCP_LOG_DIR/pmcd and the
+# following set in the environment:
+# IFS=" \t\n"
+# PATH=... as per $PCP_DIR/etc/pcp.env ...
+#
+
+# Specification format, one per line ("Tags" must be unique)
+# Tag Shell command
+
+# minimal effort here, no stress for the shell ... just start and quit
+null exit 0
+
+# not too much work, date(1) is pretty light-weight
+date date
+
+# compile and run the generic simple program ... requires a C compiler
+# to be installed
+cc cd /tmp; rm -f $$.[oc] $$; echo "main(){printf(\"g'day world\\\\n\");}" >/tmp/$$.c; cc -o $$ $$.c; ./$$; rm -f $$.[oc] $$
+
+# Is the default DNS server responding?
+# CONFIGURE-ME-PLEASE - local customization required
+# CONFIGURE-ME-PLEASE - DEFAULT-DNS-SERVER will be changed by Install to
+# CONFIGURE-ME-PLEASE - be the hostname for the default DNS server
+# CONFIGURE-ME-PLEASE - and NSLOOKUP is the path of the nslookup(1) command
+dns NSLOOKUP - DEFAULT-DNS-SERVER </dev/null
+
+# DNS lookup for localhost
+dns-self NSLOOKUP `hostname`
+
+# DNS lookup that will fail ...
+dns-err NSLOOKUP foo.bar.no.host.com
+
+# ypserv ... if you have yp running
+ypserv ypcat hosts | grep `hostname`
+
+# contact portmap/rpcbind for registered RPC programs
+rpcbind rpcinfo -p
+
+# if smtpd is running here, a simple test
+smtp ( echo "expn root"; echo quit ) | telnet-probe localhost 25
+
+# NNTP ... need to customize nntp server host
+nntp ( echo "listgroup comp.sys.sgi"; echo quit ) | telnet-probe tokyo.engr.sgi.com 119
diff --git a/src/pmdas/shping/shping.CPUTime.pmchart b/src/pmdas/shping/shping.CPUTime.pmchart
new file mode 100644
index 0000000..cce7e88
--- /dev/null
+++ b/src/pmdas/shping/shping.CPUTime.pmchart
@@ -0,0 +1,11 @@
+#pmchart
+Version 2.0 host dynamic
+
+Chart Title "User CPU Time for shping Commands" Style plot
+ Plot Color #-cycle Host * Metric shping.time.cpu_usr Matching .*
+
+Chart Title "System CPU Time for shping Commands" Style plot
+ Plot Color #-cycle Host * Metric shping.time.cpu_sys Matching .*
+
+#
+# CPU time (user and system) for commands run by the shping PMDA
diff --git a/src/pmdas/shping/shping.RealTime.pmchart b/src/pmdas/shping/shping.RealTime.pmchart
new file mode 100644
index 0000000..05d5436
--- /dev/null
+++ b/src/pmdas/shping/shping.RealTime.pmchart
@@ -0,0 +1,9 @@
+#pmchart
+Version 2.0 host dynamic
+
+Chart Title "Elapsed Time for shping Commands" Style plot
+ Plot Color #-cycle Host * Metric shping.time.real Matching .*
+
+#
+# Elapsed time (or real time, or response time) for commands run by the
+# shping PMDA
diff --git a/src/pmdas/shping/shping.c b/src/pmdas/shping/shping.c
new file mode 100644
index 0000000..f14be03
--- /dev/null
+++ b/src/pmdas/shping/shping.c
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2012 Red Hat.
+ * Copyright (c) 1995-2003 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.
+ */
+
+#include <ctype.h>
+#include "pmapi.h"
+#include "impl.h"
+#include "pmda.h"
+#include "shping.h"
+#include "domain.h"
+#include <sys/stat.h>
+#if defined(HAVE_SYS_WAIT_H)
+#include <sys/wait.h>
+#endif
+#if defined(HAVE_SYS_RESOURCE_H)
+#include <sys/resource.h>
+#endif
+#if defined(HAVE_SYS_PRCTL_H)
+#include <sys/prctl.h>
+#endif
+#if defined(HAVE_SCHED_H)
+#include <sched.h>
+#endif
+#if defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#define LOG_PRI(p) ((p) & LOG_PRIMASK)
+
+static int cycles; /* completed cycles */
+static int numskip; /* skipped cycles */
+static int numcmd; /* number of commands */
+static int timedout; /* command timed out */
+static pid_t shpid; /* for /sbin/sh running command */
+
+#if defined(HAVE_PTHREAD_H)
+static pthread_t sprocpid;
+#elif defined(HAVE_SCHED_H)
+pid_t sprocpid; /* for refresh() */
+#else
+#error "Need pthreads or sproc"
+#endif
+
+/*
+ * only one instance domain here ...
+ */
+#define SHPING_INDOM 0
+pmdaIndom indomtab = { 0, 0, NULL };
+
+/*
+ * all metrics supported in this PMDA - one table entry for each
+ */
+static pmdaMetric metrics[] =
+{
+/* time.real */
+ { NULL,
+ { PMDA_PMID(0,0), PM_TYPE_FLOAT, SHPING_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0), }, },
+/* time.cpu_usr */
+ { NULL,
+ { PMDA_PMID(0,1), PM_TYPE_FLOAT, SHPING_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0), }, },
+/* time.cpu_sys */
+ { NULL,
+ { PMDA_PMID(0,2), PM_TYPE_FLOAT, SHPING_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0), }, },
+/* control.numcmd */
+ { NULL,
+ { PMDA_PMID(0,3),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,0,0,0,0,0), }, },
+/* control.cycletime */
+ { NULL,
+ { PMDA_PMID(0,4),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0), }, },
+/* control.timeout */
+ { NULL,
+ { PMDA_PMID(0,5),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0), }, },
+/* status */
+ { NULL,
+ { PMDA_PMID(0,6),PM_TYPE_32,SHPING_INDOM,PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0), }, },
+/* cmd */
+ { NULL,
+ { PMDA_PMID(0,7),PM_TYPE_STRING,SHPING_INDOM,PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,0,0,0,0,0), }, },
+/* control.debug */
+ { NULL,
+ { PMDA_PMID(0,8),PM_TYPE_32,PM_INDOM_NULL,PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,0,0,0,0,0), }, },
+/* control.cycles */
+ { NULL,
+ { PMDA_PMID(0,9),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE), }, },
+/* error */
+ { NULL,
+ { PMDA_PMID(0,10),PM_TYPE_32,SHPING_INDOM,PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0), }, },
+
+};
+
+static int nummetric = (sizeof(metrics)/sizeof(metrics[0]));
+
+void
+logmessage(int priority, const char *format, ...)
+{
+ va_list arglist;
+ char buffer[2048];
+ char *level;
+ char *p;
+ time_t now;
+
+ buffer[0] = '\0';
+ time(&now);
+
+ priority = LOG_PRI(priority);
+ switch (priority) {
+ case LOG_EMERG :
+ level = "Emergency";
+ break;
+ case LOG_ALERT :
+ level = "Alert";
+ break;
+ case LOG_CRIT :
+ level = "Critical";
+ break;
+ case LOG_ERR :
+ level = "Error";
+ break;
+ case LOG_WARNING :
+ level = "Warning";
+ break;
+ case LOG_NOTICE :
+ level = "Notice";
+ break;
+ case LOG_INFO :
+ level = "Info";
+ break;
+ case LOG_DEBUG :
+ level = "Debug";
+ break;
+ default:
+ level = "???";
+ break;
+ }
+
+ va_start (arglist, format);
+ vsnprintf (buffer, sizeof(buffer), format, arglist);
+
+ /* strip unwanted '\n' at end of text so's not to double up */
+ for (p = buffer; *p; p++);
+ if (*(--p) == '\n') *p = '\0';
+
+ fprintf (stderr, "[%.19s] %s(%" FMT_PID ") %s: %s\n", ctime(&now), pmProgname, getpid(), level, buffer) ;
+ va_end (arglist) ;
+}
+
+
+static void
+onhup(int dummy)
+{
+ _exit(0);
+}
+
+static void
+onalarm(int dummy)
+{
+ timedout = 1;
+ if (shpid > 1) { /* something other than error, self or init */
+ kill(-shpid, SIGTERM); /* nuke process group */
+ sleep(1);
+ kill(-shpid, SIGKILL);
+ }
+ signal(SIGALRM, onalarm);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ fprintf(stderr, "Timeout!\n");
+#endif
+}
+
+/*
+ * the sproc starts here to refresh the metric values periodically
+ */
+static void
+refresh(void *dummy)
+{
+ int i;
+ int sts;
+ int waittime;
+ struct timeval startcycle;
+ struct timeval now;
+ struct timeval then;
+ struct rusage cpu_now;
+ struct rusage cpu_then;
+ char *argv[4];
+
+ signal(SIGHUP, onhup);
+#if defined (PR_TERMCHILD)
+ prctl(PR_TERMCHILD); /* SIGHUP when the parent dies */
+#elif defined (PR_SET_PDEATHSIG)
+ prctl(PR_SET_PDEATHSIG, SIGTERM);
+#elif defined(IS_SOLARIS) || defined(IS_DARWIN) || defined(IS_MINGW) || defined(IS_AIX) || defined(IS_FREEBSD) || defined(IS_GNU) || defined(IS_NETBSD)
+ /* no signals here for child exit */
+#else
+!bozo: cant decide between PR_TERMCHILD and PR_SET_PDEATHSIG
+#endif
+#ifndef NOFILE
+#define NOFILE 7
+#endif
+
+ signal(SIGALRM, onalarm);
+
+ putenv("IFS= \t\n");
+ putenv("PATH=/usr/sbin:/usr/bsd:/sbin:/usr/bin:/bin");
+
+ argv[0] = "sh";
+ argv[1] = "-c";
+ argv[2] = "";
+ argv[3] = NULL;
+
+ for ( ; ; ) {
+ cycles++;
+ __pmtimevalNow(&startcycle);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ fprintf(stderr, "\nStart cycle @ %s", ctime(&startcycle.tv_sec));
+#endif
+ for (i = 0; i < numcmd; i++) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ fprintf(stderr, "[%s] %s ->\n", cmdlist[i].tag, cmdlist[i].cmd);
+#endif
+ getrusage(RUSAGE_CHILDREN, &cpu_then);
+ __pmtimevalNow(&then);
+ fflush(stderr);
+ fflush(stdout);
+ shpid = fork();
+ if (shpid == 0) {
+ int j;
+ setsid(); /* make new process group */
+ for (j = 0; j < NOFILE; j++)
+ close(j);
+ open("/dev/null", O_RDONLY, 0);
+ sts = -1;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ FILE *f;
+ if ((f = fopen("shping.out", "a")) != NULL) {
+ fprintf(f, "\n[%s] %s\n", cmdlist[i].tag, cmdlist[i].cmd);
+ fclose(f);
+ }
+ sts = open("shping.out", O_WRONLY|O_APPEND|O_CREAT, 0644);
+ }
+#endif
+ if (sts == -1)
+ open("/dev/null", O_WRONLY, 0);
+ if (dup(1) == -1) {
+ fprintf(stderr, "Warning: dup() failed: %s\n", pmErrStr(-oserror()));
+ }
+ argv[2] = cmdlist[i].cmd;
+ sts = execv("/bin/sh", argv);
+ exit(-1);
+ }
+ else if (shpid < 0) {
+ logmessage(LOG_CRIT, "refresh: fork() failed: %s", osstrerror());
+ cmdlist[i].status = STATUS_SYS;
+ cmdlist[i].error = oserror();
+ cmdlist[i].real = cmdlist[i].usr = cmdlist[i].sys = -1;
+ continue;
+
+ }
+ timedout = 0;
+ alarm(timeout);
+ waitpid(shpid, &sts, 0);
+ __pmtimevalNow(&now);
+ getrusage(RUSAGE_CHILDREN, &cpu_now);
+ alarm(0);
+
+ if (timedout) {
+ cmdlist[i].error = PM_ERR_TIMEOUT;
+ cmdlist[i].status = STATUS_TIMEOUT;
+ cmdlist[i].real = cmdlist[i].usr = cmdlist[i].sys = -1;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_INFO, "[%s] timeout\n", cmdlist[i].tag);
+#endif
+ }
+ else {
+ if (WIFEXITED(sts)) {
+ cmdlist[i].error = WEXITSTATUS(sts);
+ if (cmdlist[i].error == 0)
+ cmdlist[i].status = STATUS_OK;
+ else {
+ cmdlist[i].status = STATUS_EXIT;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_INFO, "[%s] exit status: %d\n",
+ cmdlist[i].tag, cmdlist[i].error);
+#endif
+ }
+ }
+ else if (WIFSIGNALED(sts)) {
+ cmdlist[i].error = WTERMSIG(sts);
+ cmdlist[i].status = STATUS_SIG;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_INFO, "[%s] killed signal: %d\n",
+ cmdlist[i].tag, cmdlist[i].error);
+#endif
+ }
+ else {
+ /* assume WIFSTOPPED(sts) */
+ cmdlist[i].error = WSTOPSIG(sts);
+ cmdlist[i].status = STATUS_SIG;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_INFO, "[%s] stopped signal: %d\n",
+ cmdlist[i].tag, cmdlist[i].error);
+#endif
+ }
+ cmdlist[i].real = 1000 * (float)(now.tv_sec - then.tv_sec) +
+ (float)(now.tv_usec - then.tv_usec) / 1000;
+ cmdlist[i].usr = 1000 * (float)(cpu_now.ru_utime.tv_sec - cpu_then.ru_utime.tv_sec) +
+ (float)(cpu_now.ru_utime.tv_usec - cpu_then.ru_utime.tv_usec) / 1000;
+ cmdlist[i].sys = 1000 * (float)(cpu_now.ru_stime.tv_sec - cpu_then.ru_stime.tv_sec) +
+ (float)(cpu_now.ru_stime.tv_usec - cpu_then.ru_stime.tv_usec) / 1000;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ fprintf(stderr, "status: %d error: %d real: %.3f usr: %.3f sys: %.3f\n\n",
+ cmdlist[i].status, cmdlist[i].error,
+ cmdlist[i].real, cmdlist[i].usr, cmdlist[i].sys);
+#endif
+ }
+
+ /*
+ * harvest delinquent children ... includes those who were fork()'d
+ * above, and timed out.
+ */
+ for ( ; ; ) {
+ sts = waitpid(-1, NULL, WNOHANG);
+ if (sts <= 0)
+ break;
+ }
+
+ __pmtimevalNow(&now);
+ if (cycletime) {
+ waittime = (int)cycletime - now.tv_sec + startcycle.tv_sec;
+ if (waittime < 0) {
+ /* can't keep up */
+ while (waittime < 0) {
+ numskip++;
+ waittime += cycletime;
+ }
+ }
+ sleep(waittime);
+ }
+ }
+}
+
+static int
+shping_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *ext)
+{
+ int i; /* over pmidlist[] */
+ int j; /* over vset->vlist[] */
+ int sts;
+ int need;
+ int inst;
+ int numval;
+ static pmResult *res = NULL;
+ static int maxnpmids = 0;
+ pmValueSet *vset;
+ __pmID_int *pmidp;
+ pmAtomValue atom;
+ pmDesc *dp = NULL;
+ int type;
+
+#ifndef HAVE_SPROC
+ /* In the pthread world we don't have asyncronous notification that
+ * a thread has died, so we use pthread_kill to check is refresh
+ * is still running. */
+ int err;
+
+ if ( (err = pthread_kill (sprocpid, 0)) != 0 ) {
+ logmessage (LOG_CRIT, "'refresh' thread is not responding: %s\n",
+ strerror (err));
+ exit (1);
+ }
+#endif
+
+
+ if (numpmid > maxnpmids)
+ {
+ if (res != NULL)
+ free(res);
+
+/* (numpmid - 1) because there's room for one valueSet in a pmResult */
+
+ need = sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *);
+ if ((res = (pmResult *) malloc(need)) == NULL)
+ return -oserror();
+ maxnpmids = numpmid;
+ }
+
+ res->timestamp.tv_sec = 0;
+ res->timestamp.tv_usec = 0;
+ res->numpmid = numpmid;
+
+
+ for (i = 0; i < numpmid; i++) {
+
+ pmidp = (__pmID_int*)&pmidlist[i];
+ dp = NULL;
+
+ if (ext->e_direct) {
+ if (pmidp->cluster == 0 && pmidp->item < nummetric)
+ dp = &metrics[pmidp->item].m_desc;
+ }
+ else {
+ for (j = 1; j<nummetric; j++) {
+ if (pmidp->cluster == 0 &&
+ metrics[j].m_desc.pmid == pmidlist[i]) {
+ dp = &metrics[j].m_desc;
+ break;
+ }
+ }
+ }
+
+ if (dp == NULL)
+ numval = PM_ERR_PMID;
+ else {
+ if (dp->indom != PM_INDOM_NULL) {
+ numval = 0;
+ __pmdaStartInst(dp->indom, ext);
+ while(__pmdaNextInst(&inst, ext)) {
+ numval++;
+ }
+ }
+ else {
+ numval = 1;
+ }
+ }
+
+ if (numval >= 1)
+ res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) +
+ (numval - 1)*sizeof(pmValue));
+ else
+ res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) -
+ sizeof(pmValue));
+
+ if (vset == NULL) {
+ if (i) {
+ res->numpmid = i;
+ __pmFreeResultValues(res);
+ }
+ return -oserror();
+ }
+ vset->pmid = pmidlist[i];
+ vset->numval = numval;
+ vset->valfmt = PM_VAL_INSITU;
+ if (vset->numval <= 0)
+ continue;
+
+ if (dp->indom == PM_INDOM_NULL)
+ inst = PM_IN_NULL;
+ else {
+ __pmdaStartInst(dp->indom, ext);
+ __pmdaNextInst(&inst, ext);
+ }
+
+ type = dp->type;
+ pmidp = (__pmID_int *)&pmidlist[i];
+ j = 0;
+
+ do {
+ if (j == numval) {
+ /* more instances than expected! */
+ numval++;
+ res->vset[i] = vset = (pmValueSet *)realloc(vset,
+ sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue));
+ if (vset == NULL) {
+ if (i) {
+ res->numpmid = i;
+ __pmFreeResultValues(res);
+ }
+ return -oserror();
+ }
+ }
+ vset->vlist[j].inst = inst;
+
+ if (pmidp->cluster == 0) {
+ switch (pmidp->item) {
+
+ case 0: /* shping.time.real PMID: ...0.0 */
+ atom.f = cmdlist[inst].real;
+ break;
+
+ case 1: /* shping.time.cpu_usr PMID: ...0.1 */
+ atom.f = cmdlist[inst].usr;
+ break;
+
+ case 2: /* shping.time.cpu_sys PMID: ...0.2 */
+ atom.f = cmdlist[inst].sys;
+ break;
+
+ case 3: /* shping.control.numcmd PMID: ...0.3 */
+ atom.ul = numcmd;
+ break;
+
+ case 4: /* shping.control.cycletime PMID: ...0.4 */
+ atom.ul = cycletime;
+ break;
+
+ case 5: /* shping.control.timeout PMID: ...0.5 */
+ atom.ul = timeout;
+ break;
+
+ case 6: /* shping.status PMID: ...0.6 */
+ atom.l = cmdlist[inst].status;
+ break;
+
+ case 7: /* shping.cmd PMID: ...0.7 */
+ atom.cp = cmdlist[inst].cmd;
+ break;
+
+ case 8: /* shping.control.debug PMID: ...0.8 */
+ atom.l = pmDebug;
+ break;
+
+ case 9: /* shping.control.cycles PMID: ...0.9 */
+ atom.ul = cycles;
+ break;
+
+ case 10: /* shping.error PMID: ...0.10 */
+ atom.ul = cmdlist[inst].error;
+ break;
+
+ default:
+ j = PM_ERR_PMID;
+ break;
+ }
+ }
+ if (j < 0)
+ break;
+
+ sts = __pmStuffValue(&atom, &vset->vlist[j], type);
+ if (sts < 0) {
+ __pmFreeResultValues(res);
+ return sts;
+ }
+
+ vset->valfmt = sts;
+ j++; /* next element in vlist[] for next instance */
+ } while (dp->indom != PM_INDOM_NULL && __pmdaNextInst(&inst, ext));
+
+ vset->numval = j;
+ }
+ *resp = res;
+ return 0;
+}
+
+static int
+shping_store(pmResult *result, pmdaExt *ext)
+{
+ int i;
+ pmValueSet *vsp;
+ int sts = 0;
+ int ival;
+ __pmID_int *pmidp;
+
+ for (i = 0; i < result->numpmid; i++) {
+ vsp = result->vset[i];
+ pmidp = (__pmID_int *)&vsp->pmid;
+ if (pmidp->cluster == 0) {
+ switch (pmidp->item) {
+ case 4: /* shping.control.cycletime PMID: ...0.4 */
+ ival = vsp->vlist[0].value.lval;
+ if (ival < 0) {
+ sts = PM_ERR_SIGN;
+ break;
+ }
+ cycletime = ival;
+ break;
+
+ case 5: /* shping.control.timeout PMID: ...0.5 */
+ ival = vsp->vlist[0].value.lval;
+ if (ival < 0) {
+ sts = PM_ERR_SIGN;
+ break;
+ }
+ timeout = ival;
+ break;
+
+ case 8: /* shping.control.debug PMID: ...0.8 */
+ ival = vsp->vlist[0].value.lval;
+ if (ival < 0) {
+ sts = PM_ERR_SIGN;
+ break;
+ }
+ pmDebug = ival;
+ break;
+
+ default:
+ sts = PM_ERR_PMID;
+ break;
+ }
+ }
+ else {
+ /* not one of the metrics we are willing to change */
+ sts = PM_ERR_PMID;
+ break;
+ }
+ }
+ return sts;
+}
+
+void
+shping_init(pmdaInterface *dp)
+{
+ if (dp->status != 0)
+ return;
+
+ unlink("shping.out"); /* just in case */
+
+ dp->version.two.fetch = shping_fetch;
+ dp->version.two.store = shping_store;
+
+ pmdaInit(dp, &indomtab, 1, metrics, nummetric);
+
+ if (dp->version.two.ext->e_direct == 0) {
+ logmessage(LOG_CRIT, "Metric tables require direct mapping.\n");
+ dp->status = -1;
+ return;
+ }
+
+ numcmd = indomtab.it_numinst;
+
+ /* start the sproc for async fetches */
+#ifdef HAVE_SPROC
+ if ( (sprocpid = sproc(refresh, PR_SADDR, NULL)) < 0 ) {
+ logmessage(LOG_CRIT, "sproc failed: %s\n", osstrerror());
+ dp->status = sprocpid;
+ }
+ else {
+ dp->status = 0;
+ logmessage(LOG_INFO, "Started sproc (spid=%" FMT_PID ")\n", sprocpid);
+ }
+
+ /* we're talking to pmcd ... no timeout's for us thanks */
+ signal(SIGALRM, SIG_IGN);
+
+#elif defined (HAVE_PTHREAD_H)
+ {
+ int err = pthread_create(&sprocpid, NULL, (void (*))refresh, NULL);
+ if ( err != 0 ) {
+ logmessage (LOG_CRIT, "Cannot spawn a new thread: %s\n",
+ strerror (err));
+ dp->status = err;
+ } else {
+ dp->status = 0;
+ logmessage (LOG_INFO, "Started refresh thread\n");
+ }
+ }
+#else
+#error "Need pthreads or sproc"
+#endif
+}
diff --git a/src/pmdas/shping/shping.h b/src/pmdas/shping/shping.h
new file mode 100644
index 0000000..1c266a1
--- /dev/null
+++ b/src/pmdas/shping/shping.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "pmapi.h"
+#include "impl.h"
+#include "pmda.h"
+
+typedef struct {
+ char *tag;
+ char *cmd;
+ int status;
+ int error;
+ float real;
+ float usr;
+ float sys;
+} cmd_t;
+
+#define STATUS_NOTYET -1
+#define STATUS_OK 0
+#define STATUS_EXIT 1
+#define STATUS_SIG 2
+#define STATUS_TIMEOUT 3
+#define STATUS_SYS 4
+
+extern cmd_t *cmdlist;
+
+extern __uint32_t cycletime; /* seconds per command cycle */
+extern __uint32_t timeout; /* response timeout in seconds */
+#ifdef HAVE_SPROC
+extern pid_t sprocpid; /* for refresh() */
+#endif
+extern pmdaIndom indomtab; /* cmd tag indom */
+
+extern int pmDebug;
+extern char *pmProgname;
+
+extern void shping_init(pmdaInterface *);
+
+extern void logmessage(int, const char *, ...);
diff --git a/src/pmdas/shping/shping.response.pmie b/src/pmdas/shping/shping.response.pmie
new file mode 100644
index 0000000..f77457a
--- /dev/null
+++ b/src/pmdas/shping/shping.response.pmie
@@ -0,0 +1,67 @@
+#pmieconf-rules 1
+# --- DO NOT MODIFY THIS FILE --- see pmieconf(4)
+
+rule shping.response
+ summary = "$rule$"
+ enumerate = hosts
+ predicate =
+"some_inst (
+ shping.time.real $hosts$ > $threshold$ &&
+ shping.status $hosts$ == 0
+)"
+ enabled = no
+ version = 1
+ help =
+"A monitored application or service probe from the shping PMDA
+has taken more than threshold milliseconds to complete.
+
+If this rule is enabled, the shping PMDA should be installed; see
+$PCP_PMDAS_DIR/shping/README and pmdashping(1).
+
+If some application or service is not available then the
+corresponding line should be commented out of the shping
+configuration file ($PCP_PMDAS_DIR/shping/shping.conf by default)
+and the shping PMDA restarted.";
+
+string rule
+ default = "Shell-ping PMDA slow application or service response"
+ modify = no
+ display = no;
+
+unsigned threshold
+ default = 3000
+ help =
+"Threshold time, in milliseconds, for command to run to completion.";
+
+string action_expand
+ default = %vmsec[%i]
+ display = no
+ modify = no;
+
+string email_expand
+ default = "service: %i response time: %vmsec"
+ display = no
+ modify = no;
+
+
+# Configuration info specific to non-PCP tools follows...
+#
+
+# for SGI Embedded Support Partner integration:
+string esp_type
+ default = "0x200095"
+ display = no
+ modify = no;
+
+# for EnlightenDSM integration:
+string enln_test
+ default = shping.response
+ display = no
+ modify = no;
+string enln_units
+ default = msec[%i]
+ display = no
+ modify = no;
+
+#
+# --- DO NOT MODIFY THIS FILE --- see pmieconf(4)
diff --git a/src/pmdas/shping/shping.status.pmie b/src/pmdas/shping/shping.status.pmie
new file mode 100644
index 0000000..199c600
--- /dev/null
+++ b/src/pmdas/shping/shping.status.pmie
@@ -0,0 +1,63 @@
+#pmieconf-rules 1
+# --- DO NOT MODIFY THIS FILE --- see pmieconf(4)
+
+rule shping.status
+ summary = "$rule$"
+ enumerate = hosts
+ predicate =
+"some_inst (
+ shping.status $hosts$ @0 > 0 && shping.status $hosts$ @1 == 0
+)"
+ enabled = no
+ version = 1
+ help =
+"An application or service being monitored by the shping PMDA was
+previously probed successfully and the probe has either failed, or
+not responded within a timeout period (as defined by the PCP metric
+shping.control.timeout) during the last sample interval.
+
+If this rule is enabled, the shping PMDA should be installed; see
+$PCP_PMDAS_DIR/shping/README and pmdashping(1).
+
+If some application or service is not available then the
+corresponding line should be commented out of the shping
+configuration file ($PCP_PMDAS_DIR/shping/shping.conf by default)
+and the shping PMDA restarted.";
+
+string rule
+ default = "Shell-ping PMDA application or service probe failure"
+ modify = no
+ display = no;
+
+string action_expand
+ default = %i
+ display = no
+ modify = no;
+
+string email_expand
+ default = "application or service: %i"
+ display = no
+ modify = no;
+
+
+# Configuration info specific to non-PCP tools follows...
+#
+
+# for SGI Embedded Support Partner integration:
+string esp_type
+ default = "0x200090"
+ display = no
+ modify = no;
+
+# for EnlightenDSM integration:
+string enln_test
+ default = shping.status
+ display = no
+ modify = no;
+string enln_units
+ default = exit_status
+ display = no
+ modify = no;
+
+#
+# --- DO NOT MODIFY THIS FILE --- see pmieconf(4)