summaryrefslogtreecommitdiff
path: root/src/pmevent/doargs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmevent/doargs.c')
-rw-r--r--src/pmevent/doargs.c517
1 files changed, 517 insertions, 0 deletions
diff --git a/src/pmevent/doargs.c b/src/pmevent/doargs.c
new file mode 100644
index 0000000..0692c31
--- /dev/null
+++ b/src/pmevent/doargs.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2008-2009 Aconex. All Rights Reserved.
+ * Copyright (c) 2011 Red Hat Inc.
+ * Copyright (c) 2011 Ken McDonell. 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 "pmevent.h"
+
+static int setupEventTrace(int, char **, int, char *);
+static char *options = "a:D:gh:K:LO:p:S:s:T:t:vx:zZ:?";
+static char usage[] =
+ "Usage: %s [options] metricname ...\n\n"
+ "Options:\n"
+ " -a archive metrics source is a PCP archive\n"
+ " -g start in GUI mode with new time control\n"
+ " -h host metrics source is PMCD on host\n"
+ " -K spec optional additional PMDA spec for local connection\n"
+ " spec is of the form op,domain,dso-path,init-routine\n"
+ " -L metrics source is a local context\n"
+ " -O offset initial offset into the reporting time window\n"
+ " -p port port number for connection to existing time control\n"
+ " -S starttime start of the reporting time window\n"
+ " -s samples terminate after this many samples\n"
+ " -T endtime end of the reporting time window\n"
+ " -t interval sample interval [default 1 second]\n"
+ " -v increase diagnostic output\n"
+ " -x filter optionally enable and filter the event stream\n"
+ " -Z timezone set reporting timezone\n"
+ " -z set reporting timezone to local timezone of metrics source\n";
+
+/* process command line options and flags - exits on error */
+void
+doargs(int argc, char **argv)
+{
+ int c;
+ long d;
+ int errflag = 0;
+ int m;
+ int src = 0;
+ int have_context = 0;
+ int sts;
+ char *endnum;
+ char *errmsg;
+ char *Sflag = NULL; /* argument of -S flag */
+ char *Tflag = NULL; /* argument of -T flag */
+ char *Oflag = NULL; /* argument of -O flag */
+ char *xflag = NULL; /* argument of -x flag */
+ int zflag = 0; /* for -z */
+ char *tz = NULL; /* for -Z timezone */
+ int tzh; /* initial timezone handle */
+ struct timeval logStart;
+ metric_t *mp;
+ pmMetricSpec *msp;
+ char *msg;
+ static pmLogLabel label;
+ static char *default_host_conn = "local:";
+ char *host_conn = default_host_conn; /* argument of -h */
+ const char *tmp;
+
+ delta.tv_sec = 1;
+ delta.tv_usec = 0;
+ samples = ALL_SAMPLES;
+
+ /* extract command-line arguments */
+ while ((c = getopt(argc, argv, options)) != EOF) {
+ switch (c) {
+
+ case 'a': /* archive */
+ if (++src > 1) {
+ fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname);
+ errflag++;
+ }
+ ahtype = PM_CONTEXT_ARCHIVE;
+ archive = optarg;
+ break;
+
+ 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 'g': /* use "gui" mode */
+ if (port != -1) {
+ fprintf(stderr, "%s: at most one of -g and -p allowed\n", pmProgname);
+ errflag++;
+ }
+ else
+ gui = 1;
+ break;
+
+ case 'h': /* host name */
+ if (++src > 1) {
+ fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname);
+ errflag++;
+ }
+ ahtype = PM_CONTEXT_HOST;
+ host_conn = optarg;
+ break;
+
+ case 'K': /* update local PMDA table */
+ if ((errmsg = __pmSpecLocalPMDA(optarg)) != NULL) {
+ fprintf(stderr, "%s: illegal -K argument\n", pmProgname);
+ fputs(errmsg, stderr);
+ fputc('\n', stderr);
+ errflag++;
+ }
+ break;
+
+ case 'L': /* use local context */
+ if (++src > 1) {
+ fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname);
+ errflag++;
+ }
+ ahtype = PM_CONTEXT_LOCAL;
+ break;
+
+ case 'O': /* start report time offset */
+ Oflag = optarg;
+ break;
+
+ case 'p': /* port for slave of existing time control */
+ if (gui == 1) {
+ fprintf(stderr, "%s: at most one of -g and -p allowed\n", pmProgname);
+ errflag++;
+ }
+ else {
+ port = (int)strtol(optarg, &endnum, 10);
+ if (*endnum != '\0' || port < 0) {
+ fprintf(stderr, "%s: -p requires a positive numeric argument\n", pmProgname);
+ port = -1;
+ errflag++;
+ }
+ }
+ break;
+
+ case 's': /* sample count */
+ d = (int)strtol(optarg, &endnum, 10);
+ if (Tflag) {
+ fprintf(stderr, "%s: at most one of -s and -T allowed\n", pmProgname);
+ errflag++;
+ }
+ else if (*endnum != '\0' || d < 0) {
+ fprintf(stderr, "%s: -s requires a positive numeric argument\n", pmProgname);
+ errflag++;
+ }
+ else
+ samples = d;
+ break;
+
+ case 'S': /* start report time */
+ Sflag = optarg;
+ break;
+
+ case 't': /* sampling interval */
+ if (pmParseInterval(optarg, &delta, &msg) < 0) {
+ fprintf(stderr, "%s: illegal -t argument\n", pmProgname);
+ fputs(msg, stderr);
+ free(msg);
+ errflag++;
+ }
+ break;
+
+ case 'T': /* end reporting time */
+ if (samples != ALL_SAMPLES) {
+ fprintf(stderr, "%s: at most one of -s and -T allowed\n", pmProgname);
+ errflag++;
+ }
+ Tflag = optarg;
+ break;
+
+ case 'v':
+ verbose++;
+ break;
+
+ case 'x':
+ xflag = optarg;
+ break;
+
+ case 'z': /* timezone from metrics source */
+ if (tz != NULL) {
+ fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname);
+ errflag++;
+ }
+ zflag++;
+ break;
+
+ case 'Z': /* $TZ timezone */
+ if (zflag) {
+ fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname);
+ errflag++;
+ }
+ tz = optarg;
+ break;
+
+ case '?':
+ fprintf(stderr, usage, pmProgname);
+ exit(EXIT_FAILURE);
+
+ default:
+ errflag++;
+ }
+ }
+
+ if (errflag) {
+ fprintf(stderr, usage, pmProgname);
+ exit(EXIT_FAILURE);
+ }
+
+ if (optind >= argc) {
+ fprintf(stderr, "Error: no metricname specified\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* parse uniform metric spec */
+ for ( ; optind < argc; optind++) {
+ if (ahtype == PM_CONTEXT_ARCHIVE)
+ sts = pmParseMetricSpec(argv[optind], 1, archive, &msp, &msg);
+ else
+ sts = pmParseMetricSpec(argv[optind], 0, host_conn, &msp, &msg);
+ if (sts < 0) {
+ fprintf(stderr, "%s: bad metric specification\n", pmProgname);
+ fputs(msg, stderr);
+ free(msg);
+ exit(EXIT_FAILURE);
+ }
+
+ if (msp->isarch == 0) {
+ if (ahtype == -1) {
+ ahtype = PM_CONTEXT_HOST;
+ host_conn = msp->source;
+ }
+ else if ((ahtype == PM_CONTEXT_ARCHIVE) ||
+ (ahtype == PM_CONTEXT_LOCAL &&
+ (strcmp(msp->source, default_host_conn)))) {
+ fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]);
+ exit(EXIT_FAILURE);
+ }
+ else if (strcmp(host_conn, msp->source) != 0) {
+ fprintf(stderr, "%s: %s: only one metric source allowed, found hosts %s and %s\n", pmProgname, argv[optind], host_conn, msp->source);
+ exit(EXIT_FAILURE);
+ }
+ }
+ else if (msp->isarch == 1) {
+ if (ahtype == -1) {
+ ahtype = PM_CONTEXT_ARCHIVE;
+ archive = msp->source;
+ }
+ else if (ahtype != PM_CONTEXT_ARCHIVE) {
+ fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]);
+ exit(EXIT_FAILURE);
+ }
+ else if (strcmp(archive, msp->source) != 0) {
+ fprintf(stderr, "%s: %s: only one metric source allowed, found archives %s and %s\n", pmProgname, argv[optind], archive, msp->source);
+ exit(EXIT_FAILURE);
+ }
+ }
+ else if (msp->isarch == 2) {
+ if (ahtype == -1) {
+ ahtype = PM_CONTEXT_LOCAL;
+ }
+ else if (ahtype != PM_CONTEXT_LOCAL) {
+ fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (!have_context) {
+ if (ahtype == PM_CONTEXT_ARCHIVE) {
+ /* open connection to archive */
+ if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, archive)) < 0) {
+ fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n",
+ pmProgname, msp->source, pmErrStr(sts));
+ exit(EXIT_FAILURE);
+ }
+ ctxhandle = sts;
+ if ((sts = pmGetArchiveLabel(&label)) < 0) {
+ fprintf(stderr, "%s: Cannot get archive label record: %s\n",
+ pmProgname, pmErrStr(sts));
+ exit(EXIT_FAILURE);
+ }
+ have_context = 1;
+ logStart = label.ll_start;
+ host = label.ll_hostname;
+ if ((sts = pmGetArchiveEnd(&last)) < 0) {
+ fprintf(stderr, "%s: Cannot determine end of archive: %s",
+ pmProgname, pmErrStr(sts));
+ exit(EXIT_FAILURE);
+ }
+ }
+ else {
+ /* open connection to host or local context */
+ if ((sts = pmNewContext(ahtype, host_conn)) < 0) {
+ if (ahtype == PM_CONTEXT_HOST)
+ fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n",
+ pmProgname, msp->source, pmErrStr(sts));
+ else
+ fprintf(stderr, "%s: Cannot establish local context: %s\n",
+ pmProgname, pmErrStr(sts));
+ exit(EXIT_FAILURE);
+ }
+ ctxhandle = sts;
+ have_context = 1;
+ __pmtimevalNow(&logStart);
+ }
+ }
+
+ /* Look up the host name according to the pmcd or the archive. */
+ tmp = pmGetContextHostName(ctxhandle);
+ if (strlen(tmp) == 0) {
+ fprintf(stderr, "%s: pmGetContextHostName(%d) failed\n",
+ pmProgname, ctxhandle);
+ exit(EXIT_FAILURE);
+ }
+ if ((host = strdup(tmp)) == NULL)
+ __pmNoMem("host name copy", strlen(tmp)+1, PM_FATAL_ERR);
+
+ for (m = 0; m < nmetric; m++) {
+ if (strcmp(msp->metric, metrictab[m].name) == 0)
+ break;
+ }
+ if (m < nmetric)
+ mp = &metrictab[m];
+ else {
+ nmetric++;
+ metrictab = (metric_t *)realloc(metrictab, nmetric*sizeof(metrictab[0]));
+ if (metrictab == NULL) {
+ __pmNoMem("metrictab", nmetric*sizeof(metrictab[0]), PM_FATAL_ERR);
+ /*NOTREACHED*/
+ }
+ mp = &metrictab[nmetric-1];
+ mp->name = msp->metric;
+ if ((sts = pmLookupName(1, &mp->name, &mp->pmid)) < 0) {
+ fprintf(stderr, "%s: pmLookupName: %s: %s\n", pmProgname, mp->name, pmErrStr(sts));
+ exit(EXIT_FAILURE);
+ }
+ if ((sts = pmLookupDesc(mp->pmid, &mp->desc)) < 0) {
+ fprintf(stderr, "%s: pmLookupDesc: %s: %s\n", pmProgname, mp->name, pmErrStr(sts));
+ exit(EXIT_FAILURE);
+ }
+ if (mp->desc.type != PM_TYPE_EVENT &&
+ mp->desc.type != PM_TYPE_HIGHRES_EVENT) {
+ fprintf(stderr, "%s: %s: metrics must be of event type\n", pmProgname, mp->name);
+ exit(EXIT_FAILURE);
+ }
+ mp->ninst = 0;
+ mp->iname = NULL;
+ mp->inst = NULL;
+ mp->ihash.nodes = 0;
+ mp->ihash.hsize = 0;
+ mp->ihash.hash = NULL;
+ }
+
+ if (msp->ninst > 0) {
+ int i;
+ int j;
+ if (mp->desc.indom == PM_INDOM_NULL) {
+ fprintf(stderr, "%s: %s: singular metrics do not have instances\n", pmProgname, argv[optind]);
+ exit(EXIT_FAILURE);
+ }
+ i = mp->ninst;
+ mp->ninst += msp->ninst;
+ mp->iname = (char **)realloc(mp->iname, mp->ninst*sizeof(mp->iname[0]));
+ if (mp->iname == NULL) {
+ __pmNoMem("iname[]", mp->ninst*sizeof(mp->iname[0]), PM_FATAL_ERR);
+ /*NOTREACHED*/
+ }
+ mp->inst = (int *)realloc(mp->inst, mp->ninst*sizeof(mp->inst[0]));
+ if (mp->inst == NULL) {
+ __pmNoMem("inst[]", mp->ninst*sizeof(mp->inst[0]), PM_FATAL_ERR);
+ /*NOTREACHED*/
+ }
+ for (j = 0; j < msp->ninst; j++, i++) {
+ mp->iname[i] = msp->inst[j];
+ if (ahtype == PM_CONTEXT_ARCHIVE)
+ sts = pmLookupInDomArchive(mp->desc.indom, mp->iname[i]);
+ else
+ sts = pmLookupInDom(mp->desc.indom, mp->iname[i]);
+ if (sts < 0) {
+ fprintf(stderr, "%s: pmLookupInDom: %s[%s]: %s\n", pmProgname, mp->name, mp->iname[i], pmErrStr(sts));
+ exit(EXIT_FAILURE);
+ }
+ mp->inst[i] = sts;
+ }
+ }
+
+ /*
+ * don't call pmFreeMetricSpec(msp) because we retain pointers into
+ * the structure
+ */
+ }
+
+ if (zflag) {
+ if ((tzh = pmNewContextZone()) < 0) {
+ fprintf(stderr, "%s: Cannot set context timezone: %s\n",
+ pmProgname, pmErrStr(tzh));
+ exit(EXIT_FAILURE);
+ }
+ if (ahtype == PM_CONTEXT_ARCHIVE) {
+ printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n",
+ host);
+ }
+ else {
+ printf("Note: timezone set to local timezone of host \"%s\"\n\n", host);
+ }
+ }
+ else if (tz != NULL) {
+ if ((tzh = pmNewZone(tz)) < 0) {
+ fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n",
+ pmProgname, tz, pmErrStr(tzh));
+ exit(EXIT_FAILURE);
+ }
+ printf("Note: timezone set to \"TZ=%s\"\n\n", tz);
+ }
+
+ if (pmParseTimeWindow(Sflag, Tflag, NULL, Oflag,
+ &logStart, &last, &first, &last, &now, &msg) < 0) {
+ fprintf(stderr, "%s", msg);
+ exit(EXIT_FAILURE);
+ }
+
+ if (setupEventTrace(argc, argv, ahtype, xflag) < 0)
+ exit(EXIT_FAILURE);
+
+ if (pmDebug & DBG_TRACE_APPL0) {
+ char timebuf[26];
+ char *tp;
+ int i;
+ fprintf(stderr, "first=%.6f", __pmtimevalToReal(&first));
+ tp = pmCtime(&first.tv_sec, timebuf);
+ /*
+ * tp -> Ddd Mmm DD HH:MM:SS YYYY\n
+ * 0 4 8 1 1 2 2 2
+ * 1 8 0 3 4
+ */
+ fprintf(stderr, " [%24.24s]\n", tp);
+ fprintf(stderr, "now=%.6f", __pmtimevalToReal(&now));
+ tp = pmCtime(&now.tv_sec, timebuf);
+ fprintf(stderr, " [%24.24s]\n", tp);
+ fprintf(stderr, "last=%.6f", __pmtimevalToReal(&last));
+ tp = pmCtime(&last.tv_sec, timebuf);
+ fprintf(stderr, " [%24.24s]\n", tp);
+ fprintf(stderr, "delta=%.6f\n", __pmtimevalToReal(&delta));
+ if (samples != ALL_SAMPLES)
+ fprintf(stderr, "samples=%ld\n", samples);
+ for (m = 0; m < nmetric; m++) {
+ fprintf(stderr, "[%d] metric: %s", m, metrictab[m].name);
+ if (metrictab[m].ninst > 0) {
+ fprintf(stderr, " instance:");
+ for (i = 0; i < metrictab[m].ninst; i++) {
+ if (i == 0)
+ fputc(' ', stderr);
+ else
+ fprintf(stderr, ", ");
+ fprintf(stderr, "%s (%d)", metrictab[m].iname[i], metrictab[m].inst[i]);
+ }
+ fputc('\n', stderr);
+ }
+ }
+ }
+}
+
+int
+setupEventTrace(int argc, char **argv, int ahtype, char *xflag)
+{
+ pmValueSet pmvs;
+ pmValueBlock *pmvbp;
+ pmResult store = { .numpmid = 1 };
+ int m, vlen;
+
+ if (ahtype == PM_CONTEXT_ARCHIVE)
+ return 0; /* nothing to do at this stage */
+
+ if (ahtype == PM_CONTEXT_HOST)
+ __pmSetClientIdArgv(argc, argv);
+
+ /* build pmResult for pmStore call if we're explicitly enabling events */
+ if (xflag != NULL) {
+ vlen = PM_VAL_HDR_SIZE + strlen(xflag) + 1;
+ pmvbp = (pmValueBlock *)malloc(vlen);
+ if (!pmvbp)
+ __pmNoMem("store", vlen, PM_FATAL_ERR);
+ pmvbp->vtype = PM_TYPE_STRING;
+ pmvbp->vlen = vlen;
+ strcpy(pmvbp->vbuf, xflag);
+
+ store.vset[0] = &pmvs;
+ for (m = 0; m < nmetric; m++) {
+ pmvs.pmid = metrictab[m].pmid;
+ pmvs.numval = 1;
+ pmvs.valfmt = PM_VAL_SPTR;
+ pmvs.vlist[0].inst = PM_IN_NULL;
+ pmvs.vlist[0].value.pval = pmvbp;
+
+ pmStore(&store);
+ }
+
+ free(pmvbp);
+ }
+ return 0;
+}