summaryrefslogtreecommitdiff
path: root/src/libpcp_pmcd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpcp_pmcd')
-rw-r--r--src/libpcp_pmcd/GNUlocaldefs.324
-rw-r--r--src/libpcp_pmcd/GNUmakefile35
-rw-r--r--src/libpcp_pmcd/src/GNUmakefile88
-rw-r--r--src/libpcp_pmcd/src/client.c61
-rw-r--r--src/libpcp_pmcd/src/data.c43
-rw-r--r--src/libpcp_pmcd/src/pmcd.stp.in304
-rw-r--r--src/libpcp_pmcd/src/probes.d4
-rw-r--r--src/libpcp_pmcd/src/trace.c289
8 files changed, 828 insertions, 0 deletions
diff --git a/src/libpcp_pmcd/GNUlocaldefs.32 b/src/libpcp_pmcd/GNUlocaldefs.32
new file mode 100644
index 0000000..38bc43e
--- /dev/null
+++ b/src/libpcp_pmcd/GNUlocaldefs.32
@@ -0,0 +1,4 @@
+LCFLAGS += -m32 -march=i386
+LLDFLAGS += -m32 -march=i386
+PCP_LIB_DIR=$(PCP_LIB32_DIR)
+LIBPCP_ABIDIR=32
diff --git a/src/libpcp_pmcd/GNUmakefile b/src/libpcp_pmcd/GNUmakefile
new file mode 100644
index 0000000..936948f
--- /dev/null
+++ b/src/libpcp_pmcd/GNUmakefile
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This library 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 Lesser General Public
+# License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+TOPDIR = ../..
+
+include $(TOPDIR)/src/include/builddefs
+
+LSRCFILES = GNUlocaldefs.32
+
+SUBDIRS = src $(PCP_ALTLIBS)
+
+default install : $(SUBDIRS)
+ $(SUBDIRS_MAKERULE)
+
+include $(BUILDRULES)
+
+default_pcp : default
+
+install_pcp : install
+
diff --git a/src/libpcp_pmcd/src/GNUmakefile b/src/libpcp_pmcd/src/GNUmakefile
new file mode 100644
index 0000000..1242269
--- /dev/null
+++ b/src/libpcp_pmcd/src/GNUmakefile
@@ -0,0 +1,88 @@
+#
+# Copyright (c) 2013 Red Hat.
+# Copyright (c) 2008 Aconex. All Rights Reserved.
+# Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This library 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 Lesser General Public
+# License for more details.
+#
+
+TOPDIR = ../../..
+include $(TOPDIR)/src/include/builddefs
+-include ./GNUlocaldefs
+
+CFILES = data.c trace.c client.c
+LSRCFILES = pmcd.stp.in probes.d
+
+LCFLAGS = -I$(TOPDIR)/src/pmcd/src -I$(TOPDIR)/src/libpcp/src -DPMCD_INTERNAL
+LLDLIBS = -lpcp
+
+ifeq "$(ENABLE_SECURE)" "true"
+LCFLAGS += $(NSSCFLAGS) $(NSPRCFLAGS)
+endif
+
+ifeq "$(ENABLE_PROBES)" "true"
+ifeq "$(TARGET_OS)" "linux"
+OBJECTS += probes.o
+endif
+LDIRT += probes.h pmcd.stp
+endif
+
+ifeq "$(TARGET_OS)" "mingw"
+LIBTARGET = libpcp_pmcd.$(DSOSUFFIX)
+LDIRT += libpcp_pmcd.a
+else
+STATICLIBTARGET = libpcp_pmcd.a
+LDIRT += libpcp_pmcd.$(DSOSUFFIX)
+endif
+
+default : $(LIBTARGET) $(STATICLIBTARGET)
+
+# Static probing for Linux, Mac OS X and Solaris.
+ifeq "$(ENABLE_PROBES)" "true"
+ifneq "$(findstring $(TARGET_OS),linux darwin freebsd)" ""
+trace.o: probes.h
+probes.h: probes.d pmcd.stp
+ $(DTRACE) -h -s $< -o $@
+probes.o: probes.d
+ $(DTRACE) -G -s $< -o $@
+endif
+ifeq "$(TARGET_OS)" "solaris"
+$(STATICLIBTARGET): rewrite
+trace.o: probes.h
+probes.h: probes.d
+ $(DTRACE) -h -s $< -o $@
+rewrite: trace.o
+ $(DTRACE) -G -s probes.d trace.o
+ touch rewrite
+LDIRT += rewrite
+endif
+endif
+
+pmcd.stp : pmcd.stp.in
+ $(SED) -e 's;@path@;'$(PCP_BINADM_DIR)/pmcd';' $< > $@
+
+include $(BUILDRULES)
+
+install : default
+ifeq "$(TARGET_OS)" "mingw"
+ $(INSTALL) -m 755 $(LIBTARGET) $(PCP_LIB_DIR)/$(LIBTARGET)
+endif
+
+ifeq "$(ENABLE_PROBES)" "true"
+ifeq "$(TARGET_OS)" "linux"
+ $(INSTALL) -m 755 -d $(PCP_SHARE_DIR)/../systemtap/tapset
+ $(INSTALL) -m 444 pmcd.stp $(PCP_SHARE_DIR)/../systemtap/tapset/pmcd.stp
+endif
+endif
+
+default_pcp : default
+
+install_pcp : install
diff --git a/src/libpcp_pmcd/src/client.c b/src/libpcp_pmcd/src/client.c
new file mode 100644
index 0000000..be941a2
--- /dev/null
+++ b/src/libpcp_pmcd/src/client.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012-2013 Red Hat.
+ * Copyright (c) 1995-2001,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 "pmcd.h"
+
+PMCD_INTERN ClientInfo *client;
+PMCD_INTERN int nClients; /* Number in array, (not all in use) */
+PMCD_INTERN int this_client_id;
+
+void
+ShowClients(FILE *f)
+{
+ int i;
+ char *sbuf;
+ char *hostName;
+
+ fprintf(f, " fd client connection from ipc ver operations denied\n");
+ fprintf(f, " == ======================================== ======= =================\n");
+ for (i = 0; i < nClients; i++) {
+ if (client[i].status.connected == 0)
+ continue;
+
+ fprintf(f, " %3d ", client[i].fd);
+
+ hostName = __pmGetNameInfo(client[i].addr);
+ if (hostName == NULL) {
+ sbuf = __pmSockAddrToString(client[i].addr);
+ fprintf(f, "%s", sbuf);
+ free(sbuf);
+ } else {
+ fprintf(f, "%-40.40s", hostName);
+ free(hostName);
+ }
+ fprintf(f, " %7d", __pmVersionIPC(client[i].fd));
+
+ if (client[i].denyOps != 0) {
+ fprintf(f, " ");
+ if (client[i].denyOps & PMCD_OP_FETCH)
+ fprintf(f, "fetch ");
+ if (client[i].denyOps & PMCD_OP_STORE)
+ fprintf(f, "store ");
+ }
+
+ fputc('\n', f);
+ }
+ fputc('\n', f);
+}
diff --git a/src/libpcp_pmcd/src/data.c b/src/libpcp_pmcd/src/data.c
new file mode 100644
index 0000000..ca257b0
--- /dev/null
+++ b/src/libpcp_pmcd/src/data.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012 Red Hat.
+ * Copyright (c) 1995-2001,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 "pmcd.h"
+
+/*
+ * Global data shared by pmcd and the pmcd PMDA DSO must reside
+ * in a DSO as well, due to linkage oddities with Windows DLLs.
+ */
+
+PMCD_INTERN int pmcd_hi_openfds = -1; /* Highest open pmcd file descriptor */
+PMCD_INTERN int _pmcd_done; /* flag from pmcd pmda */
+PMCD_INTERN int _pmcd_timeout = 5; /* Timeout for hung agents */
+
+PMCD_INTERN int nAgents; /* Number of active agents */
+PMCD_INTERN AgentInfo *agent; /* Array of agent info structs */
+
+PMCD_INTERN char *_pmcd_hostname; /* Explicitly requested hostname */
+/*
+ * File descriptors are used as an internal index with the advent
+ * of NSPR in libpcp. We (may) need to first decode the index to
+ * an internal representation and lookup the real file descriptor.
+ * Note the use of on-stack fd overwrite, avoiding local variable.
+ */
+
+void
+pmcd_openfds_sethi(int fd)
+{
+ if ((fd = __pmFD(fd)) > pmcd_hi_openfds)
+ pmcd_hi_openfds = fd;
+}
diff --git a/src/libpcp_pmcd/src/pmcd.stp.in b/src/libpcp_pmcd/src/pmcd.stp.in
new file mode 100644
index 0000000..83864b3
--- /dev/null
+++ b/src/libpcp_pmcd/src/pmcd.stp.in
@@ -0,0 +1,304 @@
+// Performance CoPilot pmcd tapset
+// Copyright (C) 2013 Red Hat Inc.
+//
+// This file is part of SystemTap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+
+global pmid_domain[2]
+global pmid_cluster[2]
+global pmid_item[2]
+global pmindom_domain[2]
+global pmindom_serial[2]
+global pdu_types[25]
+
+# from impl.h
+global PDU_ERROR = 0x7000
+global PDU_RESULT = 0x7001
+global PDU_PROFILE = 0x7002
+global PDU_FETCH = 0x7003
+global PDU_DESC_REQ = 0x7004
+global PDU_DESC = 0x7005
+global PDU_INSTANCE_REQ = 0x7006
+global PDU_INSTANCE = 0x7007
+global PDU_TEXT_REQ = 0x7008
+global PDU_TEXT = 0x7009
+global PDU_CONTROL_REQ = 0x700a
+global PDU_CREDS = 0x700c
+global PDU_PMNS_IDS = 0x700d
+global PDU_PMNS_NAMES = 0x700e
+global PDU_PMNS_CHILD = 0x700f
+global PDU_PMNS_TRAVERSE = 0x7010
+global PDU_AUTH = 0x7011
+global PDU_LOG_CONTROL = 0x8000
+global PDU_LOG_STATUS = 0x8001
+global PDU_LOG_REQUEST = 0x8002
+global DYNAMIC_PMID = 511
+global PM_INDOM_NULL = 0xffffffff
+global PM_ID_NULL = 0xffffffff
+
+# from pmcd.h
+global TR_ADD_CLIENT = 1
+global TR_DEL_CLIENT = 2
+global TR_ADD_AGENT = 3
+global TR_DEL_AGENT = 4
+global TR_EOF = 5
+global TR_XMIT_PDU = 7
+global TR_RECV_PDU = 8
+global TR_WRONG_PDU = 9
+global TR_XMIT_ERR = 10
+global TR_RECV_TIMEOUT = 11
+global TR_RECV_ERR = 12
+
+# Use the same naming scheme as trace.c::tracebuf
+# We sadly eschew stap 2.0+ feature to make $argN more symbolic:
+# @define t_type %( $arg1 %)
+# @define t_who %( $arg2 %)
+# @define t_p1 %( $arg3 %)
+# @define t_p2 %( $arg4 %)
+
+
+probe begin {
+ // [0]=bit start position [1]=bit length
+ pmid_item[0] = 0
+ pmid_item[1] = 10
+ pmid_cluster[0] = 10
+ pmid_cluster[1] = 12
+ pmid_domain[0] = 22
+ pmid_domain[1] = 9
+ pmindom_serial[0] = 0
+ pmindom_serial[1] = 22
+ pmindom_domain[0] = 22
+ pmindom_domain[1] = 9
+
+ pdu_types[PDU_ERROR] = "ERROR";
+ pdu_types[PDU_RESULT] = "RESULT";
+ pdu_types[PDU_PROFILE] = "PROFILE";
+ pdu_types[PDU_FETCH] = "FETCH";
+ pdu_types[PDU_DESC_REQ] = "DESC_REQ";
+ pdu_types[PDU_DESC] = "DESC";
+ pdu_types[PDU_INSTANCE_REQ] = "INSTANCE_REQ";
+ pdu_types[PDU_INSTANCE] = "INSTANCE";
+ pdu_types[PDU_TEXT_REQ] = "TEXT_REQ";
+ pdu_types[PDU_TEXT] = "TEXT";
+ pdu_types[PDU_CONTROL_REQ] = "CONTROL_REQ";
+ pdu_types[PDU_CREDS] = "CREDS";
+ pdu_types[PDU_PMNS_IDS] = "PMNS_IDS";
+ pdu_types[PDU_PMNS_NAMES] = "PMNS_NAMES";
+ pdu_types[PDU_PMNS_CHILD] = "PMNS_CHILD";
+ pdu_types[PDU_PMNS_TRAVERSE] = "PMNS_TRAVERSE";
+ pdu_types[PDU_LOG_CONTROL] = "LOG_CONTROL";
+ pdu_types[PDU_LOG_STATUS] = "LOG_STATUS";
+ pdu_types[PDU_LOG_REQUEST] = "LOG_REQUEST";
+ pdu_types[PDU_AUTH] = "AUTH";
+ pdu_types[-1] = "NO";
+}
+
+
+function bitextract (bits, start, length)
+{
+ // HAVE_BITFIELDS_LTOR ?
+ %( arch != "i386" && arch != "x86_64" %?
+ // HAVE_BITFIELDS_RTOL
+ start = 32 - start - length;
+ %)
+ return ((bits >> start) & ((1 << length) - 1));
+}
+
+function pdu_type:string (type:long)
+{
+ if (type in pdu_types)
+ return pdu_types[type]
+ else
+ return sprint ("TYPE-",type,"?");
+}
+
+
+/**
+ * probe pmcd.* - Indicates the type of the pmcd trace
+ *
+ * @t_desc: Description of the trace
+ * @t_type: Type of tracing that occurred
+ * @t_who: File descriptor
+ * @t_p1: Trace argument 1
+ * @t_p2: Trace argument 2
+ */
+
+
+probe pmcd.add_client = process("@path@").mark("PMCD")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_ADD_CLIENT)
+ next
+ t_desc = sprintf("New client: [%d]", $arg2)
+}
+
+
+probe pmcd.del_client = process("@path@").mark("PMCD")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_DEL_CLIENT)
+ next
+ t_desc = sprintf("End client: fd=%d err=%d", $arg2, $arg3)
+}
+
+
+probe pmcd.add_agent = process("@path@").mark("PMCD")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_ADD_AGENT)
+ next
+ t_desc = sprintf("Add PMDA: domain=%d ", $arg2)
+ if ($arg3 == -1 && $arg4 == -1)
+ t_desc = t_desc . "DSO"
+ else
+ t_desc = t_desc . sprintf("infd=%d, outfd=%d", $arg3, $arg4)
+}
+
+
+probe pmcd.del_agent = process("@path@").mark("PMCD")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_DEL_AGENT)
+ next
+
+ t_desc = sprintf("Drop PMDA: domain=%d ", $arg2)
+ if ($arg3 == -1 && $arg4 == -1)
+ t_desc = t_desc . "DSO"
+ else
+ t_desc = t_desc . sprintf("infd=%d, outfd=%d", $arg3, $arg4)
+}
+
+
+probe pmcd.eof = process("@path@").mark("PMCD")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_EOF)
+ next;
+
+ t_desc = sprintf("Premature EOF: expecting %s PDU, fd=%d", pdu_type($arg3), $arg2)
+}
+
+
+probe pmcd.wrong_pdu = process("@path@").mark("PMCD")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_WRONG_PDU)
+ next
+
+ t_desc = sprintf("Wrong PDU type: expecting %s PDU, fd=%d, ", pdu_type($arg3), $arg2)
+ if ($arg3 > 0)
+ t_desc = t_desc . sprintf("got %s PDU", pdu_type($arg4))
+ else if ($arg3 == 0)
+ t_desc = t_desc . "got EOF"
+ else
+ t_desc = t_desc . sprintf("got err=%d", $arg4)
+}
+
+
+probe pmcd.xmit_err = process("@path@").mark("PMCD")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_XMIT_ERR)
+ next
+
+ t_desc = sprintf("Send %s PDU failed: fd=%d, err=%d", pdu_type($arg3), $arg2, $arg4)
+}
+
+
+probe pmcd.recv_timeout = process("@path@").mark("PMCD")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_RECV_TIMEOUT)
+ next
+
+ t_desc = sprintf("Recv timeout: expecting %s PDU, fd=%d", pdu_type($arg3), $arg2)
+}
+
+
+probe pmcd.recv_err = process("@path@").mark("PMCD")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_RECV_ERR)
+ next;
+
+ t_desc = sprintf("Recv error: expecting %s PDU, fd=%d, err=%d", pdu_type($arg3), $arg2, $arg4)
+}
+
+
+probe pmcd.pdu.xmit = process("@path@").mark("PMCD_PDU")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_XMIT_PDU)
+ next
+
+ t_desc = sprintf("Xmit: %s PDU, fd=%d, ", pdu_type($arg3), $arg2)
+ if ($arg3 == PDU_ERROR)
+ t_desc = t_desc . sprintf(" err=%d", $arg4)
+ else if ($arg3 == PDU_RESULT)
+ t_desc = t_desc . sprintf("numpmid=%d", $arg4)
+ else if ($arg3 == PDU_TEXT || $arg3 == PDU_TEXT_REQ)
+ t_desc = t_desc . sprintf("id=%#lx", $arg4)
+ else if ($arg3 == PDU_DESC || $arg3 == PDU_DESC_REQ)
+ {
+ domain = bitextract ($arg4, pmid_domain[0],pmid_domain[1])
+ cluster = bitextract ($arg4, pmid_cluster[0],pmid_cluster[1])
+ item = bitextract ($arg4, pmid_item[0],pmid_item[1])
+ if ($arg4 == PM_ID_NULL)
+ t_desc = t_desc . sprintf("pmid=PM_ID_NULL")
+ else if (domain == DYNAMIC_PMID && item == 0)
+ t_desc = t_desc . sprintf("pmid=%d.*.*", $arg4)
+ else
+ t_desc = t_desc . sprintf("pmid=%d.%d.%d", domain, cluster, item)
+ }
+ else if ($arg3 == PDU_INSTANCE_REQ || $arg3 == PDU_INSTANCE)
+ {
+ domain = bitextract ($arg4, pmindom_domain[0],pmindom_domain[1])
+ serial = bitextract ($arg4, pmindom_serial[0],pmindom_serial[1])
+ if ($arg4 == PM_INDOM_NULL)
+ t_desc = t_desc . sprintf("pmid=PM_INDOM_NULL")
+ else
+ t_desc = t_desc . sprintf("indom=%d.%d", domain, serial)
+ }
+ else if ($arg2 == PDU_PMNS_NAMES)
+ t_desc = t_desc . sprintf("numpmid=%d", $arg4)
+ else if ($arg2 == PDU_PMNS_IDS)
+ t_desc = t_desc . sprintf("numpmid=%d", $arg4)
+ else if ($arg2 == PDU_CREDS)
+ t_desc = t_desc . sprintf("numcreds=%d", $arg4)
+}
+
+
+probe pmcd.pdu.recv = process("@path@").mark("PMCD_PDU")
+{
+ t_desc = ""
+
+ if ($arg1 != TR_RECV_PDU)
+ next;
+
+ t_desc = sprintf("Recv: %s PDU, fd=%d, pdubuf=%#x", pdu_type($arg3), $arg2, $arg4)
+}
+
+
+// Example Use
+# probe pmcd.*
+# {
+# println(t_desc)
+# }
+
+# probe pmcd.pdu.*
+# {
+# println(t_desc)
+# }
diff --git a/src/libpcp_pmcd/src/probes.d b/src/libpcp_pmcd/src/probes.d
new file mode 100644
index 0000000..97bdae8
--- /dev/null
+++ b/src/libpcp_pmcd/src/probes.d
@@ -0,0 +1,4 @@
+provider pcp_probe {
+ probe PMCD_PDU(int, int, int, int);
+ probe PMCD(int, int, int, int);
+};
diff --git a/src/libpcp_pmcd/src/trace.c b/src/libpcp_pmcd/src/trace.c
new file mode 100644
index 0000000..ed0ebaf
--- /dev/null
+++ b/src/libpcp_pmcd/src/trace.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2013 Red Hat.
+ * Copyright (c) 1995-2000,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 <time.h>
+#include "pmcd.h"
+#include "config.h"
+#if HAVE_STATIC_PROBES
+#include "probes.h"
+#else
+#define PCP_PROBE_PMCD_PDU(type,who,p1,p2)
+#define PCP_PROBE_PMCD(type,who,p1,p2)
+#endif
+
+/*
+ * Diagnostic event tracing support
+ */
+
+typedef struct {
+ time_t t_stamp; /* timestamp */
+ int t_type; /* event type */
+ int t_who; /* originator or principal identifier */
+ int t_p1; /* optional event parameters */
+ int t_p2;
+} tracebuf;
+
+static tracebuf *trace;
+static unsigned int next;
+
+/*
+ * by default, circular buffer last 20 events -- change by modify
+ * pmcd.control.tracebufs
+ * by default, tracing is disabled -- change by setting the following
+ * to 1, pmcd.control.traceconn (trace connections) and/or
+ * pmcd.control.tracepdu (trace PDUs)
+ */
+PMCD_INTERN int _pmcd_trace_nbufs = 20;
+PMCD_INTERN int _pmcd_trace_mask;
+
+void
+pmcd_init_trace(int n)
+{
+ if (trace != NULL)
+ free(trace);
+ if ((trace = (tracebuf *)malloc(n * sizeof(tracebuf))) == NULL) {
+ __pmNoMem("pmcd_init_trace", n * sizeof(tracebuf), PM_RECOV_ERR);
+ return;
+ }
+ _pmcd_trace_nbufs = n;
+ next = 0;
+}
+
+void
+pmcd_trace(int type, int who, int p1, int p2)
+{
+ int p;
+
+ switch (type) {
+ case TR_XMIT_PDU:
+ case TR_RECV_PDU:
+ PCP_PROBE_PMCD_PDU(type, who, p1, p2);
+ if ((_pmcd_trace_mask & TR_MASK_PDU) == 0)
+ return;
+ break;
+ default:
+ PCP_PROBE_PMCD(type, who, p1, p2);
+ if ((_pmcd_trace_mask & TR_MASK_CONN) == 0)
+ return;
+ break;
+ }
+
+ if (trace == NULL) {
+ pmcd_init_trace(_pmcd_trace_nbufs);
+ if (trace == NULL)
+ return;
+ }
+
+ p = (next++) % _pmcd_trace_nbufs;
+
+ time(&trace[p].t_stamp);
+ trace[p].t_type = type;
+ trace[p].t_who = who;
+ trace[p].t_p1 = p1;
+ trace[p].t_p2 = p2;
+
+ if (_pmcd_trace_mask & TR_MASK_NOBUF)
+ /* unbuffered, dump it now */
+ pmcd_dump_trace(stderr);
+}
+
+void
+pmcd_dump_trace(FILE *f)
+{
+ int i;
+ int p;
+ struct tm last = { 0, 0 };
+ struct tm *this;
+ char strbuf[20];
+
+ if ((_pmcd_trace_mask & TR_MASK_NOBUF) == 0)
+ fprintf(f, "\n->PMCD event trace: ");
+ if (trace != NULL && next != 0) {
+ if (next < _pmcd_trace_nbufs)
+ i = 0;
+ else
+ i = next - _pmcd_trace_nbufs;
+ if ((_pmcd_trace_mask & TR_MASK_NOBUF) == 0) {
+ fprintf(f, "starting at %s", ctime(&trace[i % _pmcd_trace_nbufs].t_stamp));
+ last.tm_hour = -1;
+ }
+ else
+ last.tm_hour = -2;
+
+ for ( ; i < next; i++) {
+ fprintf(f, "->");
+ p = i % _pmcd_trace_nbufs;
+ this = localtime(&trace[p].t_stamp);
+ if (this->tm_hour != last.tm_hour ||
+ this->tm_min != last.tm_min ||
+ this->tm_sec != last.tm_sec) {
+ if (last.tm_hour == -1)
+ fprintf(f, " ");
+ else
+ fprintf(f, "%02d:%02d:%02d ", this->tm_hour, this->tm_min, this->tm_sec);
+ last = *this; /* struct assignment */
+ }
+ else
+ fprintf(f, " ");
+
+ switch (trace[p].t_type) {
+
+ case TR_ADD_CLIENT:
+ {
+ ClientInfo *cip;
+
+ fprintf(f, "New client: [%d] ", trace[p].t_who);
+ cip = GetClient(trace[p].t_who);
+ if (cip == NULL) {
+ fprintf(f, "-- unknown?\n");
+ }
+ else {
+ __pmSockAddr *saddr = (__pmSockAddr *)cip->addr;
+ char *addrbuf;
+
+ addrbuf = __pmSockAddrToString(saddr);
+ if (addrbuf == NULL)
+ fprintf(f, "invalid socket address");
+ else {
+ fprintf(f, "addr=%s", addrbuf);
+ free(addrbuf);
+ }
+ fprintf(f, ", fd=%d, seq=%u\n", cip->fd, cip->seq);
+ }
+ }
+ break;
+
+ case TR_DEL_CLIENT:
+ fprintf(f, "End client: fd=%d", trace[p].t_who);
+ if (trace[p].t_p1 != 0)
+ fprintf(f, ", err=%d: %s", trace[p].t_p1, pmErrStr(trace[p].t_p1));
+ fputc('\n', f);
+ break;
+
+ case TR_ADD_AGENT:
+ fprintf(f, "Add PMDA: domain=%d, ", trace[p].t_who);
+ if (trace[p].t_p1 == -1 && trace[p].t_p2 == -1)
+ fprintf(f, "DSO\n");
+ else
+ fprintf(f, "infd=%d, outfd=%d\n", trace[p].t_p1, trace[p].t_p2);
+ break;
+
+ case TR_DEL_AGENT:
+ fprintf(f, "Drop PMDA: domain=%d, ", trace[p].t_who);
+ if (trace[p].t_p1 == -1 && trace[p].t_p2 == -1)
+ fprintf(f, "DSO\n");
+ else
+ fprintf(f, "infd=%d, outfd=%d\n", trace[p].t_p1, trace[p].t_p2);
+ break;
+
+ case TR_EOF:
+ fprintf(f, "Premature EOF: expecting %s PDU, fd=%d\n",
+ trace[p].t_p1 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)),
+ trace[p].t_who);
+ break;
+
+ case TR_WRONG_PDU:
+ if (trace[p].t_p2 > 0) {
+ fprintf(f, "Wrong PDU type: expecting %s PDU, fd=%d, got %s PDU\n",
+ trace[p].t_p1 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)),
+ trace[p].t_who,
+ trace[p].t_p2 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p2, strbuf, sizeof(strbuf)));
+ }
+ else if (trace[p].t_p2 == 0) {
+ fprintf(f, "Wrong PDU type: expecting %s PDU, fd=%d, got EOF\n",
+ trace[p].t_p1 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)),
+ trace[p].t_who);
+ }
+ else {
+ fprintf(f, "Wrong PDU type: expecting %s PDU, fd=%d, got err=%d: %s\n",
+ trace[p].t_p1 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)),
+ trace[p].t_who,
+ trace[p].t_p2, pmErrStr(trace[p].t_p2));
+
+ }
+ break;
+
+ case TR_XMIT_ERR:
+ fprintf(f, "Send %s PDU failed: fd=%d, err=%d: %s\n",
+ __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who,
+ trace[p].t_p2, pmErrStr(trace[p].t_p2));
+ break;
+
+ case TR_RECV_TIMEOUT:
+ fprintf(f, "Recv timeout: expecting %s PDU, fd=%d\n",
+ __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who);
+ break;
+
+ case TR_RECV_ERR:
+ fprintf(f, "Recv error: expecting %s PDU, fd=%d, err=%d: %s\n",
+ __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who,
+ trace[p].t_p2, pmErrStr(trace[p].t_p2));
+ break;
+
+ case TR_XMIT_PDU:
+ fprintf(f, "Xmit: %s PDU, fd=%d",
+ __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who);
+ if (trace[p].t_p1 == PDU_ERROR)
+ fprintf(f, ", err=%d: %s",
+ trace[p].t_p2, pmErrStr(trace[p].t_p2));
+ else if (trace[p].t_p1 == PDU_RESULT)
+ fprintf(f, ", numpmid=%d", trace[p].t_p2);
+ else if (trace[p].t_p1 == PDU_TEXT_REQ ||
+ trace[p].t_p1 == PDU_TEXT)
+ fprintf(f, ", id=0x%x", trace[p].t_p2);
+ else if (trace[p].t_p1 == PDU_DESC_REQ ||
+ trace[p].t_p1 == PDU_DESC)
+ fprintf(f, ", pmid=%s", pmIDStr_r((pmID)trace[p].t_p2, strbuf, sizeof(strbuf)));
+ else if (trace[p].t_p1 == PDU_INSTANCE_REQ ||
+ trace[p].t_p1 == PDU_INSTANCE)
+ fprintf(f, ", indom=%s", pmInDomStr_r((pmInDom)trace[p].t_p2, strbuf, sizeof(strbuf)));
+ else if (trace[p].t_p1 == PDU_PMNS_NAMES)
+ fprintf(f, ", numpmid=%d", trace[p].t_p2);
+ else if (trace[p].t_p1 == PDU_PMNS_IDS)
+ fprintf(f, ", numpmid=%d", trace[p].t_p2);
+ else if (trace[p].t_p1 == PDU_CREDS)
+ fprintf(f, ", numcreds=%d", trace[p].t_p2);
+ fputc('\n', f);
+ break;
+
+ case TR_RECV_PDU:
+ fprintf(f, "Recv: %s PDU, fd=%d, pdubuf=0x",
+ __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who);
+ /* This will only work if sizeof (int) == sizeof (ptr).
+ * On MIPS int is always 32 bits regardless the ABI,
+ * and on Linux we're checking in configure if an int is
+ * anything else but 32 bits, so if pointer is not
+ * 32 bit, then .... */
+#ifndef HAVE_32BIT_PTR
+ fprintf(f, "...");
+#endif
+ fprintf(f, "%x\n", trace[p].t_p2);
+ break;
+
+ default:
+ fprintf(f, "Type=%d who=%d p1=%d p2=%d\n",
+ trace[p].t_type, trace[p].t_who, trace[p].t_p1,
+ trace[p].t_p2);
+ break;
+ }
+ }
+ }
+ else
+ fprintf(f, "<empty>\n");
+
+ if ((_pmcd_trace_mask & TR_MASK_NOBUF) == 0)
+ fputc('\n', f);
+ next = 0; /* empty the circular buffer */
+}