summaryrefslogtreecommitdiff
path: root/src/pmnscomp/pmnscomp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmnscomp/pmnscomp.c')
-rw-r--r--src/pmnscomp/pmnscomp.c621
1 files changed, 621 insertions, 0 deletions
diff --git a/src/pmnscomp/pmnscomp.c b/src/pmnscomp/pmnscomp.c
new file mode 100644
index 0000000..ae10fa2
--- /dev/null
+++ b/src/pmnscomp/pmnscomp.c
@@ -0,0 +1,621 @@
+/*
+ * Construct a compiled PMNS suitable for "fast" loading in pmLoadNameSpace
+ *
+ * Copyright (c) 2014 Red Hat.
+ * Copyright (c) 1995-2006 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 <inttypes.h>
+#include <sys/stat.h>
+#include "pmapi.h"
+#include "impl.h"
+
+static int nodecnt; /* number of nodes */
+static int leafcnt; /* number of leaf nodes */
+static int symbsize; /* aggregate string table size */
+static __pmnsNode **_htab; /* output htab[] */
+static __pmnsNode *_nodetab; /* output nodes */
+static char *_symbol; /* string table */
+static char *symp; /* pointer into same */
+static __pmnsNode **_map; /* point-to-ordinal map */
+static int i; /* node counter for traversal */
+
+static int version = 2; /* default output format version */
+
+/*
+ * 32-bit pointer version of __pmnsNode
+ */
+typedef struct {
+ __int32_t parent;
+ __int32_t next;
+ __int32_t first;
+ __int32_t hash;
+ __int32_t name;
+ pmID pmid;
+} __pmnsNode32;
+static __int32_t *_htab32;
+static __pmnsNode32 *_nodetab32;
+
+/*
+ * 64-bit pointer version of __pmnsNode
+ */
+typedef struct {
+ __int64_t parent;
+ __int64_t next;
+ __int64_t first;
+ __int64_t hash;
+ __int64_t name;
+ pmID pmid;
+ __int32_t __pad__;
+} __pmnsNode64;
+static __int64_t *_htab64;
+static __pmnsNode64 *_nodetab64;
+
+static void
+dumpmap(void)
+{
+ int n;
+
+ for (n = 0; n < nodecnt; n++) {
+ if (n % 8 == 0) {
+ if (n)
+ putchar('\n');
+ printf("map[%3d]", n);
+ }
+ printf(" " PRINTF_P_PFX "%p", _map[n]);
+ }
+ putchar('\n');
+}
+
+static long
+nodemap(__pmnsNode *p)
+{
+ int n;
+
+ if (p == NULL)
+ return -1;
+
+ for (n = 0; n < nodecnt; n++) {
+ if (_map[n] == p)
+ return n;
+ }
+ printf("%s: fatal error, cannot map node addr " PRINTF_P_PFX "%p\n", pmProgname, p);
+ dumpmap();
+ exit(1);
+}
+
+static void
+traverse(__pmnsNode *p, void(*func)(__pmnsNode *this))
+{
+ if (p != NULL) {
+ (*func)(p);
+ traverse(p->first, func);
+ traverse(p->next, func);
+ }
+}
+
+#ifdef PCP_DEBUG
+static void
+chkascii(char *tag, char *p)
+{
+ int i = 0;
+
+ while (*p) {
+ if (!isascii((int)*p) || !isprint((int)*p)) {
+ printf("chkascii: %s: non-printable char 0x%02x in \"%s\"[%d] @ " PRINTF_P_PFX "%p\n",
+ tag, *p & 0xff, p, i, p);
+ exit(1);
+ }
+ i++;
+ p++;
+ }
+}
+
+static char *chktag;
+
+static void
+chknames(__pmnsNode *p)
+{
+ chkascii(chktag, p->name);
+}
+#endif
+
+static void
+pass1(__pmnsNode *p)
+{
+ nodecnt++;
+ if (p->pmid != PM_ID_NULL && p->first == NULL)
+ leafcnt++;
+ symbsize += strlen(p->name)+1;
+}
+
+static void
+pass2(__pmnsNode *p)
+{
+ ptrdiff_t offset;
+ _map[i] = p;
+ _nodetab[i] = *p; /* struct assignment */
+ strcpy(symp, p->name);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ chkascii("pass2 symtab", symp);
+#endif
+ offset = symp - _symbol;
+ symp += strlen(p->name);
+ *symp++ = '\0';
+ _nodetab[i].name = (char *)offset;
+ i++;
+}
+
+static void
+pass3(__pmnsNode *p)
+{
+ _nodetab[i].parent = (__pmnsNode *)nodemap(_nodetab[i].parent);
+ _nodetab[i].next = (__pmnsNode *)nodemap(_nodetab[i].next);
+ _nodetab[i].first = (__pmnsNode *)nodemap(_nodetab[i].first);
+ _nodetab[i].hash = (__pmnsNode *)nodemap(_nodetab[i].hash);
+ i++;
+}
+
+#ifndef __htonll
+void
+__htonll(char *p)
+{
+ char c;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ c = p[i];
+ p[i] = p[7-i];
+ p[7-i] = c;
+ }
+}
+#endif
+
+#ifdef HAVE_NETWORK_BYTEORDER
+#define __ntohll(a) /* noop */
+#else
+#define __ntohll(v) __htonll(v)
+#endif
+
+/*
+ * Promote a pointer to a 64 bit interger and do the endianess
+ * conversion on a 64 bit integer. Promotion should be sign
+ * extending because we're actually dealing with integers and
+ * not real pointers, so if promoting -1 from 32 to 64 bits, we
+ * want -1 to appear on the other end as well.
+ */
+static __int64_t
+to64_htonll(void *from)
+{
+ __int64_t to = (__psint_t)from; /* compiler sign extends */
+
+ __htonll((char *)&to);
+ return to;
+}
+
+/*
+ * And this is the reverse - take something which purpots to be a pointer
+ * and stuff it into an 32 bit integer. If cannot do it safely, then
+ * complain and exit
+ */
+static __int32_t
+to32_htonl(void *from)
+{
+ __int32_t to = (__int32_t)(__psint_t)from; /* compiler truncates */
+
+ if (to != (__psint_t)from) {
+ fprintf(stderr, "%s: loss of precision during the conversion\n",
+ pmProgname);
+ exit(1);
+ }
+ return htonl(to);
+}
+
+static pmLongOptions longopts[] = {
+ PMAPI_OPTIONS_HEADER("Options"),
+ PMOPT_DEBUG,
+ { "duplicates", 0, 'd', 0, "duplicate PMIDs are allowed" },
+ { "force", 0, 'f', 0, "force overwriting of the output file if it exists" },
+ PMOPT_NAMESPACE,
+ { "version", 1, 'v', "N", "alternate output format version [default 2]" },
+ PMOPT_HELP,
+ PMAPI_OPTIONS_END
+};
+
+static pmOptions opts = {
+ .short_options = "dD:fn:v:?",
+ .long_options = longopts,
+ .short_usage = "[options] outfile",
+};
+
+int
+main(int argc, char **argv)
+{
+ int n;
+ int c;
+ int j;
+ int sts;
+ int force = 0;
+ int dupok = 0;
+ char *pmnsfile = PM_NS_DEFAULT;
+ char *endnum;
+ FILE *outf;
+ __pmnsNode *root;
+ __pmnsNode **htab;
+ int htabcnt; /* count of the number of htab[] entries */
+ __int32_t tmp;
+ __int32_t sum;
+ long startsum = 0; /* initialize to pander to gcc */
+
+ while ((c = pmgetopt_r(argc, argv, &opts)) != EOF) {
+ switch (c) {
+
+ case 'd': /* duplicate PMIDs are allowed */
+ dupok = 1;
+ break;
+
+ case 'D': /* debug flag */
+ sts = __pmParseDebug(opts.optarg);
+ if (sts < 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 'n': /* alternative namespace file */
+ pmnsfile = opts.optarg;
+ break;
+
+ case 'v': /* alternate version */
+ version = (int)strtol(opts.optarg, &endnum, 10);
+ if (*endnum != '\0') {
+ pmprintf("%s: -v requires numeric argument\n", pmProgname);
+ opts.errors++;
+ }
+ if (version < 1 || version > 2) {
+ pmprintf("%s: output format version %d not supported\n",
+ pmProgname, version);
+ opts.errors++;
+ }
+ break;
+
+ case '?':
+ default:
+ opts.errors++;
+ break;
+ }
+ }
+
+ if (opts.errors || opts.optind != argc-1) {
+ pmUsageMessage(&opts);
+ exit(1);
+ }
+
+ if (force) {
+ struct stat sbuf;
+
+ if (stat(argv[opts.optind], &sbuf) == -1) {
+ if (oserror() != ENOENT) {
+ fprintf(stderr, "%s: cannot stat \"%s\": %s\n",
+ pmProgname, argv[opts.optind], osstrerror());
+ exit(1);
+ }
+ }
+ else {
+ /* stat is OK, so exists ... must be a regular file */
+ if (!S_ISREG(sbuf.st_mode)) {
+ fprintf(stderr, "%s: \"%s\" is not a regular file\n",
+ pmProgname, argv[opts.optind]);
+ exit(1);
+ }
+ if (unlink(argv[opts.optind]) == -1) {
+ fprintf(stderr, "%s: cannot unlink \"%s\": %s\n",
+ pmProgname, argv[opts.optind], osstrerror());
+ exit(1);
+ }
+ }
+ }
+
+ if (access(argv[opts.optind], F_OK) == 0) {
+ fprintf(stderr, "%s: \"%s\" already exists!\nYou must either remove it first, or use -f\n",
+ pmProgname, argv[opts.optind]);
+ exit(1);
+ }
+
+ if ((n = pmLoadASCIINameSpace(pmnsfile, dupok)) < 0) {
+ fprintf(stderr, "pmLoadNameSpace: %s\n", pmErrStr(n));
+ exit(1);
+ }
+
+ {
+ __pmnsTree *t;
+ t = __pmExportPMNS();
+ if (t == NULL) {
+ /* sanity check - shouldn't ever happen */
+ fprintf(stderr, "%s: Exported PMNS is NULL!\n", pmProgname);
+ exit(1);
+ }
+ root = t->root;
+ htabcnt = t->htabsize;
+ htab = t->htab;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ chktag = "pmLoadASCIINameSpace";
+ traverse(root, chknames);
+ }
+#endif
+
+ traverse(root, pass1);
+
+ _htab = (__pmnsNode **)malloc(htabcnt * sizeof(_htab[0]));
+ _nodetab = (__pmnsNode *)malloc(nodecnt * sizeof(_nodetab[0]));
+ symp = _symbol = (char *)malloc(symbsize);
+ _map = (__pmnsNode **)malloc(nodecnt * sizeof(_map[0]));
+
+ if (_htab == NULL || _nodetab == NULL ||
+ symp == NULL || _map == NULL) {
+ __pmNoMem("pmnscomp", htabcnt * sizeof(_htab[0]) +
+ nodecnt * sizeof(_nodetab[0]) +
+ symbsize +
+ nodecnt * sizeof(_map[0]), PM_FATAL_ERR);
+ }
+
+ i = 0;
+ traverse(root, pass2);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ chktag = "pass2";
+ traverse(root, chknames);
+ }
+#endif
+
+ memcpy(_htab, htab, htabcnt * sizeof(htab[0]));
+ for (j = 0; j < htabcnt; j++)
+ _htab[j] = (__pmnsNode *)nodemap(_htab[j]);
+
+ i = 0;
+ traverse(root, pass3);
+
+ /*
+ * 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[opts.optind], "w+")) == NULL) {
+ fprintf(stderr, "%s: cannot create \"%s\": %s\n",
+ pmProgname, argv[opts.optind], osstrerror());
+ exit(1);
+ }
+
+ /*
+ * Format verisons
+ * 0 PmNs - original PCP 1.0, 32-bit format
+ * 1 PmN1 - PCP 1.1 format with both 32 and 64-bit formats
+ * for MIPS
+ * 2 PmN2 - same as PmN1, but with initial checksum
+ *
+ * Note: all of this must be understood by pmLoadNameSpace() as well
+ */
+ if (version == 0)
+ fprintf(outf, "PmNs");
+ else if (version == 1)
+ fprintf(outf, "PmN1");
+ else if (version == 2)
+ fprintf(outf, "PmN2");
+
+ if (version == 2) {
+ /* dummy at this stage, filled in later */
+ fwrite(&sum, sizeof(sum), 1, outf);
+ startsum = ftell(outf);
+ }
+
+ if(version == 1 || version == 2) {
+ /*
+ * Version 1, after label, comes repetitions of, one for each "style"
+ *
+ * <symbsize> | __int32_t
+ * <_symbol> |
+ * <htabcnt><size of _htab[0]> | style 1, __int32_t
+ * <nodecnt><size of _nodetab[0]> | __int32_t
+ * <_htab>
+ * <_nodetab>
+ * <htabcnt><size of _htab[0]> | style 2, __int32_t
+ * <nodecnt><size of _nodetab[0]> | __int32_t
+ * <_htab>
+ * <_nodetab>
+ * .... | style 3, ...
+ *
+ * Version 2 is similar, except the checksum follows the label,
+ * then as for Version 1.
+ */
+
+ tmp = htonl((__int32_t)symbsize);
+ fwrite(&tmp, sizeof(tmp), 1, outf);
+
+ fwrite(_symbol, sizeof(_symbol[0]), symbsize, outf);
+
+ tmp = htonl((__int32_t)htabcnt);
+ fwrite(&tmp, sizeof(tmp), 1, outf);
+ tmp = htonl((__int32_t)sizeof(_htab32[0]));
+ fwrite(&tmp, sizeof(tmp), 1, outf);
+ tmp = htonl((__int32_t)nodecnt);
+ fwrite(&tmp, sizeof(tmp), 1, outf);
+ tmp = htonl((__int32_t)sizeof(_nodetab32[0]));
+ fwrite(&tmp, sizeof(tmp), 1, outf);
+
+ _htab32 = (__int32_t *)malloc(htabcnt * sizeof(__int32_t));
+ for (j = 0; j < htabcnt; j++)
+ _htab32[j] = to32_htonl(_htab[j]);
+ fwrite(_htab32, sizeof(_htab32[0]), htabcnt, outf);
+ _nodetab32 = (__pmnsNode32 *)malloc(nodecnt * sizeof(__pmnsNode32));
+ for (j = 0; j < nodecnt; j++) {
+ _nodetab32[j].parent = to32_htonl(_nodetab[j].parent);
+ _nodetab32[j].next = to32_htonl(_nodetab[j].next);
+ _nodetab32[j].first = to32_htonl(_nodetab[j].first);
+ _nodetab32[j].hash = to32_htonl(_nodetab[j].hash);
+ _nodetab32[j].name = to32_htonl(_nodetab[j].name);
+ _nodetab32[j].pmid = htonl(_nodetab[j].pmid);
+ }
+ fwrite(_nodetab32, sizeof(_nodetab32[0]), nodecnt, outf);
+
+ tmp = htonl((__int32_t)htabcnt);
+ fwrite(&tmp, sizeof(tmp), 1, outf);
+ tmp = htonl((__int32_t)sizeof(_htab64[0]));
+ fwrite(&tmp, sizeof(tmp), 1, outf);
+ tmp = htonl((__int32_t)nodecnt);
+ fwrite(&tmp, sizeof(tmp), 1, outf);
+ tmp = htonl((__int32_t)sizeof(_nodetab64[0]));
+ fwrite(&tmp, sizeof(tmp), 1, outf);
+
+ _htab64 = (__int64_t *)malloc(htabcnt * sizeof(__int64_t));
+ for (j = 0; j < htabcnt; j++) {
+ /*
+ * Danger ahead ... serious cast games here to convert
+ * 32-bit ptrs to 64-bit integers _with_ sign extension
+ */
+ _htab64[j] = to64_htonll(_htab[j]);
+ }
+ fwrite(_htab64, sizeof(_htab64[0]), htabcnt, outf);
+ _nodetab64 = (__pmnsNode64 *)malloc(nodecnt * sizeof(__pmnsNode64));
+ for (j = 0; j < nodecnt; j++) {
+ /*
+ * Danger ahead ... serious cast games here to convert
+ * 32-bit ptrs to 64-bit integers _with_ sign extension
+ */
+ _nodetab64[j].parent = to64_htonll(_nodetab[j].parent);
+ _nodetab64[j].next = to64_htonll(_nodetab[j].next);
+ _nodetab64[j].first = to64_htonll(_nodetab[j].first);
+ _nodetab64[j].hash = to64_htonll(_nodetab[j].hash);
+ _nodetab64[j].name = to64_htonll(_nodetab[j].name);
+
+ _nodetab64[j].pmid = htonl(_nodetab[j].pmid);
+ _nodetab64[j].__pad__ = htonl(0xdeadbeef);
+ }
+ fwrite(_nodetab64, sizeof(_nodetab64[0]), nodecnt, outf);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ printf("32-bit Header: htab[%d] x %d bytes, nodetab[%d] x %d bytes\n",
+ htabcnt, (int)sizeof(_htab32[0]),
+ nodecnt, (int)sizeof(_nodetab32[0]));
+ printf("\n32-bit Hash Table\n");
+ for (j = 0; j < htabcnt; j++) {
+ if (j % 10 == 0) {
+ if (j)
+ putchar('\n');
+ printf("htab32[%3d]", j);
+ }
+ printf(" %5d", (int)ntohl(_htab32[j]));
+ }
+ printf("\n\n32-bit Node Table\n");
+ for (j = 0; j < nodecnt; j++) {
+ if (j % 20 == 0)
+ printf(" Parent Next First Hash Symbol PMID\n");
+ printf("node32[%4d] %6d %6d %6d %6d %-16.16s",
+ j, (int)ntohl(_nodetab32[j].parent),
+ (int)ntohl(_nodetab32[j].next),
+ (int)ntohl(_nodetab32[j].first),
+ (int)ntohl(_nodetab32[j].hash),
+ _symbol+ntohl(_nodetab32[j].name));
+ if (htonl(_nodetab32[j].first) == -1)
+ printf(" %s", pmIDStr(htonl(_nodetab32[j].pmid)));
+ putchar('\n');
+ }
+ printf("\n64-bit Header: htab[%d] x %d bytes, nodetab[%d] x %d bytes\n",
+ htabcnt, (int)sizeof(_htab64[0]),
+ nodecnt, (int)sizeof(_nodetab64[0]));
+ printf("\n64-bit Hash Table\n");
+ for (j = 0; j < htabcnt; j++) {
+ __int64_t k64 = _htab64[j];
+ if (j % 10 == 0) {
+ if (j)
+ putchar('\n');
+ printf("htab64[%3d]", j);
+ }
+ __ntohll((char *)&k64);
+ printf(" %5" PRIi64, k64);
+ }
+ printf("\n\n64-bit Node Table\n");
+ for (j = 0; j < nodecnt; j++) {
+ __pmnsNode64 t = _nodetab64[j]; /* struct copy */
+
+ if (j % 20 == 0)
+ printf(" Parent Next First Hash Symbol PMID\n");
+
+ __ntohll ((char *)&t.name);
+ __ntohll ((char *)&t.parent);
+ __ntohll ((char *)&t.first);
+ __ntohll ((char *)&t.next);
+ __ntohll ((char *)&t.hash);
+
+ printf("node64[%4d] "
+ "%6" PRIi64 " %6" PRIi64 " %6" PRIi64 " %6" PRIi64
+ " %-16.16s",
+ j, t.parent, t.next, t.first, t.hash, _symbol+t.name);
+ if (t.first == -1) {
+ printf(" %s", pmIDStr(htonl(_nodetab64[j].pmid)));
+ }
+ putchar('\n');
+ }
+ }
+#endif
+ }
+
+ if (version == 2) {
+ fseek(outf, startsum, SEEK_SET);
+ sum = __pmCheckSum(outf);
+ fseek(outf, startsum - (long)sizeof(sum), SEEK_SET);
+ tmp = htonl(sum);
+ fwrite(&tmp, sizeof(sum), 1, outf);
+ }
+
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ if (version == 2)
+ printf("\nChecksum 0x%x\n", sum);
+ printf("\nSymbol Table\n");
+ for (j = 0; j < symbsize; j++) {
+ if (j % 50 == 0) {
+ if (j)
+ putchar('\n');
+ printf("symbol[%4d] ", j);
+ }
+ if (_symbol[j])
+ putchar(_symbol[j]);
+ else
+ putchar('*');
+ }
+ putchar('\n');
+ }
+#endif
+
+ printf("Compiled PMNS contains\n\t%5d hash table entries\n\t%5d leaf nodes\n\t%5d non-leaf nodes\n\t%5d bytes of symbol table\n",
+ htabcnt, leafcnt, nodecnt - leafcnt, symbsize);
+
+ exit(0);
+}