Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / dump-tree.c
1 /*
2  * dump-tree.c --
3  *
4  *      Operations to dump the OID tree in a human readable format.
5  *
6  * Copyright (c) 1999 Frank Strauss, Technical University of Braunschweig.
7  * Copyright (c) 1999 J. Schoenwaelder, Technical University of Braunschweig.
8  * Copyright (c) 2002 J. Schoenwaelder, University of Osnabrueck.
9  *
10  * See the file "COPYING" for information on usage and redistribution
11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12  *
13  * @(#) $Id: dump-tree.c 8090 2008-04-18 12:56:29Z strauss $
14  */
15
16 #include <config.h>
17
18 #include <stdio.h>
19 #include <string.h>
20
21 #include "smi.h"
22 #include "smidump.h"
23
24
25 static int pmodc = 0;
26 static SmiModule **pmodv = NULL;
27
28 static int ignoreconformance = 0;
29 static int ignoreleafs = 0;
30 static int full = 0;
31 static int compact = 0;
32
33 static char *getFlags(SmiNode *smiNode)
34 {
35
36     switch (smiNode->access) {
37     case SMI_ACCESS_UNKNOWN:
38         return "---";
39     case SMI_ACCESS_NOT_ACCESSIBLE:
40         return "---";
41     case SMI_ACCESS_EVENT_ONLY:
42         return "---";
43     case SMI_ACCESS_NOTIFY:
44         return "--n";
45     case SMI_ACCESS_READ_ONLY:
46         return "r-n";
47     case SMI_ACCESS_READ_WRITE:
48         return "rwn";
49     case SMI_ACCESS_NOT_IMPLEMENTED:
50         return "---";
51     case SMI_ACCESS_INSTALL:
52         return "-i-";
53     case SMI_ACCESS_INSTALL_NOTIFY:
54         return "-in";
55     case SMI_ACCESS_REPORT_ONLY:
56         return "--r";
57     }
58
59     return "";
60 }
61
62
63
64 static char getStatusChar(SmiStatus status)
65 {
66     switch (status) {
67     case SMI_STATUS_UNKNOWN:
68         return '+';
69     case SMI_STATUS_CURRENT:
70         return '+';
71     case SMI_STATUS_DEPRECATED:
72         return 'x';
73     case SMI_STATUS_MANDATORY:
74         return '+';
75     case SMI_STATUS_OPTIONAL:
76         return '+';
77     case SMI_STATUS_OBSOLETE:
78         return 'o';
79     }
80
81     return ' ';
82 }
83
84
85
86 static char *getTypeName(SmiNode *smiNode)
87 {
88     char *type;
89     SmiType *smiType, *parentType;
90
91     smiType = smiGetNodeType(smiNode);
92
93     if (!smiType || smiNode->nodekind == SMI_NODEKIND_TABLE)
94         return NULL;
95     
96     if (smiType->decl == SMI_DECL_IMPLICIT_TYPE) {
97         parentType = smiGetParentType(smiType);
98         if (!parentType)
99             return NULL;
100         smiType = parentType;
101     }
102
103     type = xstrdup(smiType->name);
104     return type;
105 }
106
107
108
109 static void fprintIndex(FILE *f, SmiNode *smiNode)
110 {
111     char *indexname;
112     int  i;
113     SmiElement *smiElement;
114     
115     indexname = NULL;
116     for (i = -1, smiElement = smiGetFirstElement(smiNode);
117          smiElement; smiElement = smiGetNextElement(smiElement), i++) {
118         if (i > 0) fprintf(f, ",");
119         if (indexname) {
120             fprintf(f, indexname);
121         }
122         indexname = smiGetElementNode(smiElement)->name;
123     }
124     if (indexname) {
125         fprintf(f, "%s%s%s",
126                 (i > 0) ? "," : "",
127                 (smiNode->implied) ? "*" : "",
128                 indexname);
129     }
130 }
131
132
133
134 static void fprintObjects(FILE *f, SmiNode *smiNode)
135 {
136     char *objectname;
137     int  i;
138     SmiElement *smiElement;
139
140     objectname = NULL;
141     for (i = -1, smiElement = smiGetFirstElement(smiNode);
142          smiElement;
143          smiElement = smiGetNextElement(smiElement), i++) {
144         if (i > 0) fprintf(f, ",");
145         if (objectname) {
146             fprintf(f, objectname);
147         }
148         objectname = smiGetElementNode(smiElement)->name;
149     }
150     if (objectname) {
151         fprintf(f, "%s%s", (i > 0) ? "," : "", objectname);
152     }
153 }
154
155
156
157 static int isPartOfLoadedModules(SmiNode *smiNode)
158 {
159     SmiModule *smiModule;
160     int i;
161     
162     smiModule = smiGetNodeModule(smiNode);
163
164     for (i = 0; i < pmodc; i++) {
165         if (strcmp(pmodv[i]->name, smiModule->name) == 0) {
166             return 1;
167         }
168     }
169     return 0;
170 }
171
172 /*
173  * The following function pruneSubTree() is tricky. There are some
174  * interactions between the supported options. See the detailed
175  * comments below. Good examples to test the implemented behaviour
176  * are:
177  *
178  * smidump -u -f tree --tree-no-leaf IF-MIB ETHER-CHIPSET-MIB
179  *
180  * (And the example above does _not_ work in combination with
181  * --tree-no-conformance so the code below is still broken.)
182  */
183
184 static int pruneSubTree(SmiNode *smiNode)
185 {
186     SmiNode   *childNode;
187
188     const int confmask = (SMI_NODEKIND_GROUP | SMI_NODEKIND_COMPLIANCE);
189     const int leafmask = (SMI_NODEKIND_GROUP | SMI_NODEKIND_COMPLIANCE
190                           | SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR
191                           | SMI_NODEKIND_ROW | SMI_NODEKIND_NOTIFICATION);
192
193     if (! smiNode) {
194         return 1;
195     }
196
197     /*
198      * First, prune all nodes which the user has told us to ignore.
199      * In the case of ignoreleafs, we have to special case nodes with
200      * an unknown status (which actually represent OBJECT-IDENTITY
201      * definitions). More special case code is needed to exclude
202      * module identity nodes.
203      */
204
205     if (ignoreconformance && (smiNode->nodekind & confmask)) {
206         return 1;
207     }
208
209     if (ignoreleafs) {
210         if (smiNode->nodekind & leafmask) {
211             return 1;
212         }
213         if (smiNode->nodekind == SMI_NODEKIND_NODE
214             && smiNode->status != SMI_STATUS_UNKNOWN) {
215             SmiModule *smiModule = smiGetNodeModule(smiNode);
216             if (smiModule && smiNode != smiGetModuleIdentityNode(smiModule)) {
217                 return 1;
218             }
219         }
220     }
221
222     /*
223      * Next, generally do not prune nodes that belong to the set of
224      * modules we are looking at.
225      */
226
227     if (isPartOfLoadedModules(smiNode)) {
228         if (!ignoreconformance || !smiGetFirstChildNode(smiNode)) {
229             return 0;
230         }
231     }
232
233     /*
234      * Finally, prune all nodes where all child nodes are pruned.
235      */
236
237     for (childNode = smiGetFirstChildNode(smiNode);
238          childNode;
239          childNode = smiGetNextChildNode(childNode)) {
240
241         /*
242          * In the case of ignoreleafs, we have to peek at the child
243          * nodes. Otherwise, we would prune too much. we still want to
244          * see the path to the leafs we have pruned away. This also
245          * interact with the semantics of ignoreconformance since we
246          * still want in combination with ignoreleafs to see the path
247          * to the pruned conformance leafs.
248          */
249         
250         if (ignoreleafs && (childNode->nodekind & leafmask)) {
251             if (isPartOfLoadedModules(childNode)) {
252                 if (ignoreconformance && (childNode->nodekind & confmask)) {
253                     return 1;
254                 }
255                 return 0;
256             }
257         }
258  
259         if (! pruneSubTree(childNode)) {
260             return 0;
261         }
262     }
263
264     return 1;
265 }
266
267
268
269 static void fprintSubTree(FILE *f, SmiNode *smiNode,
270                           char *prefix, size_t typefieldlen)
271 {
272     SmiNode     *childNode, *indexNode;
273     SmiNodekind lastNodeKind = SMI_NODEKIND_UNKNOWN;
274     SmiType     *type;
275     int         i = 0, cnt, prefixlen;
276     size_t      newtypefieldlen = 9;
277     char        c = 0;
278     char        *type_name;
279
280     if (smiNode) {
281         prefixlen = strlen(prefix);
282         switch (smiNode->nodekind) {
283         case SMI_NODEKIND_SCALAR:
284         case SMI_NODEKIND_COLUMN:
285             if (prefixlen > 0) {
286                 c = prefix[prefixlen-1];
287                 prefix[prefixlen-1] = getStatusChar(smiNode->status);
288             }
289             type_name = getTypeName(smiNode);
290             if (type_name) {
291                 fprintf(f, "%s-- %s %-*s %s(%u)\n",
292                         prefix,
293                         getFlags(smiNode),
294                         typefieldlen,
295                         type_name,
296                         smiNode->name,
297                         smiNode->oid[smiNode->oidlen-1]);
298                 xfree(type_name);
299             }
300             if (prefixlen > 0 && c) {
301                 prefix[prefixlen-1] = c;
302             }
303             break;
304         case SMI_NODEKIND_ROW:
305             if (prefixlen > 0) {
306                 c = prefix[prefixlen-1];
307                 prefix[prefixlen-1] = getStatusChar(smiNode->status);
308             }
309             fprintf(f, "%s--%s(%u) [", prefix,
310                     smiNode->name,
311                     smiNode->oid[smiNode->oidlen-1]);
312             switch (smiNode->indexkind) {
313             case SMI_INDEX_INDEX:
314             case SMI_INDEX_REORDER:
315                 fprintIndex(f, smiNode);
316                 break;
317             case SMI_INDEX_EXPAND:  /* TODO: we have to do more work here! */
318                 break;
319             case SMI_INDEX_AUGMENT:
320             case SMI_INDEX_SPARSE:
321                 indexNode = smiGetRelatedNode(smiNode);
322                 if (indexNode) {
323                     fprintIndex(f, indexNode);
324                 }
325                 break;
326             case SMI_INDEX_UNKNOWN:
327                 break;      
328             }
329             fprintf(f, "]\n");
330             if (prefixlen > 0 && c) {
331                 prefix[prefixlen-1] = c;
332             }
333             break;
334         case SMI_NODEKIND_NOTIFICATION:
335             if (prefixlen > 0) {
336                 c = prefix[prefixlen-1];
337                 prefix[prefixlen-1] = getStatusChar(smiNode->status);
338             }
339             fprintf(f, "%s--%s(%u) [", prefix,
340                     smiNode->name,
341                     smiNode->oid[smiNode->oidlen-1]);
342             fprintObjects(f, smiNode);
343             fprintf(f, "]\n");
344             if (prefixlen > 0 && c) {
345                 prefix[prefixlen-1] = c;
346             }
347             break;
348         default:
349             if (prefixlen > 0) {
350                 c = prefix[prefixlen-1];
351                 prefix[prefixlen-1] = getStatusChar(smiNode->status);
352             }
353             if (smiNode->oid)
354                 if (prefixlen > 0) {
355                     fprintf(f, "%s--%s(%u)\n", prefix,
356                             smiNode->name ? smiNode->name : " ",
357                             smiNode->oid[smiNode->oidlen-1]);
358                 } else {
359                     unsigned int j;
360                     fprintf(f, "%s--%s(", prefix,
361                             smiNode->name ? smiNode->name : " ");
362                     for (j = 0; j < smiNode->oidlen; j++) {
363                         fprintf(f, "%s%u", j ? "." : "", smiNode->oid[j]);
364                     }
365                     fprintf(f, ")\n");
366                 }
367             else
368                 fprintf(f, "%s--%s(?)\n", prefix,
369                         smiNode->name ? smiNode->name : " ");
370             if (prefixlen > 0 && c) {
371                 prefix[prefixlen-1] = c;
372             }
373         }
374         for (childNode = smiGetFirstChildNode(smiNode), cnt = 0;
375              childNode;
376              childNode = smiGetNextChildNode(childNode)) {
377             if (! pruneSubTree(childNode)) {
378                 type = smiGetNodeType(childNode);
379                 if (type) {
380                     type_name = getTypeName(childNode);
381                     if (type_name) {
382                         if (strlen(type_name) > newtypefieldlen) {
383                             newtypefieldlen = strlen(type_name);
384                         }
385                         xfree(type_name);
386                     }
387                 }
388                 cnt++;
389             }
390         }
391         for (childNode = smiGetFirstChildNode(smiNode);
392              childNode;
393              childNode = smiGetNextChildNode(childNode)) {
394             char *newprefix;
395             if (pruneSubTree(childNode)) {
396                 continue;
397             }
398             i++;
399             if (! compact &&
400                 ((childNode->nodekind != SMI_NODEKIND_COLUMN
401                   && childNode->nodekind != SMI_NODEKIND_SCALAR)
402                  || (lastNodeKind != childNode->nodekind))) {
403                 fprintf(f, "%s  |\n", prefix);
404             }
405             newprefix = xmalloc(strlen(prefix)+10);
406             strcpy(newprefix, prefix);
407             if (cnt == 1 || cnt == i) {
408                 strcat(newprefix, "   ");
409             } else {
410                 strcat(newprefix, "  |");
411             }
412             fprintSubTree(f, childNode, newprefix, newtypefieldlen);
413             xfree(newprefix);
414             lastNodeKind = childNode->nodekind;
415         }
416     }
417 }
418
419
420
421 static void fprintTree(FILE *f)
422 {
423     SmiNode *smiNode;
424     SmiNode *childNode;
425     SmiNode *nextNode;
426     int cnt;
427     
428     smiNode = smiGetNode(NULL, "iso");
429
430     if (! full) {
431         do {
432             for (childNode = smiGetFirstChildNode(smiNode), cnt = 0, nextNode = NULL;
433                  childNode;
434                  childNode = smiGetNextChildNode(childNode)) {
435                 if (! pruneSubTree(childNode)) {
436                     cnt++;
437                     if (! nextNode) {
438                         nextNode = childNode;
439                     }
440                 }
441             }
442             if (cnt == 1) {
443                 smiNode = nextNode;
444             }
445         } while (cnt == 1);
446     }
447     
448     if (smiNode) {
449         fprintSubTree(f, smiNode, "", 0);
450     }
451 }
452
453
454
455 static void dumpTree(int modc, SmiModule **modv, int flags, char *output)
456 {
457     int     i;
458     FILE    *f = stdout;
459     
460     if (output) {
461         f = fopen(output, "w");
462         if (!f) {
463             fprintf(stderr, "smidump: cannot open %s for writing: ", output);
464             perror(NULL);
465             exit(1);
466         }
467     }
468
469     if (flags & SMIDUMP_FLAG_UNITE) {
470         
471         pmodc = modc;
472         pmodv = modv;
473         
474         if (! (flags & SMIDUMP_FLAG_SILENT)) {
475             fprintf(f, "# united registration tree (generated by smidump "
476                     SMI_VERSION_STRING ")\n\n");
477         }
478         if (! (flags & SMIDUMP_FLAG_SILENT) && (flags & SMIDUMP_FLAG_ERROR)) {
479             fprintf(f, "# WARNING: this output may be incorrect due to "
480                     "significant parse errors\n\n");
481         }
482         fprintTree(f);
483         
484     } else {
485
486         for (i = 0; i < modc; i++) {
487
488             pmodc = 1;
489             pmodv = &(modv[i]);
490         
491             if (! (flags & SMIDUMP_FLAG_SILENT)) {
492                 fprintf(f, "# %s registration tree (generated by smidump "
493                         SMI_VERSION_STRING ")\n\n", modv[i]->name);
494             }
495             if (! (flags & SMIDUMP_FLAG_SILENT) && (flags & SMIDUMP_FLAG_ERROR)) {
496                 fprintf(f, "# WARNING: this output may be incorrect due to "
497                         "significant parse errors\n\n");
498             }
499             fprintTree(f);
500         }
501     }
502
503     if (fflush(f) || ferror(f)) {
504         perror("smidump: write error");
505         exit(1);
506     }
507
508     if (output) {
509         fclose(f);
510     }
511 }
512
513
514
515 void initTree()
516 {
517     static SmidumpDriverOption opt[] = {
518         { "no-conformance", OPT_FLAG, &ignoreconformance, 0,
519           "do not show conformance nodes"},
520         { "no-leafs", OPT_FLAG, &ignoreleafs, 0,
521           "do not show leaf nodes"},
522         { "full-root", OPT_FLAG, &full, 0,
523           "generate the full path to the root"},
524         { "compact", OPT_FLAG, &compact, 0,
525           "generate a more compact representation"},
526         { 0, OPT_END, 0, 0 }
527     };
528     
529     static SmidumpDriver driver = {
530         "tree",
531         dumpTree,
532         SMI_FLAG_NODESCR,
533         0,
534         "structure of the OID tree",
535         opt,
536         NULL
537     };
538     
539     smidumpRegisterDriver(&driver);
540 }