diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/newhelp | |
download | pcp-debian.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/newhelp')
-rw-r--r-- | src/newhelp/GNUmakefile | 40 | ||||
-rw-r--r-- | src/newhelp/chkhelp.c | 348 | ||||
-rw-r--r-- | src/newhelp/newhelp.c | 473 |
3 files changed, 861 insertions, 0 deletions
diff --git a/src/newhelp/GNUmakefile b/src/newhelp/GNUmakefile new file mode 100644 index 0000000..658f5cc --- /dev/null +++ b/src/newhelp/GNUmakefile @@ -0,0 +1,40 @@ +# +# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +TOPDIR = ../.. +include $(TOPDIR)/src/include/builddefs + +TARGETS = newhelp$(EXECSUFFIX) chkhelp$(EXECSUFFIX) +CFILES = newhelp.c chkhelp.c + +LLDFLAGS = $(WARN_OFF) +LLDLIBS = $(PCP_PMDALIB) +LDIRT = $(TARGETS) + +default: $(TARGETS) + +install: default + $(INSTALL) -m 755 $(TARGETS) $(PCP_BINADM_DIR) + +include $(BUILDRULES) + +newhelp$(EXECSUFFIX): newhelp.o + $(CCF) -o $@ $(LDFLAGS) newhelp.o $(LDLIBS) + +chkhelp$(EXECSUFFIX): chkhelp.o + $(CCF) -o $@ $(LDFLAGS) chkhelp.o $(LDLIBS) + +default_pcp: default + +install_pcp: install diff --git a/src/newhelp/chkhelp.c b/src/newhelp/chkhelp.c new file mode 100644 index 0000000..3e4f4ad --- /dev/null +++ b/src/newhelp/chkhelp.c @@ -0,0 +1,348 @@ +/* + * + * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * check help files build by newhelp + * + * Usage: + * chkhelp helpfile metricname ... + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" + +#define VERSION 2 +static int version = VERSION; + +static int handle; + +/* + * Note: these two are from libpcp_pmda/src/help.c + */ +typedef struct { + pmID pmid; + __uint32_t off_oneline; + __uint32_t off_text; +} help_idx_t; + +typedef struct { + int dir_fd; + int pag_fd; + int numidx; + help_idx_t *index; + char *text; + int textlen; +} help_t; + +static int +next(int *ident, int *type) +{ + static help_t *hp = NULL; + static int nextidx; + pmID pmid; + __pmID_int *pi = (__pmID_int *)&pmid; + extern void *__pmdaHelpTab(void); + + if (hp == NULL) { + hp = (help_t *)__pmdaHelpTab(); + /* + * Note, skip header and version info at index[0] + */ + nextidx = 1; + } + + if (nextidx > hp->numidx) + return 0; + + pmid = hp->index[nextidx].pmid; + nextidx++; + + if (pi->flag == 0) { + /* real PMID */ + *ident = (int)pmid; + *type = 1; + } + else { + /* special hack, this is encoding a domain id, not a PMID */ + pi->flag = 0; + *ident = (int)pmid; + *type = 2; + } + + return 1; +} + + +/* + * with -e come here for every metric in the PMNS ... + */ +void +dometric(const char *name) +{ + int sts; + pmID pmid; + char *tp; + + sts = pmLookupName(1, (char **)&name, &pmid); + if (sts < 0) { + fprintf(stderr, "pmLookupName: failed for \"%s\": %s\n", name, pmErrStr(sts)); + return; + } + if (sts == 0) { + fprintf(stderr, "pmLookupName: failed for \"%s\"\n", name); + return; + } + + tp = pmdaGetHelp(handle, pmid, PM_TEXT_ONELINE); + if (tp != NULL) + return; + tp = pmdaGetHelp(handle, pmid, PM_TEXT_HELP); + if (tp != NULL) + return; + + /* no help text, report metric */ + printf("%s\n", name); +} + +int +main(int argc, char **argv) +{ + int sts; + int c; + int help = 0; + int oneline = 0; + char *pmnsfile = PM_NS_DEFAULT; + int errflag = 0; + int aflag = 0; + int eflag = 0; + int allpmid = 0; + int allindom = 0; + char *filename; + char *tp; + char *name; + int id; + int next_type; + char *endnum; + + __pmSetProgname(argv[0]); + + while ((c = getopt(argc, argv, "D:eHin:Opv:?")) != 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 'e': /* help text exists? */ + eflag = 1; + break; + + case 'H': /* help text */ + help = 1; + break; + + case 'i': + aflag++; + allindom = 1; + break; + + case 'n': /* alternative namespace file */ + pmnsfile = optarg; + break; + + case 'O': /* oneline text */ + oneline = 1; + break; + + case 'p': + aflag++; + allpmid = 1; + break; + + case 'v': /* version 2 only these days */ + version = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0') { + fprintf(stderr, "%s: -v requires numeric argument\n", pmProgname); + errflag++; + } + if (version != 2) { + fprintf(stderr + ,"%s: deprecated option - only version 2 is supported\n" + , pmProgname); + errflag++; + } + break; + + case '?': + default: + errflag++; + break; + } + } + + if (optind == argc) { + fprintf(stderr, "%s: missing helpfile argument\n\n", pmProgname); + errflag = 1; + } + + if (aflag && optind < argc-1) { + fprintf(stderr, "%s: metricname arguments cannot be used with -i or -p\n\n", + pmProgname); + errflag = 1; + } + + if (aflag == 0 && optind == argc-1 && oneline+help != 0) { + fprintf(stderr, "%s: -O or -H require metricname arguments or -i or -p\n\n", + pmProgname); + errflag = 1; + } + + if (eflag && (allpmid || allindom)) { + fprintf(stderr, "%s: -e cannot be used with -i or -p\n\n", + pmProgname); + errflag = 1; + } + + if (errflag || optind >= argc) { + fprintf(stderr, +"Usage: %s helpfile\n" +" %s [options] helpfile [metricname ...]\n" +"\n" +"Options:\n" +" -e exists check, only report metrics with no help text\n" +" -H display verbose help text\n" +" -i process all the instance domains\n" +" -n pmnsfile use an alternative PMNS\n" +" -O display the one line help summary\n" +" -p process all the metrics (PMIDs)\n" +" -v version deprecated (only version 2 format supported)\n" +"\n" +"No options implies silently check internal integrity of the helpfile.\n", + pmProgname, pmProgname); + exit(1); + } + + filename = argv[optind++]; + if ((handle = pmdaOpenHelp(filename)) < 0) { + fprintf(stderr, "pmdaOpenHelp: failed to open \"%s\": ", filename); + if (handle == -EINVAL) + fprintf(stderr, "Bad format, not version %d PCP help text\n", version); + else + fprintf(stderr, "%s\n", pmErrStr(handle)); + exit(1); + } + + if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { + fprintf(stderr, "pmLoadNameSpace: %s\n", pmErrStr(sts)); + exit(1); + } + + if (help + oneline == 0 && (optind < argc || aflag)) + /* if metric names, -p or -i => -O is default */ + oneline = 1; + + if (optind == argc && aflag == 0) + /* no metric names, process all entries */ + aflag = 1; + + if (eflag) { + if (optind == argc) + sts = pmTraversePMNS("", dometric); + if (sts < 0) + fprintf(stderr, "Error: pmTraversePMNS(\"\", ...): %s\n", pmErrStr(sts)); + else { + for ( ; optind < argc; optind++) { + sts = pmTraversePMNS(argv[optind], dometric); + if (sts < 0) + fprintf(stderr, "Error: pmTraversePMNS(\"%s\", ...): %s\n", argv[optind], pmErrStr(sts)); + } + } + exit(0); + } + + while (optind < argc || aflag) { + if (aflag) { + if (next(&id, &next_type) == 0) + break; +#ifdef PCP_DEBUG + if ((pmDebug & DBG_TRACE_APPL0) && allindom+allpmid == 0) + fprintf(stderr, "next_type=%d id=0x%x\n", next_type, id); +#endif + if (next_type == 2) { + if (!allindom) + continue; + printf("\nInDom %s:", pmInDomStr((pmInDom)id)); + } + else { + char *p; + if (!allpmid) + continue; + + printf("\nPMID %s", pmIDStr((pmID)id)); + sts = pmNameID(id, &p); + if (sts == 0) { + printf(" %s", p); + free(p); + } + putchar(':'); + } + } + else { + next_type = 1; + name = argv[optind++]; + if ((sts = pmLookupName(1, &name, (pmID *)&id)) < 0) { + printf("\n%s: %s\n", name, pmErrStr(sts)); + continue; + } + if (id == PM_ID_NULL) { + printf("\n%s: unknown metric\n", name); + continue; + } + printf("\nPMID %s %s:", pmIDStr((pmID)id), name); + } + + if (oneline) { + if (next_type == 1) + tp = pmdaGetHelp(handle, (pmID)id, PM_TEXT_ONELINE); + else + tp = pmdaGetInDomHelp(handle, (pmInDom)id, PM_TEXT_ONELINE); + if (tp != NULL) + printf(" %s", tp); + putchar('\n'); + } + + if (help) { + if (next_type == 1) + tp = pmdaGetHelp(handle, (pmID)id, PM_TEXT_HELP); + else + tp = pmdaGetInDomHelp(handle, (pmInDom)id, PM_TEXT_HELP); + if (tp != NULL && *tp) + printf("%s\n", tp); + } + + } + + return 0; +} diff --git a/src/newhelp/newhelp.c b/src/newhelp/newhelp.c new file mode 100644 index 0000000..97f0eaa --- /dev/null +++ b/src/newhelp/newhelp.c @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2014 Red Hat. + * Copyright (c) 1995-2001,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. + */ + +/* + * newhelp file + * + * in the model of newaliases, build ndbm data files for a PMDA's help file + * -- given the bloat of the ndbm files, version 2 uses a much simpler + * file access method, but preserves the file name conventions from + * version 1 that is based on ndbm. + */ + +#include <ctype.h> +#include <fcntl.h> +#include "pmapi.h" +#include "impl.h" + +#define DEFAULT_HELP_VERSION 2 + +/* maximum bytes per line and bytes per entry */ +#define MAXLINE 128 +#define MAXENTRY 1024 + +static int verbose; +static int ln; +static char *filename; +static int status; +static int version = DEFAULT_HELP_VERSION; +static FILE *f; + +typedef struct { + pmID pmid; + __uint32_t off_oneline; + __uint32_t off_text; +} help_idx_t; + +static help_idx_t *hindex; +static int numindex; +static int thisindex = -1; + +static void +newentry(char *buf) +{ + int n; + char *p; + char *end_name; + char end_c; + char *name; + pmID pmid; + char *start; + int warn = 0; + int i; + + /* skip leading white space ... */ + for (p = buf; isspace((int)*p); p++) + ; + /* skip over metric name or indom spec ... */ + name = p; + for (p = buf; *p != '\n' && !isspace((int)*p); p++) + ; + end_c = *p; + *p = '\0'; /* terminate metric name */ + end_name = p; + + if ((n = pmLookupName(1, &name, &pmid)) < 0) { + /* apparently not a metric name */ + int domain; + int cluster; + int item; + int serial; + pmID *pmidp; + if (sscanf(buf, "%d.%d.%d", &domain, &cluster, &item) == 3) { + /* a numeric pmid */ + __pmID_int ii; + ii.domain = domain; + ii.cluster = cluster; + ii.item = item; + ii.flag = 0; + pmidp = (pmID *)ⅈ + pmid = *pmidp; + } + else if (sscanf(buf, "%d.%d", &domain, &serial) == 2) { + /* an entry for an instance domain */ + __pmInDom_int ii; + ii.domain = domain; + ii.serial = serial; + /* set a bit here to disambiguate pmInDom from pmID */ + ii.flag = 1; + pmidp = (pmID *)ⅈ + pmid = *pmidp; + } + else { + fprintf(stderr, "%s: [%s:%d] %s: %s, entry abandoned\n", + pmProgname, filename, ln, buf, pmErrStr(n)); + status = 2; + return; + } + } + else { + if (pmid == PM_ID_NULL) { + fprintf(stderr, "%s: [%s:%d] %s: unknown metric, entry abandoned\n", + pmProgname, filename, ln, name); + status = 2; + return; + } + } + + for (i = 0; i < thisindex; i++) { + if (hindex[thisindex].pmid == pmid) { + __pmInDom_int *kp = (__pmInDom_int *)&pmid; + fprintf(stderr, "%s: [%s:%d] duplicate key (", + pmProgname, filename, ln); + if (kp->flag == 0) + fprintf(stderr, "%s", pmIDStr(pmid)); + else { + kp->flag = 0; + fprintf(stderr, "%s", pmInDomStr((pmInDom)pmid)); + } + fprintf(stderr, ") entry abandoned\n"); + status = 2; + return; + } + } + + if (++thisindex >= numindex) { + if (numindex == 0) + numindex = 128; + else + numindex *= 2; + if ((hindex = (help_idx_t *)realloc(hindex, numindex * sizeof(hindex[0]))) == NULL) { + __pmNoMem("newentry", numindex * sizeof(hindex[0]), PM_FATAL_ERR); + } + } + + fprintf(f, "\n@ %s ", name); + + hindex[thisindex].pmid = pmid; + hindex[thisindex].off_oneline = ftell(f); + + /* skip white space ... to start of oneline */ + *p = end_c; + if (*p != '\n') + p++; + for ( ; *p != '\n' && isspace((int)*p); p++) + ; + start = p; + + /* skip to end of line ... */ + for ( ; *p != '\n'; p++) + ; + *p = '\0'; + p++; + + if (p - start == 1 && verbose) { + fprintf(stderr, "%s: [%s:%d] %s: warning, null oneline\n", + pmProgname, filename, ln, name); + warn = 1; + if (!status) status = 1; + } + + if (fwrite(start, sizeof(*start), p - start, f) != p - start || ferror(f)) { + fprintf(stderr, "%s: [%s:%d] %s: write oneline failed, entry abandoned\n", + pmProgname, filename, ln, name); + thisindex--; + status = 2; + return; + } + + hindex[thisindex].off_text = ftell(f); + + /* trim all but last newline ... */ + i = (int)strlen(p) - 1; + while (i >= 0 && p[i] == '\n') + i--; + if (i < 0) + i = 0; + else { + /* really have text ... p[i] is last non-newline char */ + i++; + if (version == 1) + p[i++] = '\n'; + } + p[i] = '\0'; + + if (i == 0 && verbose) { + fprintf(stderr, "%s: [%s:%d] %s: warning, null help\n", + pmProgname, filename, ln, name); + warn = 1; + if (!status) status = 1; + } + + if (fwrite(p, sizeof(*p), i+1, f) != i+1 || ferror(f)) { + fprintf(stderr, + "%s: [%s:%d] %s: write help failed, entry abandoned\n", + pmProgname, filename, ln, name); + thisindex--; + status = 2; + return; + } + + if (verbose && warn == 0) { + *end_name = '\0'; + fprintf(stderr, "%s\n", name); + *end_name = end_c; + } +} + +static int +idcomp(const void *a, const void *b) +{ + /* + * comparing 32-bit keys here ... want PMIDs to go first the + * InDoms, sort by low order bits ... serial from InDom is easier + * than cluster and item from PMID, so use InDom format + */ + __pmInDom_int *iiap, *iibp; + + iiap = (__pmInDom_int *)(&((help_idx_t *)a)->pmid); + iibp = (__pmInDom_int *)(&((help_idx_t *)b)->pmid); + + if (iiap->flag == iibp->flag) + /* both of the same type, use serial to order */ + return iiap->serial - iibp->serial; + else if (iiap->flag == 0) + /* a is the PMID, b is an InDom */ + return -1; + else + /* b is the PMID, a is an InDom */ + return 1; +} + +static pmLongOptions longopts[] = { + PMAPI_OPTIONS_HEADER("General options"), + PMOPT_DEBUG, + PMOPT_NAMESPACE, + PMOPT_HELP, + PMAPI_OPTIONS_HEADER("Output options"), + { "output", 1, 'o', "FILE", "base name for output files" }, + { "verbose", 0, 'V', 0, "verbose/diagnostic output" }, + { "version", 0, 'v', 0, "deprecated (only version 2 format supported)" }, + PMAPI_OPTIONS_END +}; + +static pmOptions opts = { + .short_options = "D:n:o:Vv:?", + .long_options = longopts, + .short_usage = "[options] [file ...]", +}; + +int +main(int argc, char **argv) +{ + int n; + int c; + int i; + int sts; + char *pmnsfile = PM_NS_DEFAULT; + char *fname = NULL; + char pathname[MAXPATHLEN]; + FILE *inf; + char buf[MAXENTRY+MAXLINE]; + char *endnum; + char *bp; + char *p; + int skip; + help_idx_t hdr; + + while ((c = pmgetopt_r(argc, argv, &opts)) != EOF) { + switch (c) { + + case 'D': /* debug flag */ + if ((sts = __pmParseDebug(opts.optarg)) < 0) { + pmprintf("%s: unrecognized debug flag specification (%s)\n", + pmProgname, opts.optarg); + opts.errors++; + } + else + pmDebug |= sts; + break; + + case 'n': /* alternative namespace file */ + pmnsfile = opts.optarg; + break; + + case 'o': /* alternative output file name */ + fname = opts.optarg; + break; + + case 'V': /* more chit-chat */ + verbose++; + break; + + case 'v': /* version 2 only these days */ + version = (int)strtol(opts.optarg, &endnum, 10); + if (*endnum != '\0') { + pmprintf("%s: -v requires numeric argument\n", pmProgname); + opts.errors++; + } + if (version != 2) { + pmprintf("%s: deprecated option - only version 2 is supported\n", + pmProgname); + opts.errors++; + } + break; + + case '?': + default: + opts.errors++; + break; + } + } + + if (opts.errors) { + pmUsageMessage(&opts); + exit(2); + } + + if ((n = pmLoadNameSpace(pmnsfile)) < 0) { + fprintf(stderr, "%s: pmLoadNameSpace: %s\n", pmProgname, pmErrStr(n)); + exit(2); + } + + do { + if (opts.optind < argc) { + filename = argv[opts.optind]; + if ((inf = fopen(filename, "r")) == NULL) { + perror(filename); + exit(2); + } + if (fname == NULL) + fname = filename; + } + else { + if (fname == NULL) { + fprintf(stderr, + "%s: need either a -o option or a filename " + "argument to name the output file\n", pmProgname); + exit(2); + } + filename = "<stdin>"; + inf = stdin; + } + + if (version == 2 && f == NULL) { + sprintf(pathname, "%s.pag", fname); + if ((f = fopen(pathname, "w")) == NULL) { + fprintf(stderr, "%s: fopen(\"%s\", ...) failed: %s\n", + pmProgname, pathname, osstrerror()); + exit(2); + } + /* header: 2 => pag cf 1 => dir */ + fprintf(f, "PcPh2%c\n", '0' + version); + } + + bp = buf; + skip = 1; + for ( ; ; ) { + if (fgets(bp, MAXLINE, inf) == NULL) { + skip = -1; + *bp = '@'; + } + ln++; + if (bp[0] == '#') + continue; + if (bp[0] == '@') { + /* start of a new entry */ + if (bp > buf) { + /* really have a prior entry */ + p = bp - 1; + while (p > buf && *p == '\n') + p--; + *++p = '\n'; + *++p = '\0'; + newentry(buf); + } + if (skip == -1) + break; + skip = 0; + bp++; /* skip '@' */ + while (*bp && isspace((int)*bp)) + bp++; + if (bp[0] == '\0') { + if (verbose) + fprintf(stderr, "%s: [%s:%d] null entry?\n", + pmProgname, filename, ln); + skip = 1; + bp = buf; + if (!status) status = 1; + } + else { + for (p = bp; *p; p++) + ; + memmove(buf, bp, p - bp + 1); + for (bp = buf; *bp; bp++) + ; + } + } + if (skip) + continue; + for (p = bp; *p; p++) + ; + if (bp > buf && p[-1] != '\n') { + *p++ = '\n'; + *p = '\0'; + fprintf(stderr, "%s: [%s:%d] long line split after ...\n%s", + pmProgname, filename, ln, buf); + ln--; + if (!status) status = 1; + } + bp = p; + if (bp > &buf[MAXENTRY]) { + bp = &buf[MAXENTRY]; + bp[-1] = '\0'; + bp[-2] = '\n'; + fprintf(stderr, "%s: [%s:%d] entry truncated after ... %s", + pmProgname, filename, ln, &bp[-64]); + skip = 1; + if (!status) status = 1; + } + } + + fclose(inf); + opts.optind++; + } while (opts.optind < argc); + + if (f != NULL) { + fclose(f); + + /* do the directory index ... */ + sprintf(pathname, "%s.dir", fname); + if ((f = fopen(pathname, "w")) == NULL) { + fprintf(stderr, "%s: fopen(\"%s\", ...) failed: %s\n", + pmProgname, pathname, osstrerror()); + exit(2); + } + + /* index header */ + hdr.pmid = 0x50635068; /* "PcPh" */ + /* "1" => dir, next char is version */ + hdr.off_oneline = 0x31000000 | (('0' + version) << 16); + hdr.off_text = thisindex + 1; /* # entries */ + if (fwrite(&hdr, sizeof(hdr), 1, f) != 1 || ferror(f)) { + fprintf(stderr, "%s: fwrite index failed: %s\n", + pmProgname, osstrerror()); + exit(2); + } + + /* sort and write index */ + qsort((void *)hindex, thisindex+1, sizeof(hindex[0]), idcomp); + for (i = 0; i <= thisindex; i++) { + if (fwrite(&hindex[i], sizeof(hindex[0]), 1, f) != 1 + || ferror(f)) { + fprintf(stderr, "%s: fwrite index failed: %s\n", + pmProgname, osstrerror()); + exit(2); + } + } + } + + exit(status); +} |