diff --git a/tools/dump-tree.c b/tools/dump-tree.c index 3db2265..4c1950f 100644 --- a/tools/dump-tree.c +++ b/tools/dump-tree.c @@ -117,7 +117,7 @@ static void fprintIndex(FILE *f, SmiNode *smiNode) smiElement; smiElement = smiGetNextElement(smiElement), i++) { if (i > 0) fprintf(f, ","); if (indexname) { - fprintf(f, indexname); + fprintf(f, "%s", indexname); } indexname = smiGetElementNode(smiElement)->name; } @@ -143,7 +143,7 @@ static void fprintObjects(FILE *f, SmiNode *smiNode) smiElement = smiGetNextElement(smiElement), i++) { if (i > 0) fprintf(f, ","); if (objectname) { - fprintf(f, objectname); + fprintf(f, "%s", objectname); } objectname = smiGetElementNode(smiElement)->name; } diff --git a/tools/dump-tree.c.format-security b/tools/dump-tree.c.format-security new file mode 100644 index 0000000..3db2265 --- /dev/null +++ b/tools/dump-tree.c.format-security @@ -0,0 +1,540 @@ +/* + * dump-tree.c -- + * + * Operations to dump the OID tree in a human readable format. + * + * Copyright (c) 1999 Frank Strauss, Technical University of Braunschweig. + * Copyright (c) 1999 J. Schoenwaelder, Technical University of Braunschweig. + * Copyright (c) 2002 J. Schoenwaelder, University of Osnabrueck. + * + * See the file "COPYING" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * @(#) $Id: dump-tree.c 8090 2008-04-18 12:56:29Z strauss $ + */ + +#include + +#include +#include + +#include "smi.h" +#include "smidump.h" + + +static int pmodc = 0; +static SmiModule **pmodv = NULL; + +static int ignoreconformance = 0; +static int ignoreleafs = 0; +static int full = 0; +static int compact = 0; + +static char *getFlags(SmiNode *smiNode) +{ + + switch (smiNode->access) { + case SMI_ACCESS_UNKNOWN: + return "---"; + case SMI_ACCESS_NOT_ACCESSIBLE: + return "---"; + case SMI_ACCESS_EVENT_ONLY: + return "---"; + case SMI_ACCESS_NOTIFY: + return "--n"; + case SMI_ACCESS_READ_ONLY: + return "r-n"; + case SMI_ACCESS_READ_WRITE: + return "rwn"; + case SMI_ACCESS_NOT_IMPLEMENTED: + return "---"; + case SMI_ACCESS_INSTALL: + return "-i-"; + case SMI_ACCESS_INSTALL_NOTIFY: + return "-in"; + case SMI_ACCESS_REPORT_ONLY: + return "--r"; + } + + return ""; +} + + + +static char getStatusChar(SmiStatus status) +{ + switch (status) { + case SMI_STATUS_UNKNOWN: + return '+'; + case SMI_STATUS_CURRENT: + return '+'; + case SMI_STATUS_DEPRECATED: + return 'x'; + case SMI_STATUS_MANDATORY: + return '+'; + case SMI_STATUS_OPTIONAL: + return '+'; + case SMI_STATUS_OBSOLETE: + return 'o'; + } + + return ' '; +} + + + +static char *getTypeName(SmiNode *smiNode) +{ + char *type; + SmiType *smiType, *parentType; + + smiType = smiGetNodeType(smiNode); + + if (!smiType || smiNode->nodekind == SMI_NODEKIND_TABLE) + return NULL; + + if (smiType->decl == SMI_DECL_IMPLICIT_TYPE) { + parentType = smiGetParentType(smiType); + if (!parentType) + return NULL; + smiType = parentType; + } + + type = xstrdup(smiType->name); + return type; +} + + + +static void fprintIndex(FILE *f, SmiNode *smiNode) +{ + char *indexname; + int i; + SmiElement *smiElement; + + indexname = NULL; + for (i = -1, smiElement = smiGetFirstElement(smiNode); + smiElement; smiElement = smiGetNextElement(smiElement), i++) { + if (i > 0) fprintf(f, ","); + if (indexname) { + fprintf(f, indexname); + } + indexname = smiGetElementNode(smiElement)->name; + } + if (indexname) { + fprintf(f, "%s%s%s", + (i > 0) ? "," : "", + (smiNode->implied) ? "*" : "", + indexname); + } +} + + + +static void fprintObjects(FILE *f, SmiNode *smiNode) +{ + char *objectname; + int i; + SmiElement *smiElement; + + objectname = NULL; + for (i = -1, smiElement = smiGetFirstElement(smiNode); + smiElement; + smiElement = smiGetNextElement(smiElement), i++) { + if (i > 0) fprintf(f, ","); + if (objectname) { + fprintf(f, objectname); + } + objectname = smiGetElementNode(smiElement)->name; + } + if (objectname) { + fprintf(f, "%s%s", (i > 0) ? "," : "", objectname); + } +} + + + +static int isPartOfLoadedModules(SmiNode *smiNode) +{ + SmiModule *smiModule; + int i; + + smiModule = smiGetNodeModule(smiNode); + + for (i = 0; i < pmodc; i++) { + if (strcmp(pmodv[i]->name, smiModule->name) == 0) { + return 1; + } + } + return 0; +} + +/* + * The following function pruneSubTree() is tricky. There are some + * interactions between the supported options. See the detailed + * comments below. Good examples to test the implemented behaviour + * are: + * + * smidump -u -f tree --tree-no-leaf IF-MIB ETHER-CHIPSET-MIB + * + * (And the example above does _not_ work in combination with + * --tree-no-conformance so the code below is still broken.) + */ + +static int pruneSubTree(SmiNode *smiNode) +{ + SmiNode *childNode; + + const int confmask = (SMI_NODEKIND_GROUP | SMI_NODEKIND_COMPLIANCE); + const int leafmask = (SMI_NODEKIND_GROUP | SMI_NODEKIND_COMPLIANCE + | SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR + | SMI_NODEKIND_ROW | SMI_NODEKIND_NOTIFICATION); + + if (! smiNode) { + return 1; + } + + /* + * First, prune all nodes which the user has told us to ignore. + * In the case of ignoreleafs, we have to special case nodes with + * an unknown status (which actually represent OBJECT-IDENTITY + * definitions). More special case code is needed to exclude + * module identity nodes. + */ + + if (ignoreconformance && (smiNode->nodekind & confmask)) { + return 1; + } + + if (ignoreleafs) { + if (smiNode->nodekind & leafmask) { + return 1; + } + if (smiNode->nodekind == SMI_NODEKIND_NODE + && smiNode->status != SMI_STATUS_UNKNOWN) { + SmiModule *smiModule = smiGetNodeModule(smiNode); + if (smiModule && smiNode != smiGetModuleIdentityNode(smiModule)) { + return 1; + } + } + } + + /* + * Next, generally do not prune nodes that belong to the set of + * modules we are looking at. + */ + + if (isPartOfLoadedModules(smiNode)) { + if (!ignoreconformance || !smiGetFirstChildNode(smiNode)) { + return 0; + } + } + + /* + * Finally, prune all nodes where all child nodes are pruned. + */ + + for (childNode = smiGetFirstChildNode(smiNode); + childNode; + childNode = smiGetNextChildNode(childNode)) { + + /* + * In the case of ignoreleafs, we have to peek at the child + * nodes. Otherwise, we would prune too much. we still want to + * see the path to the leafs we have pruned away. This also + * interact with the semantics of ignoreconformance since we + * still want in combination with ignoreleafs to see the path + * to the pruned conformance leafs. + */ + + if (ignoreleafs && (childNode->nodekind & leafmask)) { + if (isPartOfLoadedModules(childNode)) { + if (ignoreconformance && (childNode->nodekind & confmask)) { + return 1; + } + return 0; + } + } + + if (! pruneSubTree(childNode)) { + return 0; + } + } + + return 1; +} + + + +static void fprintSubTree(FILE *f, SmiNode *smiNode, + char *prefix, size_t typefieldlen) +{ + SmiNode *childNode, *indexNode; + SmiNodekind lastNodeKind = SMI_NODEKIND_UNKNOWN; + SmiType *type; + int i = 0, cnt, prefixlen; + size_t newtypefieldlen = 9; + char c = 0; + char *type_name; + + if (smiNode) { + prefixlen = strlen(prefix); + switch (smiNode->nodekind) { + case SMI_NODEKIND_SCALAR: + case SMI_NODEKIND_COLUMN: + if (prefixlen > 0) { + c = prefix[prefixlen-1]; + prefix[prefixlen-1] = getStatusChar(smiNode->status); + } + type_name = getTypeName(smiNode); + if (type_name) { + fprintf(f, "%s-- %s %-*s %s(%u)\n", + prefix, + getFlags(smiNode), + typefieldlen, + type_name, + smiNode->name, + smiNode->oid[smiNode->oidlen-1]); + xfree(type_name); + } + if (prefixlen > 0 && c) { + prefix[prefixlen-1] = c; + } + break; + case SMI_NODEKIND_ROW: + if (prefixlen > 0) { + c = prefix[prefixlen-1]; + prefix[prefixlen-1] = getStatusChar(smiNode->status); + } + fprintf(f, "%s--%s(%u) [", prefix, + smiNode->name, + smiNode->oid[smiNode->oidlen-1]); + switch (smiNode->indexkind) { + case SMI_INDEX_INDEX: + case SMI_INDEX_REORDER: + fprintIndex(f, smiNode); + break; + case SMI_INDEX_EXPAND: /* TODO: we have to do more work here! */ + break; + case SMI_INDEX_AUGMENT: + case SMI_INDEX_SPARSE: + indexNode = smiGetRelatedNode(smiNode); + if (indexNode) { + fprintIndex(f, indexNode); + } + break; + case SMI_INDEX_UNKNOWN: + break; + } + fprintf(f, "]\n"); + if (prefixlen > 0 && c) { + prefix[prefixlen-1] = c; + } + break; + case SMI_NODEKIND_NOTIFICATION: + if (prefixlen > 0) { + c = prefix[prefixlen-1]; + prefix[prefixlen-1] = getStatusChar(smiNode->status); + } + fprintf(f, "%s--%s(%u) [", prefix, + smiNode->name, + smiNode->oid[smiNode->oidlen-1]); + fprintObjects(f, smiNode); + fprintf(f, "]\n"); + if (prefixlen > 0 && c) { + prefix[prefixlen-1] = c; + } + break; + default: + if (prefixlen > 0) { + c = prefix[prefixlen-1]; + prefix[prefixlen-1] = getStatusChar(smiNode->status); + } + if (smiNode->oid) + if (prefixlen > 0) { + fprintf(f, "%s--%s(%u)\n", prefix, + smiNode->name ? smiNode->name : " ", + smiNode->oid[smiNode->oidlen-1]); + } else { + unsigned int j; + fprintf(f, "%s--%s(", prefix, + smiNode->name ? smiNode->name : " "); + for (j = 0; j < smiNode->oidlen; j++) { + fprintf(f, "%s%u", j ? "." : "", smiNode->oid[j]); + } + fprintf(f, ")\n"); + } + else + fprintf(f, "%s--%s(?)\n", prefix, + smiNode->name ? smiNode->name : " "); + if (prefixlen > 0 && c) { + prefix[prefixlen-1] = c; + } + } + for (childNode = smiGetFirstChildNode(smiNode), cnt = 0; + childNode; + childNode = smiGetNextChildNode(childNode)) { + if (! pruneSubTree(childNode)) { + type = smiGetNodeType(childNode); + if (type) { + type_name = getTypeName(childNode); + if (type_name) { + if (strlen(type_name) > newtypefieldlen) { + newtypefieldlen = strlen(type_name); + } + xfree(type_name); + } + } + cnt++; + } + } + for (childNode = smiGetFirstChildNode(smiNode); + childNode; + childNode = smiGetNextChildNode(childNode)) { + char *newprefix; + if (pruneSubTree(childNode)) { + continue; + } + i++; + if (! compact && + ((childNode->nodekind != SMI_NODEKIND_COLUMN + && childNode->nodekind != SMI_NODEKIND_SCALAR) + || (lastNodeKind != childNode->nodekind))) { + fprintf(f, "%s |\n", prefix); + } + newprefix = xmalloc(strlen(prefix)+10); + strcpy(newprefix, prefix); + if (cnt == 1 || cnt == i) { + strcat(newprefix, " "); + } else { + strcat(newprefix, " |"); + } + fprintSubTree(f, childNode, newprefix, newtypefieldlen); + xfree(newprefix); + lastNodeKind = childNode->nodekind; + } + } +} + + + +static void fprintTree(FILE *f) +{ + SmiNode *smiNode; + SmiNode *childNode; + SmiNode *nextNode; + int cnt; + + smiNode = smiGetNode(NULL, "iso"); + + if (! full) { + do { + for (childNode = smiGetFirstChildNode(smiNode), cnt = 0, nextNode = NULL; + childNode; + childNode = smiGetNextChildNode(childNode)) { + if (! pruneSubTree(childNode)) { + cnt++; + if (! nextNode) { + nextNode = childNode; + } + } + } + if (cnt == 1) { + smiNode = nextNode; + } + } while (cnt == 1); + } + + if (smiNode) { + fprintSubTree(f, smiNode, "", 0); + } +} + + + +static void dumpTree(int modc, SmiModule **modv, int flags, char *output) +{ + int i; + FILE *f = stdout; + + if (output) { + f = fopen(output, "w"); + if (!f) { + fprintf(stderr, "smidump: cannot open %s for writing: ", output); + perror(NULL); + exit(1); + } + } + + if (flags & SMIDUMP_FLAG_UNITE) { + + pmodc = modc; + pmodv = modv; + + if (! (flags & SMIDUMP_FLAG_SILENT)) { + fprintf(f, "# united registration tree (generated by smidump " + SMI_VERSION_STRING ")\n\n"); + } + if (! (flags & SMIDUMP_FLAG_SILENT) && (flags & SMIDUMP_FLAG_ERROR)) { + fprintf(f, "# WARNING: this output may be incorrect due to " + "significant parse errors\n\n"); + } + fprintTree(f); + + } else { + + for (i = 0; i < modc; i++) { + + pmodc = 1; + pmodv = &(modv[i]); + + if (! (flags & SMIDUMP_FLAG_SILENT)) { + fprintf(f, "# %s registration tree (generated by smidump " + SMI_VERSION_STRING ")\n\n", modv[i]->name); + } + if (! (flags & SMIDUMP_FLAG_SILENT) && (flags & SMIDUMP_FLAG_ERROR)) { + fprintf(f, "# WARNING: this output may be incorrect due to " + "significant parse errors\n\n"); + } + fprintTree(f); + } + } + + if (fflush(f) || ferror(f)) { + perror("smidump: write error"); + exit(1); + } + + if (output) { + fclose(f); + } +} + + + +void initTree() +{ + static SmidumpDriverOption opt[] = { + { "no-conformance", OPT_FLAG, &ignoreconformance, 0, + "do not show conformance nodes"}, + { "no-leafs", OPT_FLAG, &ignoreleafs, 0, + "do not show leaf nodes"}, + { "full-root", OPT_FLAG, &full, 0, + "generate the full path to the root"}, + { "compact", OPT_FLAG, &compact, 0, + "generate a more compact representation"}, + { 0, OPT_END, 0, 0 } + }; + + static SmidumpDriver driver = { + "tree", + dumpTree, + SMI_FLAG_NODESCR, + 0, + "structure of the OID tree", + opt, + NULL + }; + + smidumpRegisterDriver(&driver); +}