summaryrefslogtreecommitdiff
path: root/qa/pmlogconv
diff options
context:
space:
mode:
Diffstat (limited to 'qa/pmlogconv')
-rwxr-xr-xqa/pmlogconv/GNUmakefile44
-rw-r--r--qa/pmlogconv/libpcp.c489
-rw-r--r--qa/pmlogconv/logio.c261
-rw-r--r--qa/pmlogconv/pmlogconv.c354
4 files changed, 1148 insertions, 0 deletions
diff --git a/qa/pmlogconv/GNUmakefile b/qa/pmlogconv/GNUmakefile
new file mode 100755
index 0000000..dd6d225
--- /dev/null
+++ b/qa/pmlogconv/GNUmakefile
@@ -0,0 +1,44 @@
+#!gmake
+#
+# Copyright (c) 1997-2002 Silicon Graphics, Inc. All Rights Reserved.
+#
+
+ifdef PCP_CONF
+include $(PCP_CONF)
+else
+include $(PCP_DIR)/etc/pcp.conf
+endif
+PATH = $(shell . $(PCP_DIR)/etc/pcp.env; echo $$PATH)
+include $(PCP_INC_DIR)/builddefs
+
+# remove -Lpath and -Ipath options from builddefs CFLAGS value
+#
+PCP_LIBS =
+TMP := $(CFLAGS:-I%=)
+ifdef PCP_DIR
+# put -Ipath and -Lpath back but use paths for run-time environment
+#
+CFLAGS = $(TMP) -I$(PCP_INC_DIR)/..
+LDFLAGS = -L$(PCP_LIB_DIR)
+else
+CFLAGS = $(TMP)
+endif
+
+CFILES = pmlogconv.c logio.c libpcp.c
+LLDLIBS = -lpcp
+TARGET = pmlogconv
+
+LDIRT = $(TARGET)
+
+default: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+
+include $(BUILDRULES)
+
+install: default
+ $(INSTALL) -m 755 $(TARGET) $(PCP_BIN_DIR)/$(TARGET)
+
+pmlogconv.o: pmlogconv.c
+logio.o: logio.c
+libpcp.o: libpcp.c
diff --git a/qa/pmlogconv/libpcp.c b/qa/pmlogconv/libpcp.c
new file mode 100644
index 0000000..44ebc59
--- /dev/null
+++ b/qa/pmlogconv/libpcp.c
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 1995-2002,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.
+ */
+
+#include "pcp/pmapi.h"
+#include "pcp/impl.h"
+
+#define PM_LOG_VERS01 1
+
+/*
+ * Routines in this file are lifted from libpcp to allow obsolete
+ * functionality to be restored to read V1 archives ...
+ */
+
+/*
+ * logutil.c
+ */
+
+int
+__pmLogChkLabel(__pmLogCtl *lcp, FILE *f, __pmLogLabel *lp, int vol)
+{
+ int len;
+ int version = UNKNOWN_VERSION;
+ int xpectlen = sizeof(__pmLogLabel) + 2 * sizeof(len);
+ int n;
+
+ if (vol >= 0 && vol < lcp->l_numseen && lcp->l_seen[vol]) {
+ /* FastPath, cached result of previous check for this volume */
+ fseek(f, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET);
+ return 0;
+ }
+
+ if (vol >= 0 && vol >= lcp->l_numseen) {
+ lcp->l_seen = (int *)realloc(lcp->l_seen, (vol+1)*(int)sizeof(lcp->l_seen[0]));
+ if (lcp->l_seen == NULL)
+ lcp->l_numseen = 0;
+ else {
+ int i;
+ for (i = lcp->l_numseen; i < vol; i++)
+ lcp->l_seen[i] = 0;
+ lcp->l_numseen = vol+1;
+ }
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, "__pmLogChkLabel: fd=%d vol=%d", fileno(f), vol);
+#endif
+
+ fseek(f, (long)0, SEEK_SET);
+ n = (int)fread(&len, 1, sizeof(len), f);
+ len = ntohl(len);
+ if (n != sizeof(len) || len != xpectlen) {
+ if (feof(f)) {
+ clearerr(f);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, " file is empty\n");
+#endif
+ return PM_ERR_NODATA;
+ }
+ else {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, " header read -> %d (expect %d) or bad header len=%d (expected %d)\n",
+ n, (int)sizeof(len), len, xpectlen);
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ return -errno;
+ }
+ else
+ return PM_ERR_LABEL;
+ }
+ }
+
+ if ((n = (int)fread(lp, 1, sizeof(__pmLogLabel), f)) != sizeof(__pmLogLabel)) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, " bad label len=%d: expected %d\n",
+ n, (int)sizeof(__pmLogLabel));
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ return -errno;
+ }
+ else
+ return PM_ERR_LABEL;
+ }
+ else {
+ /* swab internal log label */
+ lp->ill_magic = ntohl(lp->ill_magic);
+ lp->ill_pid = ntohl(lp->ill_pid);
+ lp->ill_start.tv_sec = ntohl(lp->ill_start.tv_sec);
+ lp->ill_start.tv_usec = ntohl(lp->ill_start.tv_usec);
+ lp->ill_vol = ntohl(lp->ill_vol);
+ }
+
+ n = (int)fread(&len, 1, sizeof(len), f);
+ len = ntohl(len);
+ if (n != sizeof(len) || len != xpectlen) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, " trailer read -> %d (expect %d) or bad trailer len=%d (expected %d)\n",
+ n, (int)sizeof(len), len, xpectlen);
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ return -errno;
+ }
+ else
+ return PM_ERR_LABEL;
+ }
+
+ version = lp->ill_magic & 0xff;
+ if ((lp->ill_magic & 0xffffff00) != PM_LOG_MAGIC ||
+ (version != PM_LOG_VERS01 && version != PM_LOG_VERS02) ||
+ lp->ill_vol != vol) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, " version %d not supported\n", version);
+#endif
+ return PM_ERR_LABEL;
+ }
+ else {
+ if (__pmSetVersionIPC(fileno(f), version) < 0)
+ return -errno;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, " [magic=%8x version=%d vol=%d pid=%d host=%s]\n",
+ lp->ill_magic, version, lp->ill_vol, (int)lp->ill_pid, lp->ill_hostname);
+#endif
+ }
+
+ if (vol >= 0 && vol < lcp->l_numseen)
+ lcp->l_seen[vol] = 1;
+
+ return version;
+}
+
+/*
+ * logmeta.c
+ */
+
+static char *
+StrTimeval(__pmTimeval *tp)
+{
+ if (tp == NULL) {
+ static char *null_timeval = "<null timeval>";
+ return null_timeval;
+ }
+ else {
+ static char sbuf[13];
+ static struct tm *tmp;
+ time_t t = tp->tv_sec;
+ tmp = localtime(&t);
+ sprintf(sbuf, "%02d:%02d:%02d.%03d", /* safe */
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec, tp->tv_usec/1000);
+ return sbuf;
+ }
+}
+
+static int
+addindom(__pmLogCtl *lcp, pmInDom indom, const __pmTimeval *tp, int numinst,
+ int *instlist, char **namelist, int *indom_buf, int allinbuf)
+{
+ __pmLogInDom *idp;
+ __pmHashNode *hp;
+ int sts;
+
+ if ((idp = (__pmLogInDom *)malloc(sizeof(__pmLogInDom))) == NULL)
+ return -errno;
+ idp->stamp = *tp; /* struct assignment */
+ idp->numinst = numinst;
+ idp->instlist = instlist;
+ idp->namelist = namelist;
+ idp->buf = indom_buf;
+ idp->allinbuf = allinbuf;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA)
+ fprintf(stderr, "addindom( ..., %s, %s, numinst=%d)\n",
+ pmInDomStr(indom), StrTimeval((__pmTimeval *)tp), numinst);
+#endif
+
+
+ if ((hp = __pmHashSearch((unsigned int)indom, &lcp->l_hashindom)) == NULL) {
+ idp->next = NULL;
+ sts = __pmHashAdd((unsigned int)indom, (void *)idp, &lcp->l_hashindom);
+ }
+ else {
+ idp->next = (__pmLogInDom *)hp->data;
+ hp->data = (void *)idp;
+ sts = 0;
+ }
+ return sts;
+}
+
+/*
+ * load _all_ of the hashed pmDesc and __pmLogInDom structures from the metadata
+ * log file -- used at the initialization (NewContext) of an archive
+ * If version 2 then
+ * load all the names from the meta data and create l_pmns.
+ */
+int
+__pmLogLoadMeta(__pmLogCtl *lcp)
+{
+ int rlen;
+ int check;
+ pmDesc *dp;
+ int sts = 0;
+ __pmLogHdr h;
+ FILE *f = lcp->l_mdfp;
+ int version2 = ((lcp->l_label.ill_magic & 0xff) == PM_LOG_VERS02);
+ int numpmid = 0;
+ int n;
+
+ if (version2) {
+ if ((sts = __pmNewPMNS(&(lcp->l_pmns))) < 0) {
+ goto end;
+ }
+ }
+
+ fseek(f, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET);
+ for ( ; ; ) {
+ n = (int)fread(&h, 1, sizeof(__pmLogHdr), f);
+
+ /* swab hdr */
+ h.len = ntohl(h.len);
+ h.type = ntohl(h.type);
+
+ if (n != sizeof(__pmLogHdr) || h.len <= 0) {
+ if (feof(f)) {
+ clearerr(f);
+ sts = 0;
+ goto end;
+ }
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA) {
+ fprintf(stderr, "__pmLogLoadMeta: header read -> %d: expected: %d\n",
+ n, (int)sizeof(__pmLogHdr));
+ }
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ sts = -errno;
+ }
+ else
+ sts = PM_ERR_LOGREC;
+ goto end;
+ }
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA) {
+ fprintf(stderr, "__pmLogLoadMeta: record len=%d, type=%d @ offset=%d\n",
+ h.len, h.type, (int)(ftell(f) - sizeof(__pmLogHdr)));
+ }
+#endif
+ rlen = h.len - (int)sizeof(__pmLogHdr) - (int)sizeof(int);
+ if (h.type == TYPE_DESC) {
+ numpmid++;
+ if ((dp = (pmDesc *)malloc(sizeof(pmDesc))) == NULL) {
+ sts = -errno;
+ goto end;
+ }
+ if ((n = (int)fread(dp, 1, sizeof(pmDesc), f)) != sizeof(pmDesc)) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA) {
+ fprintf(stderr, "__pmLogLoadMeta: pmDesc read -> %d: expected: %d\n",
+ n, (int)sizeof(pmDesc));
+ }
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ sts = -errno;
+ }
+ else
+ sts = PM_ERR_LOGREC;
+ goto end;
+ }
+ else {
+ /* swab desc */
+ dp->type = ntohl(dp->type);
+ dp->sem = ntohl(dp->sem);
+ dp->indom = __ntohpmInDom(dp->indom);
+ dp->units = __ntohpmUnits(dp->units);
+ dp->pmid = __ntohpmID(dp->pmid);
+ }
+
+ if ((sts = __pmHashAdd((int)dp->pmid, (void *)dp, &lcp->l_hashpmid)) < 0)
+ goto end;
+
+ if (version2) {
+ char name[MAXPATHLEN];
+ int numnames;
+ int i;
+ int len;
+
+ /* read in the names & store in PMNS tree ... */
+ if ((n = (int)fread(&numnames, 1, sizeof(numnames), f)) !=
+ sizeof(numnames)) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA) {
+ fprintf(stderr, "__pmLogLoadMeta: numnames read -> %d: expected: %d\n",
+ n, (int)sizeof(numnames));
+ }
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ sts = -errno;
+ }
+ else
+ sts = PM_ERR_LOGREC;
+ goto end;
+ }
+ else {
+ /* swab numnames */
+ numnames = ntohl(numnames);
+ }
+
+ for (i = 0; i < numnames; i++) {
+ if ((n = (int)fread(&len, 1, sizeof(len), f)) !=
+ sizeof(len)) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA) {
+ fprintf(stderr, "__pmLogLoadMeta: len name[%d] read -> %d: expected: %d\n",
+ i, n, (int)sizeof(len));
+ }
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ sts = -errno;
+ }
+ else
+ sts = PM_ERR_LOGREC;
+ goto end;
+ }
+ else {
+ /* swab len */
+ len = ntohl(len);
+ }
+
+ if ((n = (int)fread(name, 1, len, f)) != len) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA) {
+ fprintf(stderr, "__pmLogLoadMeta: name[%d] read -> %d: expected: %d\n",
+ i, n, len);
+ }
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ sts = -errno;
+ }
+ else
+ sts = PM_ERR_LOGREC;
+ goto end;
+ }
+ name[len] = '\0';
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA) {
+ fprintf(stderr, "__pmLogLoadMeta: PMID: %s name: %s\n",
+ pmIDStr(dp->pmid), name);
+ }
+#endif
+
+ if ((sts = __pmAddPMNSNode(lcp->l_pmns, dp->pmid, name)) < 0) {
+ /*
+ * If we see a duplicate PMID, its a recoverable error.
+ * We wont be able to see all of the data in the log, but
+ * its better to provide access to some rather than none,
+ * esp. when only one or two metric IDs may be corrupted
+ * in this way (which we may not be interested in anyway).
+ */
+ if (sts != PM_ERR_PMID)
+ goto end;
+ sts = 0;
+ }
+ }/*for*/
+ }/*version2*/
+ }
+ else if (h.type == TYPE_INDOM) {
+ int *tbuf;
+ pmInDom indom;
+ __pmTimeval *when;
+ int numinst;
+ int *instlist;
+ char **namelist;
+ char *namebase;
+ int *stridx;
+ int i;
+ int k;
+ int allinbuf;
+
+ if ((tbuf = (int *)malloc(rlen)) == NULL) {
+ sts = -errno;
+ goto end;
+ }
+ if ((n = (int)fread(tbuf, 1, rlen, f)) != rlen) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA) {
+ fprintf(stderr, "__pmLogLoadMeta: indom read -> %d: expected: %d\n",
+ n, rlen);
+ }
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ sts = -errno;
+ }
+ else
+ sts = PM_ERR_LOGREC;
+ goto end;
+ }
+
+ k = 0;
+ when = (__pmTimeval *)&tbuf[k];
+ when->tv_sec = ntohl(when->tv_sec);
+ when->tv_usec = ntohl(when->tv_usec);
+ k += sizeof(*when)/sizeof(int);
+ indom = __ntohpmInDom((unsigned int)tbuf[k++]);
+ numinst = ntohl(tbuf[k++]);
+ if (numinst > 0) {
+ instlist = &tbuf[k];
+ k += numinst;
+ stridx = &tbuf[k];
+#if defined(HAVE_32BIT_PTR)
+ namelist = (char **)stridx;
+ allinbuf = 1; /* allocation is all in tbuf */
+#else
+ allinbuf = 0; /* allocation for namelist + tbuf */
+ /* need to allocate to hold the pointers */
+ namelist = (char **)malloc(numinst*sizeof(char*));
+ if (namelist == NULL) {
+ sts = -errno;
+ goto end;
+ }
+#endif
+ k += numinst;
+ namebase = (char *)&tbuf[k];
+ for (i = 0; i < numinst; i++) {
+ instlist[i] = ntohl(instlist[i]);
+ namelist[i] = &namebase[ntohl(stridx[i])];
+ }
+ }
+ else {
+ /* no instances, or an error */
+ instlist = NULL;
+ namelist = NULL;
+ }
+ if ((sts = addindom(lcp, indom, when, numinst, instlist, namelist, tbuf, allinbuf)) < 0)
+ goto end;
+ }
+ else
+ fseek(f, (long)rlen, SEEK_CUR);
+ n = (int)fread(&check, 1, sizeof(check), f);
+ check = ntohl(check);
+ if (n != sizeof(check) || h.len != check) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOGMETA) {
+ fprintf(stderr, "__pmLogLoadMeta: trailer read -> %d or len=%d: expected %d @ offset=%d\n",
+ n, check, h.len, (int)(ftell(f) - sizeof(check)));
+ }
+#endif
+ if (ferror(f)) {
+ clearerr(f);
+ sts = -errno;
+ }
+ else
+ sts = PM_ERR_LOGREC;
+ goto end;
+ }
+ }/*for*/
+end:
+
+ fseek(f, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET);
+
+ if (version2 && sts == 0) {
+ __pmFixPMNSHashTab(lcp->l_pmns, numpmid, 1);
+ }
+ return sts;
+}
diff --git a/qa/pmlogconv/logio.c b/qa/pmlogconv/logio.c
new file mode 100644
index 0000000..655d21b
--- /dev/null
+++ b/qa/pmlogconv/logio.c
@@ -0,0 +1,261 @@
+/*
+ * utils for pmlogconv
+ *
+ * Copyright (c) 1997-2002 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* pinched from pmlogextract and libpcp */
+
+#include "pcp/pmapi.h"
+#include "pcp/impl.h"
+
+/*
+ * raw read of next log record - largely stolen from __pmLogRead in libpcp
+ */
+int
+_pmLogGet(__pmLogCtl *lcp, int vol, __pmPDU **pb)
+{
+ int head;
+ int tail;
+ int sts;
+ long offset;
+ char *p;
+ __pmPDU *lpb;
+ FILE *f;
+
+ if (vol == PM_LOG_VOL_META)
+ f = lcp->l_mdfp;
+ else
+ f = lcp->l_mfp;
+
+ offset = ftell(f);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG) {
+ fprintf(stderr, "_pmLogGet: fd=%d vol=%d posn=%ld ",
+ fileno(f), vol, offset);
+ }
+#endif
+
+again:
+ sts = (int)fread(&head, 1, sizeof(head), f);
+ if (sts != sizeof(head)) {
+ if (sts == 0) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, "AFTER end\n");
+#endif
+ fseek(f, offset, SEEK_SET);
+ if (vol != PM_LOG_VOL_META) {
+ if (lcp->l_curvol < lcp->l_maxvol) {
+ if (__pmLogChangeVol(lcp, lcp->l_curvol+1) == 0) {
+ f = lcp->l_mfp;
+ goto again;
+ }
+ }
+ }
+ return PM_ERR_EOL;
+ }
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, "Error: hdr fread=%d %s\n", sts, strerror(errno));
+#endif
+ if (sts > 0)
+ return PM_ERR_LOGREC;
+ else
+ return -errno;
+ }
+
+ if ((lpb = (__pmPDU *)malloc(ntohl(head))) == NULL) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, "Error: __pmFindPDUBuf(%d) %s\n",
+ (int)ntohl(head), strerror(errno));
+#endif
+ fseek(f, offset, SEEK_SET);
+ return -errno;
+ }
+
+ lpb[0] = head;
+ if ((sts = (int)fread(&lpb[1], 1, ntohl(head) - sizeof(head), f)) != ntohl(head) - sizeof(head)) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, "Error: data fread=%d %s\n", sts, strerror(errno));
+#endif
+ if (sts == 0) {
+ fseek(f, offset, SEEK_SET);
+ return PM_ERR_EOL;
+ }
+ else if (sts > 0)
+ return PM_ERR_LOGREC;
+ else
+ return -errno;
+ }
+
+
+ p = (char *)lpb;
+ memcpy(&tail, &p[ntohl(head) - sizeof(head)], sizeof(head));
+ if (head != tail) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, "Error: head-tail mismatch (%d-%d)\n",
+ (int)ntohl(head), (int)ntohl(tail));
+#endif
+ return PM_ERR_LOGREC;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG) {
+ if (vol != PM_LOG_VOL_META || ntohl(lpb[1]) == TYPE_INDOM) {
+ fprintf(stderr, "@");
+ if (sts >= 0) {
+ struct timeval stamp;
+ __pmTimeval *tvp = (__pmTimeval *)&lpb[vol == PM_LOG_VOL_META ? 2 : 1];
+ stamp.tv_sec = ntohl(tvp->tv_sec);
+ stamp.tv_usec = ntohl(tvp->tv_usec);
+ __pmPrintStamp(stderr, &stamp);
+ }
+ else
+ fprintf(stderr, "unknown time");
+ }
+ fprintf(stderr, " len=%d (incl head+tail)\n", (int)ntohl(head));
+ }
+#endif
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_PDU) {
+ int i, j;
+ struct timeval stamp;
+ __pmTimeval *tvp = (__pmTimeval *)&lpb[vol == PM_LOG_VOL_META ? 2 : 1];
+ fprintf(stderr, "_pmLogGet");
+ if (vol != PM_LOG_VOL_META || ntohl(lpb[1]) == TYPE_INDOM) {
+ fprintf(stderr, " timestamp=");
+ stamp.tv_sec = ntohl(tvp->tv_sec);
+ stamp.tv_usec = ntohl(tvp->tv_usec);
+ __pmPrintStamp(stderr, &stamp);
+ }
+ fprintf(stderr, " " PRINTF_P_PFX "%p ... " PRINTF_P_PFX "%p", lpb, &lpb[ntohl(head)/sizeof(__pmPDU) - 1]);
+ fputc('\n', stderr);
+ fprintf(stderr, "%03d: ", 0);
+ for (j = 0, i = 0; j < ntohl(head)/sizeof(__pmPDU); j++) {
+ if (i == 8) {
+ fprintf(stderr, "\n%03d: ", j);
+ i = 0;
+ }
+ fprintf(stderr, "0x%x ", lpb[j]);
+ i++;
+ }
+ fputc('\n', stderr);
+ }
+#endif
+
+ *pb = lpb;
+ return 0;
+}
+
+int
+_pmLogPut(FILE *f, __pmPDU *pb)
+{
+ int rlen = ntohl(pb[0]);
+ int sts;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG) {
+ fprintf(stderr, "_pmLogPut: fd=%d rlen=%d\n",
+ fileno(f), rlen);
+ }
+#endif
+
+ if ((sts = (int)fwrite(pb, 1, rlen, f)) != rlen) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LOG)
+ fprintf(stderr, "_pmLogPut: fwrite=%d %s\n", sts, strerror(errno));
+#endif
+ return -errno;
+ }
+ return 0;
+}
+
+/*
+ * like __pmDecodeDesc but pmDesc in metadata not PDU
+ */
+typedef struct {
+ __pmLogHdr hdr;
+ pmDesc desc;
+} desc_t;
+
+void
+_pmUnpackDesc(__pmPDU *pdubuf, pmDesc *desc)
+{
+ desc_t *pp;
+
+ pp = (desc_t *)pdubuf;
+ desc->type = ntohl(pp->desc.type);
+ desc->sem = ntohl(pp->desc.sem);
+ desc->indom = __ntohpmInDom(pp->desc.indom);
+ desc->units = __ntohpmUnits(pp->desc.units);
+ desc->pmid = __ntohpmID(pp->desc.pmid);
+ return;
+}
+
+/*
+ * like rewrite_pdu() from pmlogger
+ */
+
+typedef struct {
+ pmID pmid;
+ int numval; /* no. of vlist els to follow, or error */
+ int valfmt; /* insitu or pointer */
+ __pmValue_PDU vlist[1]; /* zero or more */
+} vlist_t;
+
+typedef struct {
+ int hdr;
+ // __pmPDUHdr hdr;
+ __pmTimeval timestamp; /* when returned */
+ int numpmid; /* no. of PMIDs to follow */
+ __pmPDU data[1]; /* zero or more */
+} result_t;
+
+#define PM_ERR_BASE1 1000
+#define XLATE_ERR_1TO2(e) \
+ ((e) <= -PM_ERR_BASE1 ? (e)+PM_ERR_BASE1-PM_ERR_BASE2 : (e))
+
+void
+rewrite_pdu(__pmPDU *pb)
+{
+ result_t *pp = (result_t *)pb;
+ int vsize;
+ int numpmid;
+ int numval;
+ vlist_t *vlp;
+ int i;
+
+ numpmid = ntohl(pp->numpmid);
+ vsize = 0;
+ for (i = 0; i < numpmid; i++) {
+ vlp = (vlist_t *)&pp->data[vsize/sizeof(__pmPDU)];
+ numval = ntohl(vlp->numval);
+ vsize += sizeof(vlp->pmid) + sizeof(vlp->numval);
+ if (numval > 0)
+ vsize += sizeof(vlp->valfmt) + numval * sizeof(__pmValue_PDU);
+ if (numval < 0)
+ vlp->numval = htonl(XLATE_ERR_1TO2(numval));
+ }
+
+ return;
+}
+
diff --git a/qa/pmlogconv/pmlogconv.c b/qa/pmlogconv/pmlogconv.c
new file mode 100644
index 0000000..0387ec0
--- /dev/null
+++ b/qa/pmlogconv/pmlogconv.c
@@ -0,0 +1,354 @@
+/*
+ * pmlogconv - convert PCP archive logs from V1 to V2 format
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include "pcp/pmapi.h"
+#include "pcp/impl.h"
+
+#define LOG 0
+#define META 1
+
+typedef struct { /* input archive control */
+ int ctx;
+ char *name;
+ pmLogLabel label;
+ __pmPDU *pb[2];
+ int pick[2];
+ int eof[2];
+} inarch_t;
+
+static __pmLogCtl logctl; /* output archive control */
+
+static inarch_t inarch;
+static __pmTimeval current; /* most recently output timestamp */
+
+static __pmHashCtl pmid_done;
+
+static int exit_status = 0;
+
+extern int _pmLogGet(__pmLogCtl *, int, __pmPDU **);
+extern int _pmLogPut(FILE *, __pmPDU *);
+extern void _pmUnpackDesc(__pmPDU *, pmDesc *);
+extern void rewrite_pdu(__pmPDU *);
+
+/*
+ *
+ */
+void
+writelabel_metati(int do_rewind)
+{
+ if (do_rewind) rewind(logctl.l_tifp);
+ logctl.l_label.ill_vol = PM_LOG_VOL_TI;
+ __pmLogWriteLabel(logctl.l_tifp, &logctl.l_label);
+
+
+ if (do_rewind) rewind(logctl.l_mdfp);
+ logctl.l_label.ill_vol = PM_LOG_VOL_META;
+ __pmLogWriteLabel(logctl.l_mdfp, &logctl.l_label);
+}
+
+void
+writelabel_data(void)
+{
+ logctl.l_label.ill_vol = 0;
+ __pmLogWriteLabel(logctl.l_mfp, &logctl.l_label);
+}
+
+static void
+_report(FILE *fp)
+{
+ off_t here;
+ struct stat sbuf;
+
+ here = lseek(fileno(fp), 0L, SEEK_CUR);
+ fprintf(stderr, "Error occurred at byte offset %ld into a file of", here);
+ if (fstat(fileno(fp), &sbuf) < 0)
+ fprintf(stderr, ": stat: %s\n", strerror(errno));
+ else
+ fprintf(stderr, " %ld bytes.\n", sbuf.st_size);
+ fprintf(stderr, "The last record, and the remainder of this file will not be merged.\n");
+ exit_status = 1;
+}
+
+/*
+ * pick next archive record
+ * - if next metadata is pmDesc, output this
+ * - else choose youngest data or pmInDom metadata
+ * - if data and pmIndom have same timestamp, choose pmInDom
+ */
+static int
+nextrec(void)
+{
+ int sts;
+ int pick = PM_ERR_EOL;
+ __pmTimeval *this;
+ __pmLogCtl *lcp;
+ __pmContext *ctxp;
+
+ if (!inarch.eof[META]) {
+ if (inarch.pb[META] == (__pmPDU *)0) {
+ /* refill metadata buffer */
+ ctxp = __pmHandleToPtr(inarch.ctx);
+ lcp = ctxp->c_archctl->ac_log;
+ if ((sts = _pmLogGet(lcp, PM_LOG_VOL_META, &inarch.pb[META])) < 0) {
+ inarch.eof[META] = 1;
+ if (sts != PM_ERR_EOL) {
+ fprintf(stderr, "%s: Error: __pmLogRead[meta %s]: %s\n",
+ pmProgname, inarch.name, pmErrStr(sts));
+ _report(lcp->l_mdfp);
+ exit(1);
+ }
+ }
+ }
+ }
+
+ if (!inarch.eof[LOG]) {
+ if (inarch.pb[LOG] == (__pmPDU *)0) {
+ ctxp = __pmHandleToPtr(inarch.ctx);
+ lcp = ctxp->c_archctl->ac_log;
+ if ((sts = _pmLogGet(lcp, 0, &inarch.pb[LOG])) < 0) {
+ inarch.eof[LOG] = 1;
+ if (sts != PM_ERR_EOL) {
+ fprintf(stderr, "%s: Error: __pmLogRead[log %s]: %s\n",
+ pmProgname, inarch.name, pmErrStr(sts));
+ _report(lcp->l_mfp);
+ exit(1);
+ }
+ }
+ }
+ }
+
+ if (!inarch.eof[META] && ntohl(inarch.pb[META][1]) == TYPE_DESC) {
+ /* pmDesc entry, output this immediately */
+ pmDesc desc;
+ _pmUnpackDesc(inarch.pb[META], &desc);
+ if (__pmHashSearch((int)desc.pmid, &pmid_done) != (__pmHashNode *)0) {
+ /* already been processed from another log, skip this one */
+ fprintf(stderr, "Botch: pmDesc for pmid %s seen twice in input archive\n", pmIDStr(desc.pmid));
+ exit(1);
+ }
+ __pmHashAdd((int)desc.pmid, (void *)0, &pmid_done);
+ inarch.pick[META] = TYPE_DESC;
+ return 0;
+ }
+
+ if (!inarch.eof[LOG]) {
+ this = (__pmTimeval *)&inarch.pb[LOG][1];
+ inarch.pick[LOG] = 1;
+ pick = 0;
+ current.tv_sec = ntohl(this->tv_sec);
+ current.tv_usec = ntohl(this->tv_usec);
+ }
+
+ if (!inarch.eof[META]) {
+ this = (__pmTimeval *)&inarch.pb[META][2];
+ if (ntohl(this->tv_sec) < current.tv_sec ||
+ (ntohl(this->tv_sec) == current.tv_sec && ntohl(this->tv_usec) <= current.tv_usec)) {
+ inarch.pick[LOG] = 0;
+ inarch.pick[META] = TYPE_INDOM;
+ pick = 0;
+ current.tv_sec = ntohl(this->tv_sec);
+ current.tv_usec = ntohl(this->tv_usec);
+ }
+ }
+
+ return pick;
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ int sts;
+ char *p;
+ int errflag = 0;
+ char *output;
+ char *pmnsfile = NULL;
+ int needti = 0;
+ off_t old_log_offset;
+ off_t new_log_offset;
+ off_t old_meta_offset;
+ off_t new_meta_offset;
+ extern char *optarg;
+ extern int optind;
+ extern int pmDebug;
+
+ /* trim cmd name of leading directory components */
+ pmProgname = argv[0];
+ for (p = pmProgname; *p; p++) {
+ if (*p == '/')
+ pmProgname = p+1;
+ }
+
+ while ((c = getopt(argc, argv, "D:n:?")) != EOF) {
+ switch (c) {
+
+ case 'D': /* debug flag */
+ sts = __pmParseDebug(optarg);
+ if (sts < 0) {
+ fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n",
+ pmProgname, optarg);
+ errflag++;
+ }
+ else
+ pmDebug |= sts;
+ break;
+
+ case 'n':
+ pmnsfile = optarg;
+ break;
+
+ case '?':
+ default:
+ errflag++;
+ break;
+ }
+ }
+
+ if (errflag != 0 || pmnsfile == NULL || optind != argc-2) {
+ fprintf(stderr,
+"Usage: %s [options] input-archive output-archive\n\
+\n\
+Options\n\
+ -D debug standard PCP debug flag\n\
+ -n pmnsfile PMNS to use (not optional)\n",
+ pmProgname);
+ exit(1);
+ }
+
+ if ((sts = pmLoadNameSpace(pmnsfile)) < 0) {
+ fprintf(stderr, "%s: Error loading namespace: %s\n", pmProgname, pmErrStr(sts));
+ exit(1);
+ }
+
+ inarch.name = argv[optind];
+ if ((inarch.ctx = pmNewContext(PM_CONTEXT_ARCHIVE, inarch.name)) < 0) {
+ fprintf(stderr, "%s: Error: cannot open archive \"%s\": %s\n",
+ pmProgname, inarch.name, pmErrStr(inarch.ctx));
+ exit(1);
+ }
+ if ((sts = pmGetArchiveLabel(&inarch.label)) < 0) {
+ fprintf(stderr, "%s: Error: cannot get archive label record (%s): %s\n",
+ pmProgname, inarch.name, pmErrStr(sts));
+ exit(1);
+ }
+
+ inarch.pb[LOG] = inarch.pb[META] = (__pmPDU *)0;
+ inarch.eof[LOG] = inarch.eof[META] = 0;
+ inarch.pick[LOG] = inarch.pick[META] = 0;
+
+ output = argv[argc-1];
+ if ((sts = __pmLogCreate("", output, PM_LOG_VERS02, &logctl)) < 0) {
+ fprintf(stderr, "%s: Error: __pmLogCreate: %s\n", pmProgname, pmErrStr(sts));
+ exit(1);
+ }
+
+ logctl.l_label.ill_magic = PM_LOG_MAGIC | PM_LOG_VERS02;
+ logctl.l_label.ill_pid = inarch.label.ll_pid;
+ logctl.l_label.ill_start.tv_sec = inarch.label.ll_start.tv_sec;
+ logctl.l_label.ill_start.tv_usec = inarch.label.ll_start.tv_usec;
+ strcpy(logctl.l_label.ill_hostname, inarch.label.ll_hostname);
+ strcpy(logctl.l_label.ill_tz, inarch.label.ll_tz);
+ writelabel_metati(0);
+
+ /*
+ * do meta and log records at the same time ... in the case of an
+ * equal match, the log record is processed before the corresponding
+ * meta data
+ */
+ for ( ; ; ) {
+ if (nextrec() < 0)
+ break;
+
+ if (inarch.pick[LOG]) {
+ old_log_offset = ftell(logctl.l_mfp);
+ old_meta_offset = ftell(logctl.l_mdfp);
+ if (old_log_offset == 0) {
+ /* write label record for data file */
+ logctl.l_label.ill_start.tv_sec = current.tv_sec;
+ logctl.l_label.ill_start.tv_usec = current.tv_usec;
+ writelabel_data();
+ old_log_offset = ftell(logctl.l_mfp);
+ needti = 1;
+ }
+
+ /*
+ * ignore 2^31 check for vol switch on output archive ...
+ * if input archive is one volume, would have been unreadable
+ * if too large
+ * if input archive is multivolume, we create a single
+ * volume output, so there is a potential problem here ...
+ * TODO - revisit this issue only if a need arises
+ */
+
+ /* translate data record from V1 to V2 */
+ rewrite_pdu(inarch.pb[LOG]);
+
+ /* write data record out */
+ if ((sts = _pmLogPut(logctl.l_mfp, inarch.pb[LOG])) < 0) {
+ fprintf(stderr, "%s: Error: _pmLogPut: log data: %s\n",
+ pmProgname, pmErrStr(sts));
+ exit(1);
+ }
+ /* free data record buffer */
+ free(inarch.pb[LOG]);
+ inarch.pb[LOG] = (__pmPDU *)0;
+ inarch.pick[LOG] = 0;
+
+ if (needti) {
+ fflush(logctl.l_mfp);
+ fflush(logctl.l_mdfp);
+ new_log_offset = ftell(logctl.l_mfp);
+ new_meta_offset = ftell(logctl.l_mdfp);
+ fseek(logctl.l_mfp, old_log_offset, SEEK_SET);
+ fseek(logctl.l_mdfp, old_meta_offset, SEEK_SET);
+ __pmLogPutIndex(&logctl, &current);
+ fseek(logctl.l_mfp, new_log_offset, SEEK_SET);
+ fseek(logctl.l_mdfp, new_log_offset, SEEK_SET);
+ needti = 0;
+ }
+ }
+
+ if (inarch.pick[META]) {
+ /* write metadata out and force temporal index update if indom */
+ if (inarch.pick[META] == TYPE_DESC) {
+ pmDesc desc;
+ char **names = NULL;
+ int numnames;
+ char *myname;
+
+ _pmUnpackDesc(inarch.pb[META], &desc);
+ if ((numnames = pmNameAll(desc.pmid, &names)) < 0) {
+ myname = strdup(pmIDStr(desc.pmid));
+ }
+ else {
+ myname = strdup(names[0]);
+ free(names);
+ }
+ __pmLogPutDesc(&logctl, &desc, 1, &myname);
+ free(myname);
+ }
+ else {
+ if ((sts = _pmLogPut(logctl.l_mdfp, inarch.pb[META])) < 0) {
+ fprintf(stderr, "%s: Error: _pmLogPut: meta data: %s\n",
+ pmProgname, pmErrStr(sts));
+ exit(1);
+ }
+ needti = 1;
+ }
+ /* free metadata buffer */
+ free(inarch.pb[META]);
+ inarch.pb[META] = (__pmPDU *)0;
+ inarch.pick[META] = 0;
+ }
+ }
+
+ writelabel_metati(1);
+
+ exit(exit_status);
+}