diff options
Diffstat (limited to 'src/pmns/pmnsmerge.c')
-rw-r--r-- | src/pmns/pmnsmerge.c | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/src/pmns/pmnsmerge.c b/src/pmns/pmnsmerge.c new file mode 100644 index 0000000..39316a1 --- /dev/null +++ b/src/pmns/pmnsmerge.c @@ -0,0 +1,322 @@ +/* + * pmnsmerge [-adfv] infile [...] outfile + * + * Merge PCP PMNS files + * + * Copyright (c) 1995-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. + */ + +#include <ctype.h> +#include <sys/stat.h> +#include "pmapi.h" +#include "impl.h" +#include "pmnsutil.h" + +static FILE *outf; /* output */ +static __pmnsNode *root; /* result so far */ +static char *fullname; /* full PMNS pathname for newbie */ +static int verbose; + +static pmLongOptions longopts[] = { + PMAPI_OPTIONS_HEADER("Options"), + PMOPT_DEBUG, + { "", 0, 'a', 0, "process files in order, ignoring embedded _DATESTAMP control lines" }, + { "duplicates", 0, 'd', 0, "duplicate PMIDs are allowed" }, + { "force", 0, 'f', 0, "force overwriting of the output file if it exists" }, + { "verbose", 0, 'v', 0, "verbose, echo input file names as processed" }, + PMOPT_HELP, + PMAPI_OPTIONS_END +}; + +static pmOptions opts = { + .short_options = "aD:dfv?", + .long_options = longopts, + .short_usage = "[options] infile [...] outfile", +}; + +typedef struct { + char *fname; + char *date; +} datestamp_t; + +#define STAMP "_DATESTAMP" + +static int +sortcmp(const void *a, const void *b) +{ + datestamp_t *pa = (datestamp_t *)a; + datestamp_t *pb = (datestamp_t *)b; + + if (pa->date == NULL) return -1; + if (pb->date == NULL) return 1; + return strcmp(pa->date, pb->date); +} + +/* + * scan for #define _DATESTAMP and re-order args accordingly + */ +static void +sortargs(char **argv, int argc) +{ + FILE *f; + datestamp_t *tab; + char *p; + char *q; + int i; + char lbuf[40]; + + tab = (datestamp_t *)malloc(argc * sizeof(datestamp_t)); + + for (i = 0; i <argc; i++) { + if ((f = fopen(argv[i], "r")) == NULL) { + fprintf(stderr, "%s: Error: cannot open input PMNS file \"%s\"\n", + pmProgname, argv[i]); + exit(1); + } + tab[i].fname = strdup(argv[i]); + tab[i].date = NULL; + while (fgets(lbuf, sizeof(lbuf), f) != NULL) { + if (strncmp(lbuf, "#define", 7) != 0) + continue; + p = &lbuf[7]; + while (*p && isspace((int)*p)) + p++; + if (*p == '\0' || strncmp(p, STAMP, strlen(STAMP)) != 0) + continue; + p += strlen(STAMP); + while (*p && isspace((int)*p)) + p++; + q = p; + while (*p && !isspace((int)*p)) + p++; + *p = '\0'; + tab[i].date = strdup(q); + break; + } + fclose(f); + } + + qsort(tab, argc, sizeof(tab[0]), sortcmp); + for (i = 0; i <argc; i++) { + argv[i] = tab[i].fname; + if (verbose > 1) + printf("arg[%d] %s _DATESTAMP=%s\n", i, tab[i].fname, tab[i].date); + } + + free(tab); +} + +static void +addpmns(__pmnsNode *base, char *name, __pmnsNode *p) +{ + char *tail; + ptrdiff_t nch; + __pmnsNode *np; + __pmnsNode *lastp = NULL; + + for (tail = name; *tail && *tail != '.'; tail++) + ; + nch = tail - name; + + for (np = base->first; np != NULL; np = np->next) { + if (strlen(np->name) == nch && strncmp(name, np->name, (int)nch) == 0) + break; + lastp = np; + } + + if (np == NULL) { + /* no match ... add here */ + np = (__pmnsNode *)malloc(sizeof(__pmnsNode)); + if (base->first) { + lastp->next = np; + np->parent = lastp->parent; + } + else { + base->first = np; + np->parent = base; + } + np->first = np->next = NULL; + np->hash = NULL; /* we do not need this here */ + np->name = (char *)malloc(nch+1); + strncpy(np->name, name, nch); + np->name[nch] = '\0'; + if (*tail == '\0') { + np->pmid = p->pmid; + return; + } + np->pmid = PM_ID_NULL; + } + else if (*tail == '\0') { + /* complete match */ + if (np->pmid != p->pmid) { + fprintf(stderr, "%s: Warning: performance metric \"%s\" has multiple PMIDs.\n... using PMID %s and ignoring PMID", + pmProgname, fullname, pmIDStr(np->pmid)); + fprintf(stderr, " %s\n", + pmIDStr(p->pmid)); + } + return; + } + + /* descend */ + addpmns(np, tail+1, p); +} + + +/* + * merge, adding new nodes if required + */ +static void +merge(__pmnsNode *p, int depth, char *path) +{ + char *name; + + if (depth < 1 || p->pmid == PM_ID_NULL || p->first != NULL) + return; + name = (char *)malloc(strlen(path)+strlen(p->name)+2); + if (*path == '\0') + strcpy(name, p->name); + else { + strcpy(name, path); + strcat(name, "."); + strcat(name, p->name); + } + fullname = name; + addpmns(root, name, p); + free(name); +} + +int +main(int argc, char **argv) +{ + int sts; + int first = 1; + int c; + int j; + int force = 0; + int asis = 0; + int dupok = 0; + __pmnsNode *tmp; + + umask((mode_t)022); /* anything else is pretty silly */ + + while ((c = pmgetopt_r(argc, argv, &opts)) != EOF) { + switch (c) { + + case 'a': + asis = 1; + break; + + case 'd': /* duplicate PMIDs are OK */ + dupok = 1; + break; + + 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 'f': /* force ... unlink file first */ + force = 1; + break; + + case 'v': + verbose++; + break; + + case '?': + default: + opts.errors++; + break; + } + } + + if (opts.errors || opts.optind > argc - 2) { + pmUsageMessage(&opts); + exit(1); + } + + if (force) + unlink(argv[argc-1]); + + if (access(argv[argc-1], F_OK) == 0) { + fprintf(stderr, "%s: Error: output PMNS file \"%s\" already exists!\nYou must either remove it first, or use -f\n", + pmProgname, argv[argc-1]); + exit(1); + } + + /* + * from here on, ignore SIGHUP, SIGINT and SIGTERM to protect + * the integrity of the new ouput file + */ + __pmSetSignalHandler(SIGHUP, SIG_IGN); + __pmSetSignalHandler(SIGINT, SIG_IGN); + __pmSetSignalHandler(SIGTERM, SIG_IGN); + + if ((outf = fopen(argv[argc-1], "w+")) == NULL) { + fprintf(stderr, "%s: Error: cannot create output PMNS file \"%s\": %s\n", pmProgname, argv[argc-1], osstrerror()); + exit(1); + } + + if (!asis) + sortargs(&argv[opts.optind], argc - opts.optind - 1); + + j = opts.optind; + while (j < argc-1) { + if (verbose) + printf("%s:\n", argv[j]); + + if ((sts = pmLoadASCIINameSpace(argv[j], dupok)) < 0) { + fprintf(stderr, "%s: Error: pmLoadNameSpace(%s): %s\n", + pmProgname, argv[j], pmErrStr(sts)); + exit(1); + } + { + __pmnsTree *t; + t = __pmExportPMNS(); + if (t == NULL) { + /* sanity check - shouldn't ever happen */ + fprintf(stderr, "Exported PMNS is NULL !"); + exit(1); + } + tmp = t->root; + } + + if (first) { + root = tmp; + first = 0; + } + else { + pmns_traverse(tmp, 0, "", merge); + } + j++; + } + + pmns_output(root, outf); + fclose(outf); + + /* + * now load the merged PMNS to check for errors ... + */ + if ((sts = pmLoadASCIINameSpace(argv[argc-1], dupok)) < 0) { + fprintf(stderr, "%s: Error: pmLoadNameSpace(%s): %s\n", + pmProgname, argv[argc-1], pmErrStr(sts)); + exit(1); + } + + exit(0); +} |