diff options
Diffstat (limited to 'qa/pmlogconv')
-rwxr-xr-x | qa/pmlogconv/GNUmakefile | 44 | ||||
-rw-r--r-- | qa/pmlogconv/libpcp.c | 489 | ||||
-rw-r--r-- | qa/pmlogconv/logio.c | 261 | ||||
-rw-r--r-- | qa/pmlogconv/pmlogconv.c | 354 |
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, ¤t); + 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); +} |