summaryrefslogtreecommitdiff
path: root/src/pmdas/pmcd
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/pmcd
downloadpcp-debian/3.9.10.tar.gz
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmdas/pmcd')
-rw-r--r--src/pmdas/pmcd/GNUmakefile55
-rw-r--r--src/pmdas/pmcd/help533
-rw-r--r--src/pmdas/pmcd/root_pmcd153
-rw-r--r--src/pmdas/pmcd/src/GNUmakefile68
-rwxr-xr-xsrc/pmdas/pmcd/src/objstyle88
-rw-r--r--src/pmdas/pmcd/src/pmcd.c1869
6 files changed, 2766 insertions, 0 deletions
diff --git a/src/pmdas/pmcd/GNUmakefile b/src/pmdas/pmcd/GNUmakefile
new file mode 100644
index 0000000..1534531
--- /dev/null
+++ b/src/pmdas/pmcd/GNUmakefile
@@ -0,0 +1,55 @@
+#!gmake
+#
+# Copyright (c) 2000-2001,2003,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
+#
+# pmcd PMDA
+#
+
+TOPDIR = ../../..
+include $(TOPDIR)/src/include/builddefs
+
+DFILES = help
+LTARGETS = help.dir
+LDIRT = *.log *.dir *.pag domain.h so_locations
+
+TARGETS = help.dir
+LSRCFILES = help root_pmcd
+
+SUBDIRS = src
+PMDADIR = $(PCP_PMDAS_DIR)/pmcd
+CONF_LINE = "pmcd 2 dso pmcd_init $(PCP_PMDAS_DIR)/pmcd/pmda_pmcd.$(DSOSUFFIX)"
+
+default_pcp default :: $(TARGETS)
+
+default_pcp default :: $(SUBDIRS)
+ $(SUBDIRS_MAKERULE)
+ @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \
+ echo $(CONF_LINE) >> ../pmcd.conf ; \
+ fi
+
+install_pcp install :: $(SUBDIRS)
+ $(SUBDIRS_MAKERULE)
+
+install_pcp install :: $(SUBDIRS)
+ $(INSTALL) -m 755 -d $(PMDADIR)
+ $(INSTALL) -m 644 help.dir help.pag $(PMDADIR)
+ $(INSTALL) -m 644 root_pmcd $(PCP_VAR_DIR)/pmns/root_pmcd
+
+help.dir: help root_pmcd
+ $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -v 2 -n root_pmcd -o help < help
+
+include $(BUILDRULES)
diff --git a/src/pmdas/pmcd/help b/src/pmdas/pmcd/help
new file mode 100644
index 0000000..402ecf2
--- /dev/null
+++ b/src/pmdas/pmcd/help
@@ -0,0 +1,533 @@
+#
+# Copyright (c) 2013 Red Hat.
+# 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.
+#
+# pmcd 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 text 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
+#
+
+@ 2.1 Instance domain "pmloggers" from PMCD PMDA
+This is the list of currently active pmlogger instances on the same
+machine as this PMCD. The instance names are the process ids of the
+pmlogger instances. The primary pmlogger has an extra instance with the
+instance name "primary" and an instance id of zero (in addition to its
+normal process id instance).
+
+@ 2.2 pmcd control register Instance Domain
+One instance per pmcd control register.
+
+The internal instance identifiers are the numbers 0 to 15.
+The external instance names are he ASCII equivalent of the internal
+instance identifiers.
+
+@ 2.3 PMDA Instance Domain
+One instance per PMDA managed by PMCD. The external and internal instance
+identifiers are taken from the first two fields of the PMDA specification
+in $PCP_PMCDCONF_PATH.
+
+@ 2.4 pmie Instance Domain
+One instance per running pmie process. The internal and external instance
+identifiers are the process ids of the pmie instances.
+
+@ 2.5 buffer pool Instance Domain
+The instances are as follows:
+
+ 1024 1024-byte PDU buffers managed by __pmFindPDUBuf, __pmPinPDUBuf
+ and __pmUnpinPDUBuf
+ 2048 2-Kbyte PDU buffers managed by __pmFindPDUBuf, __pmPinPDUBuf
+ and __pmUnpinPDUBuf
+ 4096 3-Kbyte or 4-Kbyte PDU buffers managed by __pmFindPDUBuf,
+ __pmPinPDUBuf and __pmUnpinPDUBuf
+ 8192 5-Kbyte, 6-Kbyte, 7-Kbyte or 8-Kbyte PDU buffers managed by
+ __pmFindPDUBuf, __pmPinPDUBuf and __pmUnpinPDUBuf
+ 8192+ PDU buffers larger that 8-Kbyte managed by __pmFindPDUBuf,
+ __pmPinPDUBuf and __pmUnpinPDUBuf
+
+@ pmcd.numagents Number of agents (PMDAs) currently connected to PMCD
+The number of agents (PMDAs) currently connected to PMCD. This may differ
+from the number of agents configured in $PCP_PMCDCONF_PATH if agents have
+terminated and/or been timed-out by PMCD.
+
+@ pmcd.numclients Number of clients currently connected to PMCD
+The number of connections open to client programs retrieving information
+from PMCD.
+
+@ pmcd.datasize Space allocated for PMCD and DSO agents' data segment (K)
+This metric returns the amount of memory in kilobytes allocated for the
+data segment of PMCD and any DSO agents (PMDAs) that it has loaded.
+
+This is handy for tracing memory utilization (and leaks) in DSOs during
+development.
+
+@ pmcd.buf.alloc Allocated buffers in internal memory pools
+This metric returns the number of allocated buffers for the various buffer
+pools used by pmcd.
+
+This is handy for tracing memory utilization (and leaks) in DSOs during
+development.
+
+@ pmcd.buf.free Free buffers in internal memory pools
+This metric returns the number of free buffers for the various buffer
+pools used by pmcd.
+
+This is handy for tracing memory utilization (and leaks) in DSOs during
+development.
+
+@ pmcd.control.timeout Timeout interval for slow/hung agents (PMDAs)
+PDU exchanges with agents (PMDAs) managed by PMCD are subject to timeouts
+which detect and clean up slow or disfunctional agents. This metric
+returns the current timeout period in seconds being used for the agents.
+If the value is zero, timeouts are not being used. This corresponds to
+the -t option described in the man page, pmcd(1).
+
+It is possible to store a new timeout value into this metric. Storing zero
+will turn off timeouts. Subsequent storing of a non-zero value will turn
+on the timeouts again.
+
+@ pmcd.control.debug Current value of PMCD debug flags
+The current value of the PMCD debug flags. This is a bit-wise OR of the
+flags described in the output of pmdbg -l. The PMCD-specific flags are:
+
+ DBG_TRACE_APPL0 2048 Trace agent & client I/O and termination
+ DBG_TRACE_APPL1 4096 Trace host access control
+ DBG_TRACE_APPL2 8192 Trace config file scanner and parser
+
+It is possible to store values into this metric. Diagnostic output is
+written to the PMCD log file (usually $PCP_LOG_DIR/pmcd/pmcd.log).
+
+Setting this metric to -1 terminates PMCD.
+
+@ pmcd.pdu_in.total Total PDUs received by PMCD
+Running total of all BINARY mode PDUs received by the PMCD from clients
+and agents.
+
+@ pmcd.pdu_in.error ERROR PDUs received by PMCD
+Running total of BINARY mode ERROR PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.result RESULT PDUs received by PMCD
+Running total of BINARY mode RESULT PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.profile PROFILE PDUs received by PMCD
+Running total of BINARY mode PROFILE PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.fetch FETCH PDUs received by PMCD
+Running total of BINARY mode FETCH PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.desc_req DESC_REQ PDUs received by PMCD
+Running total of BINARY mode DESC_REQ PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.desc DESC PDUs received by PMCD
+Running total of BINARY mode DESC PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.instance_req INSTANCE_REQ PDUs received by PMCD
+Running total of BINARY mode INSTANCE_REQ PDUs received by the PMCD
+from clients and agents.
+
+@ pmcd.pdu_in.instance INSTANCE PDUs received by PMCD
+Running total of BINARY mode INSTANCE PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.text_req TEXT_REQ PDUs received by PMCD
+Running total of BINARY mode TEXT_REQ PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.text TEXT PDUs received by PMCD
+Running total of BINARY mode TEXT PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.control_req CONTROL_REQ PDUs received by PMCD
+Running total of BINARY mode CONTROL_REQ PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.creds CREDS PDUs received by PMCD
+Running total of BINARY mode CREDS PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.pmns_ids PMNS_IDS PDUs received by PMCD
+Running total of BINARY mode PMNS_IDS PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.pmns_names PMNS_NAMES PDUs received by PMCD
+Running total of BINARY mode PMNS_NAMES PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.pmns_child PMNS_CHILD PDUs received by PMCD
+Running total of BINARY mode PMNS_CHILD PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.pmns_traverse PMNS_TRAVERSE PDUs received by PMCD
+Running total of BINARY mode PMNS_TRAVERSE PDUs received by the PMCD from
+clients and agents.
+
+@ pmcd.pdu_in.auth AUTH PDUs received by PMCD
+Running total of BINARY mode AUTH PDUs received by the PMCD from
+clients and agents. These PDUs are used for authentication.
+
+@ pmcd.pdu_out.total Total PDUs sent by PMCD
+Running total of all BINARY mode PDUs sent by the PMCD to clients and
+agents.
+
+@ pmcd.pdu_out.error ERROR PDUs sent by PMCD
+Running total of BINARY mode ERROR PDUs sent by the PMCD to clients and
+agents.
+
+@ pmcd.pdu_out.result RESULT PDUs sent by PMCD
+Running total of BINARY mode RESULT PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.profile PROFILE PDUs sent by PMCD
+Running total of BINARY mode PROFILE PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.fetch FETCH PDUs sent by PMCD
+Running total of BINARY mode FETCH PDUs sent by the PMCD to clients and
+agents.
+
+@ pmcd.pdu_out.desc_req DESC_REQ PDUs sent by PMCD
+Running total of BINARY mode DESC_REQ PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.desc DESC PDUs sent by PMCD
+Running total of BINARY mode DESC PDUs sent by the PMCD to clients and
+agents.
+
+@ pmcd.pdu_out.instance_req INSTANCE_REQ PDUs sent by PMCD
+Running total of BINARY mode INSTANCE_REQ PDUs sent by the PMCD to
+clients and agents.
+
+@ pmcd.pdu_out.instance INSTANCE PDUs sent by PMCD
+Running total of BINARY mode INSTANCE PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.text_req TEXT_REQ PDUs sent by PMCD
+Running total of BINARY mode TEXT_REQ PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.text TEXT PDUs sent by PMCD
+Running total of BINARY mode TEXT PDUs sent by the PMCD to clients and
+agents.
+
+@ pmcd.pdu_out.control_req CONTROL_REQ PDUs sent by PMCD
+Running total of BINARY mode CONTROL_REQ PDUs sent by the PMCD to
+clients and agents.
+
+@ pmcd.pdu_out.creds CREDS PDUs sent by PMCD
+Running total of BINARY mode CREDS PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.pmns_ids PMNS_IDS PDUs sent by PMCD
+Running total of BINARY mode PMNS_IDS PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.pmns_names PMNS_NAMES PDUs sent by PMCD
+Running total of BINARY mode PMNS_NAMES PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.pmns_child PMNS_CHILD PDUs sent by PMCD
+Running total of BINARY mode PMNS_CHILD PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.pmns_traverse PMNS_TRAVERSE PDUs sent by PMCD
+Running total of BINARY mode PMNS_TRAVERSE PDUs sent by the PMCD to clients
+and agents.
+
+@ pmcd.pdu_out.auth AUTH PDUs sent by PMCD
+Running total of BINARY mode AUTH PDUs sent by the PMCD to clients
+and agents. These PDUs are used for authentication.
+
+@ pmcd.pmlogger.host host where active pmlogger is running
+The fully qualified domain name of the host on which a pmlogger
+instance is running.
+
+The instance names are process ids of the active pmloggers. The
+primary pmlogger has an extra instance with the instance name "primary"
+and an instance id of zero (in addition to its normal process id
+instance).
+
+@ pmcd.pmlogger.port control port for active pmlogger
+Each pmlogger instance has a port for receiving log control
+information. This metric is a list of the active pmlogger control
+ports on the same machine as this PMCD (i.e. the host identified in the
+corresponding pmcd.pmlogger.host metric).
+
+The instance names are process ids of the active pmloggers. The
+primary pmlogger has an extra instance with the instance name "primary"
+and an instance id of zero (in addition to its normal process id
+instance).
+
+@ pmcd.pmlogger.archive full pathname to archive basename for active pmlogger
+The full pathname through the filesystem on the corresponding host
+(pmcd.pmlogger.host) that is the base name for the archive log files.
+
+The instance names are process ids of the active pmloggers. The
+primary pmlogger has an extra instance with the instance name "primary"
+and an instance id of zero (in addition to its normal process id
+instance).
+
+@ pmcd.pmlogger.pmcd_host host from which active pmlogger is fetching metrics
+The fully qualified domain name of the host from which a pmlogger
+instance is fetching metrics to be archived.
+
+The instance names are process ids of the active pmloggers. The
+primary pmlogger has an extra instance with the instance name "primary"
+and an instance id of zero (in addition to its normal process id
+instance).
+
+@ pmcd.timezone local $TZ
+Value for the $TZ environment variable where the PMCD is running.
+Enables determination of "local" time for timestamps returned via
+PMCD from a remote host.
+
+@ pmcd.hostname local hostname
+A reasonably unique identifier of the PMCD installation, for use
+by pmlogger or other tools to identify the source principal of
+the data (as distinct from identifying the connection/protocol
+used to reach it).
+
+@ pmcd.simabi Procedure call model and ABI version of this PMCD
+SIM is the subprogram interface model (originally from the MIPS object
+code formats), and ABI is the application binary interface. Both
+relate to the way the PMCD binary was compiled and linked.
+
+Usually DSO PMDAs must be compiled and linked in the same way before
+they can be used with PMCD.
+
+On some platforms this metric is not available.
+
+@ pmcd.version PMCD version
+
+@ pmcd.control.register a vector of registers that may be set by users
+A vector of 16 32-bit registers that are identified by the instance
+identifiers 0 through 15.
+
+The register contents are initially zero, but may be subsequently
+modified to be an arbitrary value using pmStore(3) or pmstore(1).
+
+The values are not used internally, but rather act as a repository into
+which operational information might be stored, and then exported to
+modify the behavior of client programs, e.g. inhibit pmie(1) rule
+firing, or trigger a status indicator. In this way,
+pmcd.control.register acts like a primitive bulletin board.
+
+Example use might be as follows
+ register[0] telephone no. of person assigned to current system problem
+ register[1] telephone no. of person assigned to current network problem
+ register[2] ORACLE database is down
+ register[3] backup in progress
+ register[4] shopping days to Christmas
+
+@ pmcd.control.traceconn control PMCD connection event tracing
+Set to 1 to enable PMCD event tracing for all connection-related
+events for clients and PMDAs.
+
+Set to 0 to disable PMCD connection event tracing.
+
+@ pmcd.control.tracepdu control PMCD PDU event tracing
+Set to 1 to enable PMCD event tracing for all PDUs sent and received
+by PMCD.
+
+Set to 0 to disable PMCD PDU event tracing.
+
+@ pmcd.control.tracenobuf control buffering of PMCD event tracing
+Set to 1 to enable unbuffered PMCD event tracing, where each event is
+reported as it happens.
+
+Set to 0 to enable buffering of PMCD event traces (this is the default),
+and event traces will only be dumped or reported when an error occurs or
+a value is stored into the PCP metric pmcd.control.dumptrace.
+
+@ pmcd.control.tracebufs number of buffers for PMCD event tracing
+Defaults to 20. May be changed dynamically.
+
+@ pmcd.control.dumptrace force dump of PMCD event tracing buffers
+Storing any value into this metric causes the PMCD event trace buffers to
+be dumped to PMCD's log file.
+
+@ pmcd.control.sighup force PMCD reset via SIGHUP
+Storing any value into this metric causes PMCD to be reset by sending
+itself a SIGHUP signal.
+
+On reset (either by storing into pmcd.control.sighup or by sending PMCD a
+SIGHUP directly), PMCD will restart any failed PMDAs and reload the PMNS
+if it has been changed.
+
+@ pmcd.control.dumpconn force dump of PMCD client connections
+Storing any value into this metric causes the details of the current PMCD
+client connections to be dumped to PMCD's log file.
+
+@ pmcd.agent.type PMDA type
+From $PCP_PMCDCONF_PATH, this metric encodes the PMDA type as follows:
+ (x << 1) | y
+where "x" is the IPC type between PMCD and the PMDA, i.e. 0 for DSO, 1
+for socket or 2 for pipe, and "y" is the message passing style, i.e.
+0 for binary or 1 for ASCII.
+
+@ pmcd.agent.status PMDA status
+This metric encodes the current status of each PMDA. The default value
+is 0 if the PMDA is active.
+
+Other values encode various degrees of PMDA difficulty in three bit fields
+(bit 0 is the low-order bit) as follows:
+
+bits 7..0
+ 1 the PMDA is connected, but not yet "ready" to accept requests
+ from the PMDA
+ 2 the PMDA has exited of its own accord
+ 4 some error prevented the PMDA being started
+ 8 PMCD stopped communication with the PMDA due to a protocol or
+ timeout error
+
+bits 15..8
+ the exit() status from the PMDA
+
+bits 23..16
+ the number of the signal that terminated the PMDA
+
+@ pmcd.services running PCP services on the local host
+A space-separated string representing all running PCP services with PID
+files in $PCP_RUN_DIR (such as pmcd itself, pmproxy and a few others).
+
+@ pmcd.openfds highest PMCD file descriptor
+The highest file descriptor index used by PMCD for a Client or PMDA
+connection.
+
+@ pmcd.pmie.numrules number of rules being evaluated
+The total number of rules being evaluated by each pmie process.
+
+@ pmcd.pmie.eval.true count of pmie predicates evaluated to true
+The predicate part of a pmie rule can be said to evaluate to either true,
+false, or not known. This metric is a cumulative count of the number of
+rules which have evaluated to true for each pmie instance.
+
+@ pmcd.pmie.eval.false count of pmie predicates evaluated to false
+The predicate part of a pmie rule can be said to evaluate to either true,
+false, or not known. This metric is a cumulative count of the number of
+rules which have evaluated to false for each pmie instance.
+
+@ pmcd.pmie.eval.unknown count of pmie predicates not evaluated
+The predicate part of a pmie rule can be said to evaluate to either true,
+false, or not known. This metric is a cumulative count of the number of
+rules which have not been successfully evaluated. This could be due to not
+yet having sufficient values to evaluate the rule, or a metric fetch may
+have been unsuccessful in retrieving current values for metrics required
+for evaluation of the rule.
+
+@ pmcd.pmie.eval.expected expected rate of rule evaluations
+This is the expected rate of evaluation of pmie rules. The value is
+calculated once when pmie starts, and is the number of pmie rules divided
+by the average time interval over which they are to be evaluated.
+
+@ pmcd.pmie.eval.actual count of actual rule evaluations
+A cumulative count of the pmie rules which have been evaluated.
+
+This value is incremented once for each evaluation of each rule.
+
+@ pmcd.pmie.actions count of rules evaluating to true
+A cumulative count of the evaluated pmie rules which have evaluated to true.
+
+This value is incremented once each time an action is executed. This value
+will always be less than or equal to pmcd.pmie.eval.true because predicates
+which have evaluated to true may be suppressed in the action part of the
+pmie rule, in which case this counter will not be incremented.
+
+@ pmcd.pmie.configfile configuration file name
+The full path in the filesystem to the configuration file containing the
+rules being evaluated by each pmie instance.
+
+If the configuration file was supplied on the standard input, then this
+metric will have the value "<stdin>". If multiple configuration files were
+given to pmie, then the value of this metric will be the first configuration
+file specified.
+
+@ pmcd.pmie.pmcd_host default hostname for pmie instance
+The default host from which pmie is fetching metrics. This is either the
+hostname given to pmie on the command line or the local host. Note that this
+does not consider host names specified in the pmie configuration file (these
+are considered non-default and can be more than one per pmie instance).
+All daemon pmie instances started through pmie_check(1) will have their
+default host passed in on their command line.
+
+@ pmcd.pmie.logfile filename of pmie instance event log
+The file to which each instance of pmie is writting events. No two pmie
+instances can share the same log file. If no logfile was specified when
+pmie was started, this metrics has the value "<none>". All daemon pmie
+instances started through pmie_check(1) must have an associated log file.
+
+@ pmcd.build build version for installed PCP package
+Minor part of the PCP build version numbering. For example on Linux
+with RPM packaging, if the PCP RPM version is pcp-2.5.99-20070323 then
+pmcd.build returns the string "20070323".
+
+@ pmcd.client.whoami optional identification information for clients of pmcd
+This metric is defined over an instance domain containing one entry
+per active client of pmcd. The instance number is a sequence number
+for each client (restarts at 0 each time pmcd is restarted). The value
+of the metric by default is the IP address of the client.
+
+Clients can optionally use pmStore to modify their own "whoami" string
+to provide more useful information about the client.
+
+@ pmcd.client.start_date date and time client connected to pmcd
+The date and time in ctime(2) format on which the client connected
+to pmcd.
+
+@ pmcd.cputime.total CPU time used by pmcd and DSO PMDAs
+Sum of user and system time since pmcd started.
+
+@ pmcd.cputime.per_pdu_in average CPU time per PDU received by pmcd
+When first requested it is the average since pmcd started, so
+pmcd.cputime.total divided by pmcd.pdu_in.total.
+
+Subsequent fetches by a PMAPI client will return the average CPU
+time per PDU received by pmcd (for all clients) since the last time
+the PMAPI client fetched this metric.
+
+@ pmcd.feature.secure status of secure_sockets protocol feature in pmcd
+A value of zero indicates no support, one indicates actively available
+(including configuration and validity of the server side certificates).
+
+@ pmcd.feature.compress status of protocol compression feature in pmcd
+A value of zero indicates no support, one indicates actively available.
+
+@ pmcd.feature.ipv6 status of Internet Protocol Version 6 support in pmcd
+A value of zero indicates no support, one indicates actively available.
+
+@ pmcd.feature.authentication status of per-user authentication support
+A value of zero indicates no support, one indicates actively available.
+
+@ pmcd.feature.creds_required status of required credentials support
+A value of zero indicates no support, one indicates actively available.
+
+@ pmcd.feature.unix_domain_sockets status of unix domain socket support
+A value of zero indicates no support, one indicates actively available.
+
+@ pmcd.feature.service_discovery status of service advertising and discovery
+A value of zero indicates no support, one indicates actively available.
diff --git a/src/pmdas/pmcd/root_pmcd b/src/pmdas/pmcd/root_pmcd
new file mode 100644
index 0000000..010df41
--- /dev/null
+++ b/src/pmdas/pmcd/root_pmcd
@@ -0,0 +1,153 @@
+/*
+ * PMCD metrics name space
+ */
+
+root {
+ pmcd
+}
+
+/*
+ * the domain for the pmcd PMDA ...
+ */
+#ifndef PMCD
+#define PMCD 2
+#endif
+
+pmcd {
+ control
+ pdu_in
+ pdu_out
+ datasize PMCD:0:1
+ numagents PMCD:0:2
+ agent
+ numclients PMCD:0:3
+ pmlogger
+ timezone PMCD:0:5
+ simabi PMCD:0:6
+ version PMCD:0:7
+ services PMCD:0:16
+ openfds PMCD:0:17
+ build PMCD:0:20
+ hostname PMCD:0:21
+ pmie
+ buf
+ client
+ cputime
+ feature
+}
+
+pmcd.control {
+ debug PMCD:0:0
+ timeout PMCD:0:4
+ register PMCD:0:8
+ traceconn PMCD:0:9
+ tracepdu PMCD:0:10
+ tracenobuf PMCD:0:14
+ tracebufs PMCD:0:11
+ dumptrace PMCD:0:12
+ dumpconn PMCD:0:13
+ sighup PMCD:0:15
+}
+
+/*
+ * Note: strange numbering for pmcd.pdu_{in,out}.total for
+ * compatibility with earlier PCP versions
+ */
+
+pmcd.pdu_in {
+ error PMCD:1:0
+ result PMCD:1:1
+ profile PMCD:1:2
+ fetch PMCD:1:3
+ desc_req PMCD:1:4
+ desc PMCD:1:5
+ instance_req PMCD:1:6
+ instance PMCD:1:7
+ text_req PMCD:1:8
+ text PMCD:1:9
+ control_req PMCD:1:10
+ creds PMCD:1:12
+ pmns_ids PMCD:1:13
+ pmns_names PMCD:1:14
+ pmns_child PMCD:1:15
+ total PMCD:1:16
+ pmns_traverse PMCD:1:17
+ auth PMCD:1:18
+}
+
+pmcd.pdu_out {
+ error PMCD:2:0
+ result PMCD:2:1
+ profile PMCD:2:2
+ fetch PMCD:2:3
+ desc_req PMCD:2:4
+ desc PMCD:2:5
+ instance_req PMCD:2:6
+ instance PMCD:2:7
+ text_req PMCD:2:8
+ text PMCD:2:9
+ control_req PMCD:2:10
+ creds PMCD:2:12
+ pmns_ids PMCD:2:13
+ pmns_names PMCD:2:14
+ pmns_child PMCD:2:15
+ total PMCD:2:16
+ pmns_traverse PMCD:2:17
+ auth PMCD:2:18
+}
+
+pmcd.pmlogger {
+ host PMCD:3:3
+ port PMCD:3:0
+ archive PMCD:3:2
+ pmcd_host PMCD:3:1
+}
+
+pmcd.agent {
+ type PMCD:4:0
+ status PMCD:4:1
+}
+
+pmcd.pmie {
+ configfile PMCD:5:0
+ logfile PMCD:5:1
+ pmcd_host PMCD:5:2
+ numrules PMCD:5:3
+ actions PMCD:5:4
+ eval
+}
+
+pmcd.pmie.eval {
+ true PMCD:5:5
+ false PMCD:5:6
+ unknown PMCD:5:7
+ expected PMCD:5:8
+ actual PMCD:5:9
+}
+
+pmcd.buf {
+ alloc PMCD:0:18
+ free PMCD:0:19
+}
+
+pmcd.client {
+ whoami PMCD:6:0
+ start_date PMCD:6:1
+}
+
+pmcd.cputime {
+ total PMCD:7:0
+ per_pdu_in PMCD:7:1
+}
+
+pmcd.feature {
+ secure PMCD:8:0
+ compress PMCD:8:1
+ ipv6 PMCD:8:2
+ authentication PMCD:8:3
+ creds_required PMCD:8:4
+ unix_domain_sockets PMCD:8:5
+ service_discovery PMCD:8:6
+}
+
+#undef PMCD
diff --git a/src/pmdas/pmcd/src/GNUmakefile b/src/pmdas/pmcd/src/GNUmakefile
new file mode 100644
index 0000000..ff5b4ff
--- /dev/null
+++ b/src/pmdas/pmcd/src/GNUmakefile
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2000,2003,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.
+#
+
+TOPDIR = ../../../..
+include $(TOPDIR)/src/include/builddefs
+
+LIBTARGET = pmda_pmcd.$(DSOSUFFIX)
+PMDAINIT = pmcd_init
+
+CFILES = pmcd.c
+LSRCFILES = objstyle
+VERSION_SCRIPT = exports
+LDIRT = $(VERSION_SCRIPT)
+
+# Add to CFLAGS to find files in pmcd/src...
+LCFLAGS = -I$(TOPDIR)/src
+LCFLAGS += -I$(TOPDIR)/src/pmie/src
+
+ifneq (, $(filter linux kfreebsd gnu, $(TARGET_OS)))
+ABI = $(shell ./objstyle)
+LCFLAGS += -DSIM_ABI=\""$(ABI)"\"
+endif
+ifeq "$(TARGET_OS)" "darwin"
+ABI = $(shell ./objstyle)
+LCFLAGS += -DSIM_ABI=\"$(ABI)\"
+endif
+ifdef PACKAGE_BUILD
+BUILD = $(PACKAGE_BUILD)
+else
+BUILD = unknown
+endif
+
+LCFLAGS += -DBUILD=\"$(BUILD)\"
+LCFLAGS += $(INVISIBILITY)
+
+LLDLIBS = $(PCP_PMDALIB)
+ifeq "$(TARGET_OS)" "mingw"
+LLDLIBS += -lpcp_pmcd
+PCPLIB_LDFLAGS += -L$(TOPDIR)/src/libpcp_pmcd/src
+endif
+
+default: $(LIBTARGET)
+
+install: default
+ $(INSTALL) -m 755 -d $(PCP_PMDAS_DIR)/pmcd
+ $(INSTALL) -m 755 $(LIBTARGET) $(PCP_PMDAS_DIR)/pmcd/$(LIBTARGET)
+
+include $(BUILDRULES)
+
+default_pcp : default
+
+install_pcp : install
+
+$(LIBTARGET): $(VERSION_SCRIPT)
+
+$(VERSION_SCRIPT):
+ $(VERSION_SCRIPT_MAKERULE)
diff --git a/src/pmdas/pmcd/src/objstyle b/src/pmdas/pmcd/src/objstyle
new file mode 100755
index 0000000..5929bab
--- /dev/null
+++ b/src/pmdas/pmcd/src/objstyle
@@ -0,0 +1,88 @@
+#! /bin/sh
+#
+# 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.
+#
+# 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
+#
+# identify the objstyle of linux platforms other than ia32 and ia64.
+
+echo 'int main(){return 0;}' >dummy.c
+cc -c dummy.c
+
+# we've had bad experience with file(1) and compiled "magic" files
+# on assorted Linux versions ... try to use the uncompiled magic
+# file if possible
+#
+# if you need to modify this, make consistent changes in
+# src/pmdas/pmcd/src/objstyle
+# qa/605
+#
+magic=''
+for file in /usr/share/misc/magic /usr/share/file/magic /usr/share/magic \
+ /etc/magic
+do
+ if [ -f "$file" ]
+ then
+ # found a file, check it contains some definitions ...
+ nl=`sed -e '/^#/d' -e '/^[ ]*$/d' <"$file" | wc -l | sed -e 's/ //g'`
+ if [ "$nl" -gt 0 ]
+ then
+ magic=$file
+ break
+ fi
+ fi
+done
+
+# sample file output
+#
+# ia32 laptop
+# dummy.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
+#
+# Mac OS X
+# pmcd.o: Mach-O universal binary with 2 architectures
+# pmcd.o (for architecture i386): Mach-O object i386
+# pmcd.o (for architecture x86_64): Mach-O 64-bit object x86_64
+#
+# dummy.o: Mach-O 64-bit object x86_64
+#
+# SLES10
+# dummy.o: ELF 64-bit LSB relocatable, IA-64 (Intel 64 bit architecture), version 1 (SYSV), not stripped
+#
+
+if [ -n "$magic" ]
+then
+ file -m $magic dummy.o
+else
+ file dummy.o
+fi \
+| ( sed -n \
+ -e '/ ELF /{
+s/^[^,]*, //
+s/, .*//
+s/ *([^)]*)//
+s/ //
+s/x86-64/x86_64/
+p
+}' \
+ -e '/object/{
+s/[ ]*$//
+s/.*[ ]//
+p
+}' \
+| tr '[\012]' '[+]' \
+; echo ) \
+| sed -e 's/+$//'
+
+rm -f dummy.[co]
diff --git a/src/pmdas/pmcd/src/pmcd.c b/src/pmdas/pmcd/src/pmcd.c
new file mode 100644
index 0000000..fecfd28
--- /dev/null
+++ b/src/pmdas/pmcd/src/pmcd.c
@@ -0,0 +1,1869 @@
+/*
+ * Copyright (c) 2013-2014 Red Hat.
+ * Copyright (c) 1995-2001,2003,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.
+ */
+
+#include "pmapi.h"
+#include "impl.h"
+#include "pmda.h"
+#include "stats.h"
+#include "pmcd/src/pmcd.h"
+#include "pmcd/src/client.h"
+#include <sys/stat.h>
+#if defined(IS_SOLARIS)
+#include <sys/systeminfo.h>
+#endif
+
+/*
+ * Note: strange numbering for pmcd.pdu_{in,out}.total for
+ * compatibility with earlier PCP versions ... this is the "item"
+ * field of the PMID
+ */
+#define _TOTAL 16
+
+/*
+ * all metrics supported in this PMD - one table entry for each
+ */
+static pmDesc desctab[] = {
+/* control.debug */
+ { PMDA_PMID(0,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* datasize */
+ { PMDA_PMID(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) },
+/* numagents */
+ { PMDA_PMID(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* numclients */
+ { PMDA_PMID(0,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* control.timeout */
+ { PMDA_PMID(0,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* timezone -- local $TZ -- for pmlogger */
+ { PMDA_PMID(0,5), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* simabi -- Subprogram Interface Model, ABI version of this pmcd (normally PM_TYPE_STRING) */
+ { PMDA_PMID(0,6), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* version -- pcp version */
+ { PMDA_PMID(0,7), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* control.register -- bulletin board */
+ { PMDA_PMID(0,8), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* control.traceconn -- trace connections */
+ { PMDA_PMID(0,9), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* control.tracepdu -- trace PDU traffic */
+ { PMDA_PMID(0,10), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* control.tracebufs -- number of trace buffers */
+ { PMDA_PMID(0,11), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* control.dumptrace -- push-button, pmStore to dump trace */
+ { PMDA_PMID(0,12), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* control.dumpconn -- push-button, pmStore to dump connections */
+ { PMDA_PMID(0,13), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* control.tracenobuf -- unbuffered tracing */
+ { PMDA_PMID(0,14), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* control.sighup -- push-button, pmStore to SIGHUP pmcd */
+ { PMDA_PMID(0,15), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* services -- locally running PCP services */
+ { PMDA_PMID(0,16), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* openfds -- number of open file descriptors */
+ { PMDA_PMID(0,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* buf.alloc */
+ { PMDA_PMID(0,18), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* buf.free */
+ { PMDA_PMID(0,19), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* build -- pcp build number */
+ { PMDA_PMID(0,20), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* hostname -- local hostname -- for pmlogger */
+ { PMDA_PMID(0,21), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+
+/* pdu_in.error */
+ { PMDA_PMID(1,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.result */
+ { PMDA_PMID(1,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.profile */
+ { PMDA_PMID(1,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.fetch */
+ { PMDA_PMID(1,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.desc_req */
+ { PMDA_PMID(1,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.desc */
+ { PMDA_PMID(1,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.instance_req */
+ { PMDA_PMID(1,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.instance */
+ { PMDA_PMID(1,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.text_req */
+ { PMDA_PMID(1,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.text */
+ { PMDA_PMID(1,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.control_req */
+ { PMDA_PMID(1,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.creds */
+ { PMDA_PMID(1,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.pmns_ids */
+ { PMDA_PMID(1,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.pmns_names */
+ { PMDA_PMID(1,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.pmns_child */
+ { PMDA_PMID(1,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.total */
+ { PMDA_PMID(1,_TOTAL), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.pmns_traverse */
+ { PMDA_PMID(1,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_in.auth */
+ { PMDA_PMID(1,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+
+/* pdu_out.error */
+ { PMDA_PMID(2,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.result */
+ { PMDA_PMID(2,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.profile */
+ { PMDA_PMID(2,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.fetch */
+ { PMDA_PMID(2,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.desc_req */
+ { PMDA_PMID(2,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.desc */
+ { PMDA_PMID(2,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.instance_req */
+ { PMDA_PMID(2,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.instance */
+ { PMDA_PMID(2,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.text_req */
+ { PMDA_PMID(2,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.text */
+ { PMDA_PMID(2,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.control_req */
+ { PMDA_PMID(2,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.creds */
+ { PMDA_PMID(2,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.pmns_ids */
+ { PMDA_PMID(2,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.pmns_names */
+ { PMDA_PMID(2,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.pmns_child */
+ { PMDA_PMID(2,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.total */
+ { PMDA_PMID(2,_TOTAL), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.pmns_traverse */
+ { PMDA_PMID(2,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pdu_out.auth */
+ { PMDA_PMID(2,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+
+/* pmlogger.port */
+ { PMDA_PMID(3,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmlogger.pmcd_host */
+ { PMDA_PMID(3,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmlogger.archive */
+ { PMDA_PMID(3,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmlogger.host */
+ { PMDA_PMID(3,3), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+
+/* agent.type */
+ { PMDA_PMID(4,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* agent.status */
+ { PMDA_PMID(4,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+
+/* pmie.configfile */
+ { PMDA_PMID(5,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmie.logfile */
+ { PMDA_PMID(5,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmie.pmcd_host */
+ { PMDA_PMID(5,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmie.numrules */
+ { PMDA_PMID(5,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmie.actions */
+ { PMDA_PMID(5,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pmie.eval.true */
+ { PMDA_PMID(5,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pmie.eval.false */
+ { PMDA_PMID(5,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pmie.eval.unknown */
+ { PMDA_PMID(5,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+/* pmie.eval.expected */
+ { PMDA_PMID(5,8), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE) },
+/* pmie.eval.actual */
+ { PMDA_PMID(5,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) },
+
+/* client.whoami */
+ { PMDA_PMID(6,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* client.start_date */
+ { PMDA_PMID(6,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) },
+
+/* pmcd.cputime.total */
+ { PMDA_PMID(7,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) },
+/* pmcd.cputime.per_pdu_in */
+ { PMDA_PMID(7,1), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,-1,0,PM_TIME_USEC,PM_COUNT_ONE) },
+
+/* pmcd.feature.secure */
+ { PMDA_PMID(8,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmcd.feature.compress */
+ { PMDA_PMID(8,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmcd.feature.ipv6 */
+ { PMDA_PMID(8,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmcd.feature.authentication */
+ { PMDA_PMID(8,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmcd.feature.creds_required */
+ { PMDA_PMID(8,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmcd.feature.unix_domain_sockets */
+ { PMDA_PMID(8,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+/* pmcd.feature.service_discovery */
+ { PMDA_PMID(8,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) },
+
+/* End-of-List */
+ { PM_ID_NULL, 0, 0, 0, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }
+};
+static int ndesc = sizeof(desctab)/sizeof(desctab[0]);
+
+static __pmProfile *_profile; /* last received profile */
+
+/* there are four instance domains: pmlogger, register, PMDA, and pmie */
+#define INDOM_PMLOGGERS 1
+static pmInDom logindom;
+#define INDOM_REGISTER 2
+static pmInDom regindom;
+#define INDOM_PMDAS 3
+static pmInDom pmdaindom;
+#define INDOM_PMIES 4
+static pmInDom pmieindom;
+#define INDOM_POOL 5
+static pmInDom bufindom;
+#define INDOM_CLIENT 6
+static pmInDom clientindom;
+
+#define NUMREG 16
+static int reg[NUMREG];
+
+typedef struct {
+ pid_t pid;
+ int size;
+ char *name;
+ void *mmap;
+} pmie_t;
+static pmie_t *pmies;
+static unsigned int npmies;
+
+static struct {
+ int inst;
+ char *iname;
+} bufinst[] = {
+ { 12, "0012" },
+ { 20, "0020" },
+ { 1024, "1024" },
+ { 2048, "2048" },
+ { 4196, "4196" },
+ { 8192, "8192" },
+ { 8193, "8192+" },
+};
+static int nbufsz = sizeof(bufinst) / sizeof(bufinst[0]);
+
+typedef struct {
+ int id; /* index into client[] */
+ int seq;
+ char *value;
+} whoami_t;
+static whoami_t *whoamis;
+static unsigned int nwhoamis;
+
+typedef struct {
+ int state;
+ double last_cputime;
+ __uint64_t last_pdu_in;
+} perctx_t;
+
+/* values for per context state */
+#define CTX_INACTIVE 0
+#define CTX_ACTIVE 1
+
+static perctx_t *ctxtab = NULL;
+static int num_ctx = 0;
+
+/*
+ * expand and initialize the per client context table
+ */
+static void
+grow_ctxtab(int ctx)
+{
+ ctxtab = (perctx_t *)realloc(ctxtab, (ctx+1)*sizeof(ctxtab[0]));
+ if (ctxtab == NULL) {
+ __pmNoMem("grow_ctxtab", (ctx+1)*sizeof(ctxtab[0]), PM_FATAL_ERR);
+ /*NOTREACHED*/
+ }
+ while (num_ctx <= ctx) {
+ ctxtab[num_ctx].state = CTX_INACTIVE;
+ num_ctx++;
+ }
+ ctxtab[ctx].state = CTX_INACTIVE;
+}
+
+/*
+ * this routine is called at initialization to patch up any parts of the
+ * desctab that cannot be statically initialized, and to optionally
+ * modify our Performance Metrics Domain Id (dom)
+ */
+static void
+init_tables(int dom)
+{
+ int i;
+ __pmID_int *pmidp;
+ __pmInDom_int *indomp;
+
+ /* set domain in instance domain correctly */
+ indomp = (__pmInDom_int *)&logindom;
+ indomp->flag = 0;
+ indomp->domain = dom;
+ indomp->serial = INDOM_PMLOGGERS;
+ indomp = (__pmInDom_int *)&regindom;
+ indomp->flag = 0;
+ indomp->domain = dom;
+ indomp->serial = INDOM_REGISTER;
+ indomp = (__pmInDom_int *)&pmdaindom;
+ indomp->flag = 0;
+ indomp->domain = dom;
+ indomp->serial = INDOM_PMDAS;
+ indomp = (__pmInDom_int *)&pmieindom;
+ indomp->flag = 0;
+ indomp->domain = dom;
+ indomp->serial = INDOM_PMIES;
+ indomp = (__pmInDom_int *)&bufindom;
+ indomp->flag = 0;
+ indomp->domain = dom;
+ indomp->serial = INDOM_POOL;
+ indomp = (__pmInDom_int *)&clientindom;
+ indomp->flag = 0;
+ indomp->domain = dom;
+ indomp->serial = INDOM_CLIENT;
+
+ /* merge performance domain id part into PMIDs in pmDesc table */
+ for (i = 0; desctab[i].pmid != PM_ID_NULL; i++) {
+ pmidp = (__pmID_int *)&desctab[i].pmid;
+ pmidp->domain = dom;
+ if (pmidp->cluster == 0 && pmidp->item == 8)
+ desctab[i].indom = regindom;
+ else if (pmidp->cluster == 0 && (pmidp->item == 18 || pmidp->item == 19))
+ desctab[i].indom = bufindom;
+ else if (pmidp->cluster == 3)
+ desctab[i].indom = logindom;
+ else if (pmidp->cluster == 4)
+ desctab[i].indom = pmdaindom;
+ else if (pmidp->cluster == 5)
+ desctab[i].indom = pmieindom;
+ else if (pmidp->cluster == 6)
+ desctab[i].indom = clientindom;
+ }
+ ndesc--;
+}
+
+
+static int
+pmcd_profile(__pmProfile *prof, pmdaExt *pmda)
+{
+ _profile = prof;
+ return 0;
+}
+
+static void
+remove_pmie_indom(void)
+{
+ int n;
+
+ for (n = 0; n < npmies; n++) {
+ free(pmies[n].name);
+ __pmMemoryUnmap(pmies[n].mmap, pmies[n].size);
+ }
+ free(pmies);
+ pmies = NULL;
+ npmies = 0;
+}
+
+static int
+stat_time_differs(struct stat *statbuf, struct stat *lastsbuf)
+{
+#if defined(HAVE_ST_MTIME_WITH_E) && defined(HAVE_STAT_TIME_T)
+ if (statbuf->st_mtime != lastsbuf->st_mtime)
+ return 1;
+#elif defined(HAVE_ST_MTIME_WITH_SPEC)
+ if ((statbuf->st_mtimespec.tv_sec != lastsbuf->st_mtimespec.tv_sec) ||
+ (statbuf->st_mtimespec.tv_nsec != lastsbuf->st_mtimespec.tv_nsec))
+ return 1;
+#elif defined(HAVE_STAT_TIMESTRUC) || defined(HAVE_STAT_TIMESPEC) || defined(HAVE_STAT_TIMESPEC_T)
+ if ((statbuf->st_mtim.tv_sec != lastsbuf->st_mtim.tv_sec) ||
+ (statbuf->st_mtim.tv_nsec != lastsbuf->st_mtim.tv_nsec))
+ return 1;
+#else
+!bozo!
+#endif
+ return 0;
+}
+
+/* use a static timestamp, stat PMIE_SUBDIR, if changed update "pmies" */
+static unsigned int
+refresh_pmie_indom(void)
+{
+ static struct stat lastsbuf;
+ pid_t pmiepid;
+ struct dirent *dp;
+ struct stat statbuf;
+ size_t size;
+ char *endp;
+ char fullpath[MAXPATHLEN];
+ void *ptr;
+ DIR *pmiedir;
+ int fd;
+ int sep = __pmPathSeparator();
+
+ snprintf(fullpath, sizeof(fullpath), "%s%c%s",
+ pmGetConfig("PCP_TMP_DIR"), sep, PMIE_SUBDIR);
+ if (stat(fullpath, &statbuf) == 0) {
+ if (stat_time_differs(&statbuf, &lastsbuf)) {
+
+ lastsbuf = statbuf;
+
+ /* tear down the old instance domain */
+ if (pmies)
+ remove_pmie_indom();
+
+ /* open the directory iterate through mmaping as we go */
+ if ((pmiedir = opendir(fullpath)) == NULL) {
+ __pmNotifyErr(LOG_ERR, "pmcd pmda cannot open %s: %s",
+ fullpath, osstrerror());
+ return 0;
+ }
+ /* NOTE: all valid files are already mmapped by pmie */
+ while ((dp = readdir(pmiedir)) != NULL) {
+ size = (npmies+1) * sizeof(pmie_t);
+ pmiepid = (pid_t)strtoul(dp->d_name, &endp, 10);
+ if (*endp != '\0') /* skips over "." and ".." here */
+ continue;
+ if (!__pmProcessExists(pmiepid))
+ continue;
+ snprintf(fullpath, sizeof(fullpath), "%s%c%s%c%s",
+ pmGetConfig("PCP_TMP_DIR"), sep, PMIE_SUBDIR, sep,
+ dp->d_name);
+ if (stat(fullpath, &statbuf) < 0) {
+ __pmNotifyErr(LOG_WARNING, "pmcd pmda cannot stat %s: %s",
+ fullpath, osstrerror());
+ continue;
+ }
+ if (statbuf.st_size != sizeof(pmiestats_t))
+ continue;
+ if ((endp = strdup(dp->d_name)) == NULL) {
+ __pmNoMem("pmie iname", strlen(dp->d_name), PM_RECOV_ERR);
+ continue;
+ }
+ if ((pmies = (pmie_t *)realloc(pmies, size)) == NULL) {
+ __pmNoMem("pmie instlist", size, PM_RECOV_ERR);
+ free(endp);
+ continue;
+ }
+ if ((fd = open(fullpath, O_RDONLY)) < 0) {
+ __pmNotifyErr(LOG_WARNING, "pmcd pmda cannot open %s: %s",
+ fullpath, osstrerror());
+ free(endp);
+ continue;
+ }
+ ptr = __pmMemoryMap(fd, statbuf.st_size, 0);
+ close(fd);
+ if (ptr == NULL) {
+ __pmNotifyErr(LOG_ERR, "pmcd pmda memmap of %s failed: %s",
+ fullpath, osstrerror());
+ free(endp);
+ continue;
+ }
+ else if (((pmiestats_t *)ptr)->version != 1) {
+ __pmNotifyErr(LOG_WARNING, "incompatible pmie version: %s",
+ fullpath);
+ __pmMemoryUnmap(ptr, statbuf.st_size);
+ free(endp);
+ continue;
+ }
+ pmies[npmies].pid = pmiepid;
+ pmies[npmies].name = endp;
+ pmies[npmies].size = statbuf.st_size;
+ pmies[npmies].mmap = ptr;
+ npmies++;
+ }
+ closedir(pmiedir);
+ }
+ }
+ else {
+ remove_pmie_indom();
+ }
+ setoserror(0);
+ return npmies;
+}
+
+static int
+pmcd_instance_reg(int inst, char *name, __pmInResult **result)
+{
+ __pmInResult *res;
+ int i;
+ char idx[3]; /* ok for NUMREG <= 99 */
+
+ res = (__pmInResult *)malloc(sizeof(__pmInResult));
+ if (res == NULL)
+ return -oserror();
+
+ if (name == NULL && inst == PM_IN_NULL)
+ res->numinst = NUMREG;
+ else
+ res->numinst = 1;
+
+ if (inst == PM_IN_NULL) {
+ if ((res->instlist = (int *)malloc(res->numinst * sizeof(res->instlist[0]))) == NULL) {
+ free(res);
+ return -oserror();
+ }
+ }
+ else
+ res->instlist = NULL;
+
+ if (name == NULL) {
+ if ((res->namelist = (char **)malloc(res->numinst * sizeof(res->namelist[0]))) == NULL) {
+ __pmFreeInResult(res);
+ return -oserror();
+ }
+ for (i = 0; i < res->numinst; i++)
+ res->namelist[0] = NULL;
+ }
+ else
+ res->namelist = NULL;
+
+ if (name == NULL && inst == PM_IN_NULL) {
+ /* return inst and name for everything */
+ for (i = 0; i < res->numinst; i++) {
+ res->instlist[i] = i;
+ snprintf(idx, sizeof(idx), "%d", i);
+ if ((res->namelist[i] = strdup(idx)) == NULL) {
+ __pmFreeInResult(res);
+ return -oserror();
+ }
+ }
+ }
+ else if (name == NULL) {
+ /* given an inst, return the name */
+ if (0 <= inst && inst < NUMREG) {
+ snprintf(idx, sizeof(idx), "%d", inst);
+ if ((res->namelist[0] = strdup(idx)) == NULL) {
+ __pmFreeInResult(res);
+ return -oserror();
+ }
+ }
+ else {
+ __pmFreeInResult(res);
+ return PM_ERR_INST;
+ }
+ }
+ else if (inst == PM_IN_NULL) {
+ /* given a name, return an inst */
+ char *endp;
+ i = (int)strtol(name, &endp, 10);
+ if (*endp == '\0' && 0 <= i && i < NUMREG)
+ res->instlist[0] = i;
+ else {
+ __pmFreeInResult(res);
+ return PM_ERR_INST;
+ }
+ }
+
+ *result = res;
+ return 0;
+}
+
+static int
+pmcd_instance_pool(int inst, char *name, __pmInResult **result)
+{
+ __pmInResult *res;
+ int i;
+
+ res = (__pmInResult *)malloc(sizeof(__pmInResult));
+ if (res == NULL)
+ return -oserror();
+
+ if (name == NULL && inst == PM_IN_NULL)
+ res->numinst = nbufsz;
+ else
+ res->numinst = 1;
+
+ if (inst == PM_IN_NULL) {
+ if ((res->instlist = (int *)malloc(res->numinst * sizeof(res->instlist[0]))) == NULL) {
+ free(res);
+ return -oserror();
+ }
+ }
+ else
+ res->instlist = NULL;
+
+ if (name == NULL) {
+ if ((res->namelist = (char **)malloc(res->numinst * sizeof(res->namelist[0]))) == NULL) {
+ __pmFreeInResult(res);
+ return -oserror();
+ }
+ for (i = 0; i < res->numinst; i++)
+ res->namelist[0] = NULL;
+ }
+ else
+ res->namelist = NULL;
+
+ if (name == NULL && inst == PM_IN_NULL) {
+ /* return inst and name for everything */
+ for (i = 0; i < nbufsz; i++) {
+ res->instlist[i] = bufinst[i].inst;
+ if ((res->namelist[i] = strdup(bufinst[i].iname)) == NULL) {
+ __pmFreeInResult(res);
+ return -oserror();
+ }
+ }
+ }
+ else if (name == NULL) {
+ /* given an inst, return the name */
+ for (i = 0; i < nbufsz; i++) {
+ if (inst == bufinst[i].inst) {
+ if ((res->namelist[0] = strdup(bufinst[i].iname)) == NULL) {
+ __pmFreeInResult(res);
+ return -oserror();
+ }
+ break;
+ }
+ }
+ if (i == nbufsz) {
+ __pmFreeInResult(res);
+ return PM_ERR_INST;
+ }
+ }
+ else if (inst == PM_IN_NULL) {
+ /* given a name, return an inst */
+ for (i = 0; i < nbufsz; i++) {
+ if (strcmp(name, bufinst[i].iname) == 0) {
+ res->instlist[0] = bufinst[i].inst;
+ break;
+ }
+ }
+ if (i == nbufsz) {
+ __pmFreeInResult(res);
+ return PM_ERR_INST;
+ }
+ }
+
+ *result = res;
+ return 0;
+}
+
+static int
+pmcd_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda)
+{
+ int sts = 0;
+ __pmInResult *res;
+ int getall = 0;
+ int getname = 0; /* initialize to pander to gcc */
+ int nports = 0; /* initialize to pander to gcc */
+ __pmLogPort *ports;
+ unsigned int pmiecount = 0; /* initialize to pander to gcc */
+ int i;
+
+ if (indom == regindom)
+ return pmcd_instance_reg(inst, name, result);
+ else if (indom == bufindom)
+ return pmcd_instance_pool(inst, name, result);
+ else if (indom == logindom || indom == pmdaindom || indom == pmieindom || indom == clientindom) {
+ res = (__pmInResult *)malloc(sizeof(__pmInResult));
+ if (res == NULL)
+ return -oserror();
+ res->instlist = NULL;
+ res->namelist = NULL;
+
+ if (indom == logindom) {
+ /* use the wildcard behaviour of __pmLogFindPort to find
+ * all pmlogger ports on localhost. Note that
+ * __pmLogFindPort will not attempt to contact pmcd if
+ * localhost is specified---this means we don't get a
+ * recursive call to pmcd which would hang!
+ */
+ if ((nports = __pmLogFindPort("localhost", PM_LOG_ALL_PIDS, &ports)) < 0) {
+ free(res);
+ return nports;
+ }
+ }
+ else if (indom == pmieindom)
+ pmiecount = refresh_pmie_indom();
+
+ if (name == NULL && inst == PM_IN_NULL) {
+ getall = 1;
+
+ if (indom == logindom)
+ res->numinst = nports;
+ else if (indom == pmdaindom)
+ res->numinst = nAgents;
+ else if (indom == pmieindom)
+ res->numinst = pmiecount;
+ else if (indom == clientindom) {
+ res->numinst = 0;
+ for (i = 0; i < nClients; i++) {
+ if (client[i].status.connected) res->numinst++;
+ }
+ }
+ }
+ else {
+ getname = name == NULL;
+ res->numinst = 1;
+ }
+
+ if (getall || !getname) {
+ if ((res->instlist = (int *)malloc(res->numinst * sizeof(int))) == NULL) {
+ sts = -oserror();
+ __pmNoMem("pmcd_instance instlist", res->numinst * sizeof(int), PM_RECOV_ERR);
+ __pmFreeInResult(res);
+ return sts;
+ }
+ }
+ if (getall || getname) {
+ if ((res->namelist = (char **)malloc(res->numinst * sizeof(char *))) == NULL) {
+ sts = -oserror();
+ __pmNoMem("pmcd_instance namelist", res->numinst * sizeof(char *), PM_RECOV_ERR);
+ free(res->instlist);
+ __pmFreeInResult(res);
+ return sts;
+ }
+ }
+ }
+ else
+ return PM_ERR_INDOM;
+
+ if (indom == logindom) {
+ res->indom = logindom;
+
+ if (getall) { /* get instance ids and names */
+ for (i = 0; i < nports; i++) {
+ res->instlist[i] = ports[i].pid;
+ res->namelist[i] = strdup(ports[i].name);
+ if (res->namelist[i] == NULL) {
+ sts = -oserror();
+ __pmNoMem("pmcd_instance pmGetInDom",
+ strlen(ports[i].name), PM_RECOV_ERR);
+ /* ensure pmFreeInResult only gets valid pointers */
+ res->numinst = i;
+ break;
+ }
+ }
+ }
+ else if (getname) { /* given id, get name */
+ for (i = 0; i < nports; i++) {
+ if (inst == ports[i].pid)
+ break;
+ }
+ if (i == nports) {
+ sts = PM_ERR_INST;
+ res->namelist[0] = NULL;
+ }
+ else {
+ res->namelist[0] = strdup(ports[i].name);
+ if (res->namelist[0] == NULL) {
+ __pmNoMem("pmcd_instance pmNameInDom",
+ strlen(ports[i].name), PM_RECOV_ERR);
+ sts = -oserror();
+ }
+ }
+ }
+ else { /* given name, get id */
+ for (i = 0; i < nports; i++) {
+ if (strcmp(name, ports[i].name) == 0)
+ break;
+ }
+ if (i == nports)
+ sts = PM_ERR_INST;
+ else
+ res->instlist[0] = ports[i].pid;
+ }
+ }
+ else if (indom == pmieindom) {
+ res->indom = pmieindom;
+
+ if (getall) { /* get instance ids and names */
+ for (i = 0; i < pmiecount; i++) {
+ res->instlist[i] = pmies[i].pid;
+ res->namelist[i] = strdup(pmies[i].name);
+ if (res->namelist[i] == NULL) {
+ sts = -oserror();
+ __pmNoMem("pmie_instance pmGetInDom",
+ strlen(pmies[i].name), PM_RECOV_ERR);
+ /* ensure pmFreeInResult only gets valid pointers */
+ res->numinst = i;
+ break;
+ }
+ }
+ }
+ else if (getname) { /* given id, get name */
+ for (i = 0; i < pmiecount; i++) {
+ if (inst == pmies[i].pid)
+ break;
+ }
+ if (i == pmiecount) {
+ sts = PM_ERR_INST;
+ res->namelist[0] = NULL;
+ }
+ else {
+ res->namelist[0] = strdup(pmies[i].name);
+ if (res->namelist[0] == NULL) {
+ sts = -oserror();
+ __pmNoMem("pmcd_instance pmNameInDom",
+ strlen(pmies[i].name), PM_RECOV_ERR);
+ }
+ }
+ }
+ else { /* given name, get id */
+ for (i = 0; i < pmiecount; i++) {
+ if (strcmp(name, pmies[i].name) == 0)
+ break;
+ }
+ if (i == pmiecount)
+ sts = PM_ERR_INST;
+ else
+ res->instlist[0] = pmies[i].pid;
+ }
+ }
+ else if (indom == pmdaindom) {
+ res->indom = pmdaindom;
+
+ if (getall) { /* get instance ids and names */
+ for (i = 0; i < nAgents; i++) {
+ res->instlist[i] = agent[i].pmDomainId;
+ res->namelist[i] = strdup(agent[i].pmDomainLabel);
+ if (res->namelist[i] == NULL) {
+ sts = -oserror();
+ __pmNoMem("pmcd_instance pmGetInDom",
+ strlen(agent[i].pmDomainLabel), PM_RECOV_ERR);
+ /* ensure pmFreeInResult only gets valid pointers */
+ res->numinst = i;
+ break;
+ }
+ }
+ }
+ else if (getname) { /* given id, get name */
+ for (i = 0; i < nAgents; i++) {
+ if (inst == agent[i].pmDomainId)
+ break;
+ }
+ if (i == nAgents) {
+ sts = PM_ERR_INST;
+ res->namelist[0] = NULL;
+ }
+ else {
+ res->namelist[0] = strdup(agent[i].pmDomainLabel);
+ if (res->namelist[0] == NULL) {
+ sts = -oserror();
+ __pmNoMem("pmcd_instance pmNameInDom",
+ strlen(agent[i].pmDomainLabel), PM_RECOV_ERR);
+ }
+ }
+ }
+ else { /* given name, get id */
+ for (i = 0; i < nAgents; i++) {
+ if (strcmp(name, agent[i].pmDomainLabel) == 0)
+ break;
+ }
+ if (i == nAgents)
+ sts = PM_ERR_INST;
+ else
+ res->instlist[0] = agent[i].pmDomainId;
+ }
+ }
+ else if (indom == clientindom) {
+ res->indom = clientindom;
+
+ if (getall) { /* get instance ids and names */
+ int k = 0;
+ for (i = 0; i < nClients; i++) {
+ char buf[11]; /* enough for 32-bit client seq number */
+ if (!client[i].status.connected)
+ continue;
+ res->instlist[k] = client[i].seq;
+ snprintf(buf, sizeof(buf), "%u", client[i].seq);
+ res->namelist[k] = strdup(buf);
+ if (res->namelist[k] == NULL) {
+ sts = -oserror();
+ __pmNoMem("pmcd_instance pmGetInDom",
+ strlen(buf), PM_RECOV_ERR);
+ /* ensure pmFreeInResult only gets valid pointers */
+ res->numinst = i;
+ break;
+ }
+ k++;
+ }
+ }
+ else if (getname) { /* given id, get name */
+ for (i = 0; i < nClients; i++) {
+ if (client[i].status.connected && inst == client[i].seq)
+ break;
+ }
+ if (i == nClients) {
+ sts = PM_ERR_INST;
+ res->namelist[0] = NULL;
+ }
+ else {
+ char buf[11]; /* enough for 32-bit client seq number */
+ snprintf(buf, sizeof(buf), "%u", (unsigned int)inst);
+ res->namelist[0] = strdup(buf);
+ if (res->namelist[0] == NULL) {
+ sts = -oserror();
+ __pmNoMem("pmcd_instance pmNameInDom",
+ strlen(buf), PM_RECOV_ERR);
+ }
+ }
+ }
+ else { /* given name, get id */
+ char buf[11]; /* enough for 32-bit client seq number */
+ for (i = 0; i < nClients; i++) {
+ if (!client[i].status.connected)
+ continue;
+ snprintf(buf, sizeof(buf), "%u", client[i].seq);
+ if (strcmp(name, buf) == 0)
+ break;
+ }
+ if (i == nClients)
+ sts = PM_ERR_INST;
+ else
+ res->instlist[0] = client[i].seq;
+ }
+ }
+
+ if (sts < 0) {
+ __pmFreeInResult(res);
+ return sts;
+ }
+
+ *result = res;
+ return 0;
+}
+
+/*
+ * numval != 1, so re-do vset[i] allocation
+ */
+static int
+vset_resize(pmResult *rp, int i, int onumval, int numval)
+{
+ int expect = numval;
+
+ if (rp->vset[i] != NULL) {
+ free(rp->vset[i]);
+ }
+
+ if (numval < 0)
+ expect = 0;
+
+ rp->vset[i] = (pmValueSet *)malloc(sizeof(pmValueSet) + (expect-1)*sizeof(pmValue));
+
+ if (rp->vset[i] == NULL) {
+ if (i) {
+ /* we're doomed ... reclaim pmValues 0, 1, ... i-1 */
+ rp->numpmid = i;
+ __pmFreeResultValues(rp);
+ }
+ return -1;
+ }
+
+ rp->vset[i]->numval = numval;
+ return 0;
+}
+
+static char *
+simabi()
+{
+#if defined(__linux__) || defined(IS_GNU)
+# if defined(__i386__)
+ return "ia32";
+# elif defined(__ia64__) || defined(__ia64)
+ return "ia64";
+# else
+ return SIM_ABI; /* SIM_ABI is defined in the linux Makefile */
+# endif /* __linux__ */
+#elif defined(IS_SOLARIS)
+ static char abi[32];
+ if (sysinfo(SI_ARCHITECTURE_NATIVE, abi, sizeof(abi)) < 0) {
+ return "unknown";
+ } else {
+ return abi;
+ }
+#elif defined(IS_FREEBSD) || defined(IS_NETBSD)
+ return "elf";
+#elif defined(IS_DARWIN)
+ return "Mach-O " SIM_ABI;
+#elif defined(IS_MINGW)
+ return "x86_64";
+#elif defined(IS_AIX)
+ return "powerpc";
+#else
+ !!! bozo : dont know which executable format pmcd should be!!!
+#endif
+}
+
+static char *
+tzinfo(void)
+{
+ /*
+ * __pmTimezone() caches its result in $TZ - pmcd is long running,
+ * however, and we *really* want to see changes in the timezone or
+ * daylight savings state via pmcd.timezone, so we clear TZ first.
+ */
+#ifdef HAVE_UNSETENV
+ unsetenv("TZ");
+#else /* MINGW */
+ putenv("TZ=");
+#endif
+ return __pmTimezone();
+}
+
+static int
+extract_service(const char *path, char *name, pid_t *pid)
+{
+ int length, sep = __pmPathSeparator();
+ char fullpath[MAXPATHLEN];
+ char buffer[64];
+ FILE *fp;
+
+ /* check basename has a ".pid" suffix */
+ if ((length = strlen(name)) < 5)
+ return 0;
+ length -= 4;
+ if (strcmp(&name[length], ".pid") != 0)
+ return 0;
+
+ /* extract PID lurking within the file */
+ snprintf(fullpath, sizeof(fullpath), "%s%c%s", path, sep, name);
+ if ((fp = fopen(fullpath, "r")) == NULL)
+ return 0;
+ sep = fscanf(fp, "%63s", buffer);
+ fclose(fp);
+ if (sep != 1)
+ return 0;
+ *pid = atoi(buffer);
+
+ /* finally setup service name to return */
+ name[length] = '\0';
+ return length;
+}
+
+char *
+services(void)
+{
+ static char servicelist[128];
+ static struct stat lastsbuf;
+ pid_t pid;
+ struct dirent *dp;
+ struct stat statbuf;
+ char *path;
+ DIR *rundir;
+ int length, offset;
+
+ path = pmGetConfig("PCP_RUN_DIR");
+ if (stat(path, &statbuf) == 0) {
+ if (stat_time_differs(&statbuf, &lastsbuf)) {
+ lastsbuf = statbuf;
+
+ /* by definition, pmcd is currently running */
+ strcpy(servicelist, PM_SERVER_SERVICE_SPEC);
+ offset = sizeof(PM_SERVER_SERVICE_SPEC) - 1;
+
+ /* iterate through directory, building up services string */
+ if ((rundir = opendir(path)) == NULL) {
+ __pmNotifyErr(LOG_ERR, "pmcd pmda cannot open %s: %s",
+ path, osstrerror());
+ return servicelist;
+ }
+ while ((dp = readdir(rundir)) != NULL) {
+ if (dp->d_name[0] == '.')
+ continue;
+ length = sizeof(PM_SERVER_SERVICE_SPEC) - 1;
+ if (strncmp(dp->d_name, PM_SERVER_SERVICE_SPEC, length) == 0)
+ continue;
+ if ((length = extract_service(path, dp->d_name, &pid)) <= 0)
+ continue;
+ if (!__pmProcessExists(pid))
+ continue;
+ if (offset + 1 + length + 1 > sizeof(servicelist))
+ continue;
+ servicelist[offset++] = ' ';
+ strcpy(&servicelist[offset], dp->d_name);
+ offset += length;
+ }
+ closedir(rundir);
+ }
+ } else {
+ strcpy(servicelist, PM_SERVER_SERVICE_SPEC);
+ }
+ return servicelist;
+}
+
+static char *
+hostnameinfo(void)
+{
+ static char host[MAXHOSTNAMELEN];
+ char *name;
+
+ (void)gethostname(host, MAXHOSTNAMELEN);
+ name = host;
+
+ return name;
+}
+
+static int
+fetch_feature(int item, pmAtomValue *avp)
+{
+ if (item < 0 || item >= PM_SERVER_FEATURES)
+ return PM_ERR_PMID;
+ avp->ul = __pmServerHasFeature((__pmServerFeature)item);
+ return 0;
+}
+
+static int
+fetch_cputime(int item, int ctx, pmAtomValue *avp)
+{
+ double usr, sys;
+ double cputime;
+
+ if (item < 0 || item > 1) {
+ return PM_ERR_PMID;
+ }
+ if (ctx < 0) {
+ /* should not happen */
+ return PM_ERR_NOTCONN;
+ }
+ __pmProcessRunTimes(&usr, &sys);
+ cputime = (usr+sys)*1000;
+ if (ctx >= num_ctx)
+ grow_ctxtab(ctx);
+ if (item == 0) { /* pmcd.cputime.total */
+ avp->ull = (__uint64_t)cputime;
+ }
+ else if (item == 1) { /* pmcd.cputime.per_pdu_in */
+ int j;
+ int pdu_in;
+ for (pdu_in = j = 0; j <= PDU_MAX; j++)
+ pdu_in += __pmPDUCntIn[j];
+ if (ctxtab[ctx].state == CTX_INACTIVE) {
+ /* first call for this context */
+ ctxtab[ctx].state = CTX_ACTIVE;
+ avp->d = cputime*1000/pdu_in;
+ }
+ else {
+ if (pdu_in > ctxtab[ctx].last_pdu_in)
+ avp->d = 1000*(cputime-ctxtab[ctx].last_cputime)/(pdu_in-ctxtab[ctx].last_pdu_in);
+ else {
+ /* should not happen, as you need another pdu to get here */
+ avp->d = 0;
+ }
+ }
+ ctxtab[ctx].last_cputime = cputime;
+ ctxtab[ctx].last_pdu_in = pdu_in;
+ }
+ return 0;
+}
+
+static void
+end_context(int ctx)
+{
+ if (ctx >= 0 && ctx < num_ctx && ctxtab[ctx].state == CTX_ACTIVE) {
+ ctxtab[ctx].state = CTX_INACTIVE;
+ }
+}
+
+static int
+pmcd_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda)
+{
+ int i; /* over pmidlist[] */
+ int j;
+ int sts, nports;
+ int need;
+ int numval;
+ int valfmt;
+ unsigned long datasize;
+ static pmResult *res = NULL;
+ static int maxnpmids = 0;
+ char *host = NULL; /* refresh max once per fetch */
+ pmiestats_t *pmie;
+ pmValueSet *vset;
+ pmDesc *dp = NULL; /* initialize to pander to gcc */
+ __pmID_int *pmidp;
+ pmAtomValue atom;
+ __pmLogPort *lpp;
+
+ if (numpmid > maxnpmids) {
+ if (res != NULL)
+ free(res);
+ /* (numpmid - 1) because there's room for one valueSet in a pmResult */
+ need = (int)sizeof(pmResult) + (numpmid - 1) * (int)sizeof(pmValueSet *);
+ if ((res = (pmResult *) malloc(need)) == NULL)
+ return -ENOMEM;
+ maxnpmids = numpmid;
+ }
+ res->timestamp.tv_sec = 0;
+ res->timestamp.tv_usec = 0;
+ res->numpmid = numpmid;
+
+ for (i = 0; i < numpmid; i++) {
+ /* Allocate a pmValueSet with room for just one value. Even for the
+ * pmlogger port metric which has an instance domain, most of the time
+ * there will only be one logger running (i.e. one instance). For the
+ * infrequent cases resize the value set later.
+ */
+ res->vset[i] = NULL;
+ if (vset_resize(res, i, 0, 1) == -1)
+ return -ENOMEM;
+ vset = res->vset[i];
+ vset->pmid = pmidlist[i];
+ vset->vlist[0].inst = PM_IN_NULL;
+
+ for (j = 0; j < ndesc; j++) {
+ if (desctab[j].pmid == pmidlist[i]) {
+ dp = &desctab[j];
+ break;
+ }
+ }
+ if (j == ndesc) {
+ /* Error, need a smaller vset */
+ if (vset_resize(res, i, 1, PM_ERR_PMID) == -1)
+ return -ENOMEM;
+ res->vset[i]->pmid = pmidlist[i];
+ continue;
+ }
+
+ valfmt = -1;
+ sts = 0;
+
+ pmidp = (__pmID_int *)&pmidlist[i];
+ switch (pmidp->cluster) {
+
+ case 0: /* global metrics */
+ switch (pmidp->item) {
+ case 0: /* control.debug */
+ atom.l = pmDebug;
+ break;
+ case 1: /* datasize */
+ __pmProcessDataSize(&datasize);
+ atom.ul = datasize;
+ break;
+ case 2: /* numagents */
+ atom.ul = 0;
+ for (j = 0; j < nAgents; j++)
+ if (agent[j].status.connected)
+ atom.ul++;
+ break;
+ case 3: /* numclients */
+ atom.ul = 0;
+ for (j = 0; j < nClients; j++)
+ if (client[j].status.connected)
+ atom.ul++;
+ break;
+ case 4: /* control.timeout */
+ atom.ul = _pmcd_timeout;
+ break;
+ case 5: /* timezone $TZ */
+ atom.cp = tzinfo();
+ break;
+ case 6: /* simabi (pmcd calling convention) */
+ atom.cp = simabi();
+ break;
+ case 7: /* version */
+ atom.cp = PCP_VERSION;
+ break;
+ case 8: /* register */
+ for (j = numval = 0; j < NUMREG; j++) {
+ if (__pmInProfile(regindom, _profile, j))
+ numval++;
+ }
+ if (numval != 1) {
+ /* need a different vset size */
+ if (vset_resize(res, i, 1, numval) == -1)
+ return -ENOMEM;
+ vset = res->vset[i];
+ vset->pmid = pmidlist[i];
+ }
+ for (j = numval = 0; j < NUMREG; j++) {
+ if (!__pmInProfile(regindom, _profile, j))
+ continue;
+ vset->vlist[numval].inst = j;
+ atom.l = reg[j];
+ sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type);
+ if (sts < 0)
+ break;
+ valfmt = sts;
+ numval++;
+ }
+ break;
+ case 9: /* traceconn */
+ atom.l = (_pmcd_trace_mask & TR_MASK_CONN) ? 1 : 0;
+ break;
+ case 10: /* tracepdu */
+ atom.l = (_pmcd_trace_mask & TR_MASK_PDU) ? 1 : 0;
+ break;
+ case 11: /* tracebufs */
+ atom.l = _pmcd_trace_nbufs;
+ break;
+ case 12: /* dumptrace ... always 0 */
+ atom.l = 0;
+ break;
+ case 13: /* dumpconn ... always 0 */
+ atom.l = 0;
+ break;
+ case 14: /* tracenobuf */
+ atom.l = (_pmcd_trace_mask & TR_MASK_NOBUF) ? 1 : 0;
+ break;
+ case 15: /* sighup ... always 0 */
+ atom.l = 0;
+ break;
+ case 16: /* services */
+ atom.cp = services();
+ break;
+ case 17: /* openfds */
+ atom.ul = (unsigned int)pmcd_hi_openfds;
+ break;
+ case 18: /* buf.alloc */
+ case 19: /* buf.free */
+ for (j = numval = 0; j < nbufsz; j++) {
+ if (__pmInProfile(bufindom, _profile, bufinst[j].inst))
+ numval++;
+ }
+ if (numval != 1) {
+ /* need a different vset size */
+ if (vset_resize(res, i, 1, numval) == -1)
+ return -ENOMEM;
+ vset = res->vset[i];
+ vset->pmid = pmidlist[i];
+ }
+ for (j = numval = 0; j < nbufsz; j++) {
+ int alloced;
+ int free;
+ int xtra_alloced;
+ int xtra_free;
+ if (!__pmInProfile(bufindom, _profile, bufinst[j].inst))
+ continue;
+ vset->vlist[numval].inst = bufinst[j].inst;
+ /* PDUBuf pool */
+ __pmCountPDUBuf(bufinst[j].inst, &alloced, &free);
+ /*
+ * the 2K buffer count also includes
+ * the 3K, 4K, ... buffers, so sub
+ * these ... which are reported as
+ * the 3K buffer count
+ */
+ __pmCountPDUBuf(bufinst[j].inst + 1024, &xtra_alloced, &xtra_free);
+ alloced -= xtra_alloced;
+ free -= xtra_free;
+ if (pmidp->item == 18)
+ atom.l = alloced;
+ else
+ atom.l = free;
+ sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type);
+ if (sts < 0)
+ break;
+ valfmt = sts;
+ numval++;
+ }
+ break;
+
+ case 20: /* build */
+ atom.cp = BUILD;
+ break;
+
+ case 21: /* hostname */
+ if (_pmcd_hostname) {
+ atom.cp = _pmcd_hostname;
+ } else {
+ if (!host)
+ host = hostnameinfo();
+ atom.cp = host;
+ }
+ break;
+ default:
+ sts = atom.l = PM_ERR_PMID;
+ break;
+ }
+ break;
+
+ case 1: /* PDUs received */
+ if (pmidp->item == _TOTAL) {
+ /* total */
+ atom.ul = 0;
+ for (j = 0; j <= PDU_MAX; j++)
+ atom.ul += __pmPDUCntIn[j];
+ }
+ else if (pmidp->item > PDU_MAX+1)
+ sts = atom.l = PM_ERR_PMID;
+ else if (pmidp->item < _TOTAL)
+ atom.ul = __pmPDUCntIn[pmidp->item];
+ else
+ atom.ul = __pmPDUCntIn[pmidp->item-1];
+ break;
+
+ case 2: /* PDUs sent */
+ if (pmidp->item == _TOTAL) {
+ /* total */
+ atom.ul = 0;
+ for (j = 0; j <= PDU_MAX; j++)
+ atom.ul += __pmPDUCntOut[j];
+ }
+ else if (pmidp->item > PDU_MAX+1)
+ sts = atom.l = PM_ERR_PMID;
+ else if (pmidp->item < _TOTAL)
+ atom.ul = __pmPDUCntOut[pmidp->item];
+ else
+ atom.ul = __pmPDUCntOut[pmidp->item-1];
+ break;
+
+ case 3: /* pmlogger control port, pmcd_host, archive and host */
+ /* find all ports. localhost => no recursive pmcd access */
+ nports = __pmLogFindPort("localhost", PM_LOG_ALL_PIDS, &lpp);
+ if (nports < 0) {
+ sts = nports;
+ break;
+ }
+ for (j = numval = 0; j < nports; j++) {
+ if (__pmInProfile(logindom, _profile, lpp[j].pid))
+ numval++;
+ }
+ if (numval != 1) {
+ /* need a different vset size */
+ if (vset_resize(res, i, 1, numval) == -1)
+ return -ENOMEM;
+ vset = res->vset[i];
+ vset->pmid = pmidlist[i];
+ }
+ for (j = numval = 0; j < nports; j++) {
+ if (!__pmInProfile(logindom, _profile, lpp[j].pid))
+ continue;
+ vset->vlist[numval].inst = lpp[j].pid;
+ switch (pmidp->item) {
+ case 0: /* pmlogger.port */
+ atom.ul = lpp[j].port;
+ break;
+ case 1: /* pmlogger.pmcd_host */
+ atom.cp = lpp[j].pmcd_host ?
+ lpp[j].pmcd_host : "";
+ break;
+ case 2: /* pmlogger.archive */
+ atom.cp = lpp[j].archive ? lpp[j].archive : "";
+ break;
+ case 3: /* pmlogger.host */
+ if (!host)
+ host = hostnameinfo();
+ atom.cp = host;
+ break;
+ default:
+ sts = atom.l = PM_ERR_PMID;
+ break;
+ }
+ if (sts >= 0)
+ sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type);
+ if (sts < 0)
+ break;
+ valfmt = sts;
+ numval++;
+ }
+ break;
+
+ case 4: /* PMDA metrics */
+ for (j = numval = 0; j < nAgents; j++) {
+ if (__pmInProfile(pmdaindom, _profile, agent[j].pmDomainId))
+ numval++;
+ }
+ if (numval != 1) {
+ /* need a different vset size */
+ if (vset_resize(res, i, 1, numval) == -1)
+ return -ENOMEM;
+ vset = res->vset[i];
+ vset->pmid = pmidlist[i];
+ }
+ for (j = numval = 0; j < nAgents; j++) {
+ if (!__pmInProfile(pmdaindom, _profile, agent[j].pmDomainId))
+ continue;
+ vset->vlist[numval].inst = agent[j].pmDomainId;
+ switch (pmidp->item) {
+ case 0: /* agent.type */
+ atom.ul = agent[j].ipcType << 1;
+ break;
+ case 1: /* agent.status */
+ if (agent[j].status.notReady)
+ atom.l = 1;
+ else if (agent[j].status.connected)
+ atom.l = 0;
+ else
+ atom.l = agent[j].reason;
+ break;
+ default:
+ sts = atom.l = PM_ERR_PMID;
+ break;
+ }
+ if (sts >= 0)
+ sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type);
+ if (sts < 0)
+ break;
+ valfmt = sts;
+ numval++;
+ }
+ if (numval > 0) {
+ pmResult sortme;
+ sortme.numpmid = 1;
+ sortme.vset[0] = vset;
+ pmSortInstances(&sortme);
+ }
+ break;
+
+
+ case 5: /* pmie metrics */
+ refresh_pmie_indom();
+ for (j = numval = 0; j < npmies; j++) {
+ if (__pmInProfile(pmieindom, _profile, pmies[j].pid))
+ numval++;
+ }
+ if (numval != 1) {
+ /* need a different vset size */
+ if (vset_resize(res, i, 1, numval) == -1)
+ return -ENOMEM;
+ vset = res->vset[i];
+ vset->pmid = pmidlist[i];
+ }
+ for (j = numval = 0; j < npmies; ++j) {
+ if (!__pmInProfile(pmieindom, _profile, pmies[j].pid))
+ continue;
+ vset->vlist[numval].inst = pmies[j].pid;
+ pmie = (pmiestats_t *)pmies[j].mmap;
+ switch (pmidp->item) {
+ case 0: /* pmie.configfile */
+ atom.cp = pmie->config;
+ break;
+ case 1: /* pmie.logfile */
+ atom.cp = pmie->logfile;
+ break;
+ case 2: /* pmie.pmcd_host */
+ atom.cp = pmie->defaultfqdn;
+ break;
+ case 3: /* pmie.numrules */
+ atom.ul = pmie->numrules;
+ break;
+ case 4: /* pmie.actions */
+ atom.ul = pmie->actions;
+ break;
+ case 5: /* pmie.eval.true */
+ atom.ul = pmie->eval_true;
+ break;
+ case 6: /* pmie.eval.false */
+ atom.ul = pmie->eval_false;
+ break;
+ case 7: /* pmie.eval.unknown */
+ atom.ul = pmie->eval_unknown;
+ break;
+ case 8: /* pmie.eval.expected */
+ atom.f = pmie->eval_expected;
+ break;
+ case 9: /* pmie.eval.actual */
+ atom.ul = pmie->eval_actual;
+ break;
+ default:
+ sts = atom.l = PM_ERR_PMID;
+ break;
+ }
+ if (sts >= 0)
+ sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type);
+ if (sts < 0)
+ break;
+ valfmt = sts;
+ numval++;
+ }
+ if (numval > 0) {
+ pmResult sortme;
+ sortme.numpmid = 1;
+ sortme.vset[0] = vset;
+ pmSortInstances(&sortme);
+ }
+ break;
+
+ case 6: /* client metrics */
+ for (j = numval = 0; j < nClients; j++) {
+ if (!client[j].status.connected)
+ continue;
+ if (__pmInProfile(clientindom, _profile, client[j].seq))
+ numval++;
+ }
+ if (numval != 1) {
+ /* need a different vset size */
+ if (vset_resize(res, i, 1, numval) == -1)
+ return -ENOMEM;
+ vset = res->vset[i];
+ vset->pmid = pmidlist[i];
+ }
+ for (j = numval = 0; j < nClients; ++j) {
+ int k;
+ char ctim[sizeof("Thu Nov 24 18:22:48 1986\n")];
+ if (!client[j].status.connected)
+ continue;
+ if (!__pmInProfile(clientindom, _profile, client[j].seq))
+ continue;
+ vset->vlist[numval].inst = client[j].seq;
+ switch (pmidp->item) {
+ case 0: /* client.whoami */
+ for (k = 0; k < nwhoamis; k++) {
+ if (whoamis[k].seq == client[j].seq) {
+ atom.cp = whoamis[k].value;
+ break;
+ }
+ }
+ if (k == nwhoamis)
+ /* no id registered, so no value */
+ atom.cp = "";
+ break;
+ case 1: /* client.start_date */
+ atom.cp = strcpy(ctim, ctime(&client[j].start));
+ /* trim trailing \n */
+ k = strlen(atom.cp);
+ atom.cp[k-1] = '\0';
+ break;
+ default:
+ sts = atom.l = PM_ERR_PMID;
+ break;
+ }
+ if (sts >= 0)
+ sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type);
+ if (sts < 0)
+ break;
+ valfmt = sts;
+ numval++;
+ }
+ if (numval > 0) {
+ pmResult sortme;
+ sortme.numpmid = 1;
+ sortme.vset[0] = vset;
+ pmSortInstances(&sortme);
+ }
+ break;
+
+ case 7: /* cputime metrics */
+ sts = fetch_cputime(pmidp->item, pmda->e_context, &atom);
+ break;
+
+ case 8: /* feature metrics */
+ sts = fetch_feature(pmidp->item, &atom);
+ break;
+ }
+
+ if (sts == 0 && valfmt == -1 && vset->numval == 1)
+ sts = valfmt = __pmStuffValue(&atom, &vset->vlist[0], dp->type);
+
+ if (sts < 0) {
+ /* failure, encode status in numval, need a different vset size */
+ if (vset_resize(res, i, vset->numval, sts) == -1)
+ return -ENOMEM;
+ }
+ else
+ vset->valfmt = valfmt;
+ }
+ *resp = res;
+
+ return 0;
+}
+
+static int
+pmcd_desc(pmID pmid, pmDesc *desc, pmdaExt *pmda)
+{
+ int i;
+
+ for (i = 0; i < ndesc; i++) {
+ if (desctab[i].pmid == pmid) {
+ *desc = desctab[i];
+ return 0;
+ }
+ }
+ return PM_ERR_PMID;
+}
+
+static int
+pmcd_store(pmResult *result, pmdaExt *pmda)
+{
+ int i;
+ pmValueSet *vsp;
+ int sts = 0;
+ __pmID_int *pmidp;
+
+ for (i = 0; i < result->numpmid; i++) {
+ vsp = result->vset[i];
+ pmidp = (__pmID_int *)&vsp->pmid;
+ if (pmidp->cluster == 0) {
+ if (pmidp->item == 0) { /* pmcd.control.debug */
+ pmDebug = vsp->vlist[0].value.lval;
+ }
+ else if (pmidp->item == 4) { /* pmcd.control.timeout */
+ int val = vsp->vlist[0].value.lval;
+ if (val < 0) {
+ sts = PM_ERR_SIGN;
+ break;
+ }
+ if (val != _pmcd_timeout) {
+ _pmcd_timeout = val;
+ }
+ }
+ else if (pmidp->item == 8) { /* pmcd.control.register */
+ int j;
+ for (j = 0; j < vsp->numval; j++) {
+ if (0 <= vsp->vlist[j].inst && vsp->vlist[j].inst < NUMREG)
+ reg[vsp->vlist[j].inst] = vsp->vlist[j].value.lval;
+ else {
+ sts = PM_ERR_INST;
+ break;
+ }
+ }
+ }
+ else if (pmidp->item == 9) { /* pmcd.control.traceconn */
+ int val = vsp->vlist[0].value.lval;
+ if (val == 0)
+ _pmcd_trace_mask &= (~TR_MASK_CONN);
+ else if (val == 1)
+ _pmcd_trace_mask |= TR_MASK_CONN;
+ else {
+ sts = PM_ERR_CONV;
+ break;
+ }
+ }
+ else if (pmidp->item == 10) { /* pmcd.control.tracepdu */
+ int val = vsp->vlist[0].value.lval;
+ if (val == 0)
+ _pmcd_trace_mask &= (~TR_MASK_PDU);
+ else if (val == 1)
+ _pmcd_trace_mask |= TR_MASK_PDU;
+ else {
+ sts = PM_ERR_CONV;
+ break;
+ }
+ }
+ else if (pmidp->item == 11) { /* pmcd.control.tracebufs */
+ int val = vsp->vlist[0].value.lval;
+ if (val < 0) {
+ sts = PM_ERR_SIGN;
+ break;
+ }
+ pmcd_init_trace(val);
+ }
+ else if (pmidp->item == 12) { /* pmcd.control.dumptrace */
+ pmcd_dump_trace(stderr);
+ }
+ else if (pmidp->item == 13) { /* pmcd.control.dumpconn */
+ time_t now;
+ time(&now);
+ fprintf(stderr, "\n->Current PMCD clients at %s", ctime(&now));
+ ShowClients(stderr);
+ }
+ else if (pmidp->item == 14) { /* pmcd.control.tracenobuf */
+ int val = vsp->vlist[0].value.lval;
+ if (val == 0)
+ _pmcd_trace_mask &= (~TR_MASK_NOBUF);
+ else if (val == 1)
+ _pmcd_trace_mask |= TR_MASK_NOBUF;
+ else {
+ sts = PM_ERR_CONV;
+ break;
+ }
+ }
+ else if (pmidp->item == 15) { /* pmcd.control.sighup */
+#ifdef HAVE_SIGHUP
+ /*
+ * send myself SIGHUP
+ */
+ __pmNotifyErr(LOG_INFO, "pmcd reset via pmcd.control.sighup");
+ raise(SIGHUP);
+#endif
+ }
+ else {
+ sts = PM_ERR_PMID;
+ break;
+ }
+ }
+ else if (pmidp->cluster == 6) {
+ if (pmidp->item == 0) { /* pmcd.client.whoami */
+ /*
+ * Expect one value for one instance (PM_IN_NULL)
+ *
+ * Use the value from the pmResult to change the value
+ * for the client[] that matches the current pmcd client.
+ */
+ char *cp = vsp->vlist[0].value.pval->vbuf;
+ int j;
+ int last_free = -1;
+
+ if (vsp->numval != 1 || vsp->vlist[0].inst != PM_IN_NULL) {
+ return PM_ERR_INST;
+ }
+ for (j = 0; j < nwhoamis; j++) {
+ if (whoamis[j].id == -1) {
+ /* slot in whoamis[] not in use */
+ last_free = j;
+ continue;
+ }
+ if (whoamis[j].id == this_client_id &&
+ whoamis[j].seq == client[this_client_id].seq) {
+ /* found the one to replace */
+ free(whoamis[j].value);
+ break;
+ }
+ if (!client[whoamis[j].id].status.connected ||
+ client[whoamis[j].id].seq != whoamis[j].seq) {
+ /* old whoamis[] entry, mark as available for reuse */
+ free(whoamis[j].value);
+ whoamis[j].id = -1;
+ last_free = j;
+ }
+ }
+ if (j == nwhoamis) {
+ if (last_free != -1) {
+ j = last_free;
+ }
+ else {
+ nwhoamis++;
+ if ((whoamis = (whoami_t *)realloc(whoamis, nwhoamis*sizeof(whoamis[0]))) == NULL) {
+ __pmNoMem("pmstore whoami", nwhoamis*sizeof(whoamis[0]), PM_RECOV_ERR);
+ nwhoamis = 0;
+ return -ENOMEM;
+ }
+ }
+ whoamis[j].id = this_client_id;
+ whoamis[j].seq = client[this_client_id].seq;
+ }
+ whoamis[j].value = strdup(cp);
+ }
+ else {
+ sts = PM_ERR_PMID;
+ break;
+ }
+ }
+ else {
+ /* not one of the metrics we are willing to change */
+ sts = PM_ERR_PMID;
+ break;
+ }
+ }
+
+ return sts;
+}
+
+void
+__PMDA_INIT_CALL
+pmcd_init(pmdaInterface *dp)
+{
+ char helppath[MAXPATHLEN];
+ int sep = __pmPathSeparator();
+
+ snprintf(helppath, sizeof(helppath), "%s%c" "pmcd" "%c" "help",
+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+ pmdaDSO(dp, PMDA_INTERFACE_5, "pmcd", helppath);
+
+ dp->version.four.profile = pmcd_profile;
+ dp->version.four.fetch = pmcd_fetch;
+ dp->version.four.desc = pmcd_desc;
+ dp->version.four.instance = pmcd_instance;
+ dp->version.four.store = pmcd_store;
+ dp->version.four.ext->e_endCallBack = end_context;
+
+ init_tables(dp->domain);
+
+ pmdaInit(dp, NULL, 0, NULL, 0);
+}