1 /*
2 * dump-yang.c --
3 *
4 * Operations to dump MIB modules in the YANG output format.
5 *
6 * Copyright (c) 2007 J. Schoenwaelder, Jacobs University Bremen.
7 *
8 * See the file "COPYING" for information on usage and redistribution
9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10 *
11 * @(#) $Id: dump-yang.c 8090 2008-04-18 12:56:29Z strauss $
12 */
13
14 #include <config.h>
15
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <string.h>
19
20 #include "smi.h"
21 #include "smidump.h"
22 #include "fprint.h"
23 #include "fortopat.h"
24
25 /*
26 * TODO:
27 * - reproduce the table comment text as a yang comment
28 * - fix the format strings to xsd pattern algorithm so that it
29 * produces more accurate results
30 * - compute proper boundaries for binary/string length restrictions
31 * - translate notifications properly (whatever that means ;-)
32 * - handle opaque in a reasonable way (test case AGGREGATE-MIB)
33 */
34
35 static int sflag = 0; /* generate smi: extensions */
36 static int nflag = 0; /* generate notifications */
37 static int INDENT = 2; /* indent factor */
38
39 #define INDENTVALUE 20 /* column to start values, except multiline */
40 #define URNBASE "urn:ietf:params:xml:ns:yang:smiv2:"
41
42
43 #define FLAG_CONFIG_FALSE 0x01
44
45
46 static const char *convertType[] = {
47
48 /*
49 * Translation of the SMIng built-in types to the YANG
50 * equivalents.
51 */
52
53 "", "Integer32", NULL, "int32",
54 "", "Integer64", NULL, "int64",
55 "", "Unsigned32", NULL, "uint32",
56 "", "Unsigned64", NULL, "uint64",
57 "", "OctetString", NULL, "binary",
58 "", "Enumeration", NULL, "enumeration",
59 "", "Bits", NULL, "bits",
60 "", "ObjectIdentifier", "yang-types", "object-identifier",
61
62 /*
63 * We want to do these translations as well in order to retire the
64 * SNMPv2-SMI module which is not really an SMIv2 module but part
65 * of the definition of SNMPv2-SMI itself.
66 */
67
68 "SNMPv2-SMI", "Integer32", NULL, "int32",
69 "SNMPv2-SMI", "Integer64", NULL, "int64",
70 "SNMPv2-SMI", "Unsigned32", NULL, "uint32",
71 "SNMPv2-SMI", "Opaque", NULL, "binary",
72 "SNMPv2-SMI", "Counter32", "yang-types", "counter32",
73 "SNMPv2-SMI", "Counter64", "yang-types", "counter64",
74 "SNMPv2-SMI", "Gauge32", "yang-types", "gauge32",
75 "SNMPv2-SMI", "TimeTicks", "yang-types", "timeticks",
76 "SNMPv2-SMI", "IpAddress", "inet-types", "ipv4-address",
77
78 /*
79 * And we like to do the same for RFC1155-SMI definitions...
80 */
81
82 "RFC1155-SMI", "Opaque", NULL, "binary",
83 "RFC1155-SMI", "Counter", "yang-types", "counter32",
84 "RFC1155-SMI", "Gauge", "yang-types", "gauge32",
85 "RFC1155-SMI", "TimeTicks", "yang-types", "timeticks",
86 "RFC1155-SMI", "IpAddress", "inet-types", "ipv4-address",
87
88 /*
89 * We also translate frequently used SNMPv2-TCs that have a YANG
90 * equivalent. Note that DateAndTime is slightly different from
91 * the ISO profile used by date-and-time.
92 */
93
94 "SNMPv2-TC", "PhysAddress", "yang-types", "phys-address",
95 "SNMPv2-TC", "MacAddress", "ieee-types", "mac-address",
96 "SNMPv2-TC", "TimeStamp", "yang-types", "timestamp",
97
98 NULL, NULL, NULL, NULL
99 };
100
101
102 static const char *convertImport[] = {
103
104 /*
105 * Things that are not types but removed from imports...
106 */
107
108 "SNMPv2-SMI", "MODULE-IDENTITY", NULL, NULL,
109 "SNMPv2-SMI", "OBJECT-IDENTITY", NULL, NULL,
110 "SNMPv2-SMI", "OBJECT-TYPE", NULL, NULL,
111 "SNMPv2-SMI", "NOTIFICATION-TYPE", NULL, NULL,
112 "SNMPv2-SMI", "mib-2", NULL, NULL,
113 "SNMPv2-TC", "TEXTUAL-CONVENTION", NULL, NULL,
114 "SNMPv2-CONF", "OBJECT-GROUP", NULL, NULL,
115 "SNMPv2-CONF", "NOTIFICATION-GROUP", NULL, NULL,
116 "SNMPv2-CONF", "MODULE-COMPLIANCE", NULL, NULL,
117 "SNMPv2-CONF", "AGENT-CAPABILITIES", NULL, NULL,
118 "SNMPv2-MIB", "snmpTraps", NULL, NULL,
119
120 NULL, NULL, NULL, NULL
121 };
122
123 /*
124 * SMIv2 modules we never like to import from...
125 */
126
127 static const char *ignoreImports[] = {
128 "RFC1155-SMI", "SNMPv2-SMI", "SNMPv2-CONF", NULL
129 };
130
131
132 /*
133 * Structure used to build a list of imported types.
134 */
135
136 typedef struct Import {
137 char *module;
138 char *prefix;
139 struct Import *nextPtr;
140 } Import;
141
142 static Import *importList = NULL;
143
144 static int silent = 0;
145
146
147 static char*
getStringStatus(SmiStatus status)148 getStringStatus(SmiStatus status)
149 {
150 return
151 (status == SMI_STATUS_CURRENT) ? "current" :
152 (status == SMI_STATUS_DEPRECATED) ? "deprecated" :
153 (status == SMI_STATUS_OBSOLETE) ? "obsolete" :
154 (status == SMI_STATUS_MANDATORY) ? "current" :
155 (status == SMI_STATUS_OPTIONAL) ? "current" :
156 "<unknown>";
157 }
158
159
160 static char*
getStringDate(time_t t)161 getStringDate(time_t t)
162 {
163 static char s[27];
164 struct tm *tm;
165
166 tm = gmtime(&t);
167 sprintf(s, "%04d-%02d-%02d",
168 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
169 return s;
170 }
171
172
173
174 static char*
getValueString(SmiValue * valuePtr,SmiType * typePtr)175 getValueString(SmiValue *valuePtr, SmiType *typePtr)
176 {
177 static char s[1024];
178 char ss[9];
179 int n;
180 unsigned int i;
181 SmiNamedNumber *nn;
182 SmiNode *nodePtr;
183
184 s[0] = 0;
185
186 switch (valuePtr->basetype) {
187 case SMI_BASETYPE_UNSIGNED32:
188 sprintf(s, "%lu", valuePtr->value.unsigned32);
189 break;
190 case SMI_BASETYPE_INTEGER32:
191 sprintf(s, "%ld", valuePtr->value.integer32);
192 break;
193 case SMI_BASETYPE_UNSIGNED64:
194 sprintf(s, UINT64_FORMAT, valuePtr->value.unsigned64);
195 break;
196 case SMI_BASETYPE_INTEGER64:
197 sprintf(s, INT64_FORMAT, valuePtr->value.integer64);
198 break;
199 case SMI_BASETYPE_FLOAT32:
200 case SMI_BASETYPE_FLOAT64:
201 case SMI_BASETYPE_FLOAT128:
202 break;
203 case SMI_BASETYPE_ENUM:
204 for (nn = smiGetFirstNamedNumber(typePtr); nn;
205 nn = smiGetNextNamedNumber(nn)) {
206 if (nn->value.value.unsigned32 == valuePtr->value.unsigned32)
207 break;
208 }
209 if (nn) {
210 sprintf(s, "%s", nn->name);
211 } else {
212 sprintf(s, "%ld", valuePtr->value.integer32);
213 }
214 break;
215 case SMI_BASETYPE_OCTETSTRING:
216 for (i = 0; i < valuePtr->len; i++) {
217 if (!isprint((int)valuePtr->value.ptr[i])) break;
218 }
219 if (i == valuePtr->len) {
220 sprintf(s, "\"%s\"", valuePtr->value.ptr);
221 } else {
222 sprintf(s, "0x%*s", 2 * valuePtr->len, "");
223 for (i=0; i < valuePtr->len; i++) {
224 sprintf(ss, "%02x", valuePtr->value.ptr[i]);
225 strncpy(&s[2+2*i], ss, 2);
226 }
227 }
228 break;
229 case SMI_BASETYPE_BITS:
230 sprintf(s, "(");
231 for (i = 0, n = 0; i < valuePtr->len * 8; i++) {
232 if (valuePtr->value.ptr[i/8] & (1 << i%8)) {
233 if (n)
234 sprintf(&s[strlen(s)], ", ");
235 n++;
236 for (nn = smiGetFirstNamedNumber(typePtr); nn;
237 nn = smiGetNextNamedNumber(nn)) {
238 if (nn->value.value.unsigned32 == i)
239 break;
240 }
241 if (nn) {
242 sprintf(&s[strlen(s)], "%s", nn->name);
243 } else {
244 sprintf(s, "%d", i);
245 }
246 }
247 }
248 sprintf(&s[strlen(s)], ")");
249 break;
250 case SMI_BASETYPE_UNKNOWN:
251 break;
252 case SMI_BASETYPE_POINTER:
253 break;
254 case SMI_BASETYPE_OBJECTIDENTIFIER:
255 nodePtr = smiGetNodeByOID(valuePtr->len, valuePtr->value.oid);
256 if (nodePtr) {
257 sprintf(s, "%s", nodePtr->name);
258 } else {
259 strcpy(s, "");
260 for (i=0; i < valuePtr->len; i++) {
261 if (i) strcat(s, ".");
262 sprintf(&s[strlen(s)], "%u", valuePtr->value.oid[i]);
263 }
264 }
265 break;
266 }
267
268 return s;
269 }
270
271
272 static int
isPrefixUnique(const char * prefix)273 isPrefixUnique(const char *prefix)
274 {
275 Import *import;
276
277 for (import = importList; import; import = import->nextPtr) {
278 if (strcmp(prefix, import->prefix) == 0) {
279 return 0;
280 }
281 }
282
283 return 1;
284 }
285
286
287 static char*
guessNicePrefix(const char * moduleName)288 guessNicePrefix(const char *moduleName)
289 {
290 char *prefix;
291 int i, d;
292
293 char *specials[] = {
294 "yang-smi", "smi",
295 "yang-types", "yang",
296 "inet-types", "inet",
297 "ieee-types", "ieee",
298 "SNMPv2-TC", "smiv2",
299 NULL, NULL
300 };
301
302 for (i = 0; specials[i]; i +=2) {
303 if (strcmp(moduleName, specials[i]) == 0) {
304 if (isPrefixUnique(specials[i+1])) {
305 return xstrdup(specials[i+1]);
306 }
307 }
308 }
309
310 prefix = xstrdup(moduleName);
311 for (i = 0; prefix[i]; i++) {
312 prefix[i] = tolower(prefix[i]);
313 }
314
315 for (i = 0, d = 0; prefix[i]; i++) {
316 if (prefix[i] == '-') {
317 d++;
318 if (d > 1) {
319 prefix[i] = 0;
320 if (isPrefixUnique(prefix)) {
321 return prefix;
322 }
323 prefix[i] = '-';
324 }
325 }
326 }
327
328 return prefix;
329 }
330
331
332 static const char*
getModulePrefix(const char * moduleName)333 getModulePrefix(const char *moduleName)
334 {
335 Import *import;
336 static char *prefix = NULL;
337
338 for (import = importList; import; import = import->nextPtr) {
339 if (strcmp(moduleName, import->module) == 0) {
340 return import->prefix;
341 }
342 }
343
344 if (prefix) xfree(prefix);
345 prefix = guessNicePrefix(moduleName);
346 return prefix;
347 }
348
349
350
351 static Import*
addImport(char * module,char * name)352 addImport(char *module, char *name)
353 {
354 Import **import, *newImport;
355
356 if (!module || !name) {
357 return NULL;
358 }
359
360 for (import = &importList; *import; import = &(*import)->nextPtr) {
361 int c = strcmp((*import)->module, module);
362 if (c == 0) return *import;
363 if (c > 0) break;
364 }
365
366 newImport = xmalloc(sizeof(Import));
367 newImport->module = module;
368 newImport->prefix = guessNicePrefix(module);
369
370 newImport->nextPtr = *import;
371 *import = newImport;
372
373 return *import;
374 }
375
376
377
378 static void
createImportList(SmiModule * smiModule)379 createImportList(SmiModule *smiModule)
380 {
381 SmiImport *smiImport;
382 SmiIdentifier impModule, impName;
383 SmiType *smiType;
384 SmiNode *smiNode;
385 int i;
386
387 for (smiImport = smiGetFirstImport(smiModule); smiImport;
388 smiImport = smiGetNextImport(smiImport)) {
389
390 impModule = smiImport->module;
391 impName = smiImport->name;
392
393 for (i = 0; convertType[i]; i += 4) {
394 if (strcmp(smiImport->module, convertType[i]) == 0
395 && strcmp(smiImport->name, convertType[i+1]) == 0) {
396 impModule = (SmiIdentifier) convertType[i+2];
397 impName = (SmiIdentifier) convertType[i+3];
398 break;
399 }
400 }
401
402 if (! impModule || ! impName) continue;
403
404 for (i = 0; convertImport[i]; i += 4) {
405 if (strcmp(smiImport->module, convertImport[i]) == 0
406 && strcmp(smiImport->name, convertImport[i+1]) == 0) {
407 impModule = (SmiIdentifier) convertImport[i+2];
408 impName = (SmiIdentifier) convertImport[i+3];
409 break;
410 }
411 }
412
413 if (! impModule || ! impName) continue;
414 #if 0
415 fprintf(stderr, "%s\t%s\n", impModule, impName);
416 #endif
417 addImport(impModule, impName);
418 }
419
420 /*
421 * Add import for the smi:oid extension and friends.
422 */
423
424 if (sflag) {
425 addImport("yang-smi", "oid");
426 }
427
428 /*
429 * Add import for yang-types that were originally ASN.1
430 * builtins...
431 */
432
433 for (smiType = smiGetFirstType(smiModule);
434 smiType; smiType = smiGetNextType(smiType)) {
435 SmiType *parentType = smiGetParentType(smiType);
436 if (parentType && strcmp(parentType->name, "ObjectIdentifier") == 0) {
437 addImport("yang-types", "object-identifier");
438 }
439 }
440
441 for (smiNode = smiGetFirstNode(smiModule,
442 SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN);
443 smiNode;
444 smiNode = smiGetNextNode(smiNode,
445 SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN)) {
446 smiType = smiGetNodeType(smiNode);
447 if (! smiType->name) {
448 smiType = smiGetParentType(smiType);
449 }
450 if (smiType && strcmp(smiType->name, "ObjectIdentifier") == 0) {
451 addImport("yang-types", "object-identifier");
452 }
453 }
454 }
455
456
457
458 static void
freeImportList(void)459 freeImportList(void)
460 {
461 Import *import, *freeme;
462
463 for (import = importList; import; ) {
464 xfree(import->prefix);
465 freeme = import;
466 import = import->nextPtr;
467 xfree(freeme);
468 }
469 importList = NULL;
470 }
471
472
473
474 static int
isGroup(SmiNode * smiNode)475 isGroup(SmiNode *smiNode)
476 {
477 SmiNode *childNode;
478
479 for(childNode = smiGetFirstChildNode(smiNode);
480 childNode;
481 childNode = smiGetNextChildNode(childNode)) {
482 if ((childNode->nodekind == SMI_NODEKIND_SCALAR
483 || childNode->nodekind == SMI_NODEKIND_TABLE)
484 && childNode->status == SMI_STATUS_CURRENT) {
485 return 1;
486 }
487 }
488
489 return 0;
490 }
491
492
493 static int
isIndex(SmiNode * groupNode,SmiNode * smiNode)494 isIndex(SmiNode *groupNode, SmiNode *smiNode)
495 {
496 SmiElement *smiElement;
497 int cnt = 0;
498
499 /*
500 * We return an indication whether smiNode is part of an index. In
501 * fact, we return number of times smiNode is part of an index
502 * since we sometimes have to disambiguate names...
503 */
504
505 for (smiElement = smiGetFirstElement(groupNode);
506 smiElement; smiElement = smiGetNextElement(smiElement)) {
507 if (smiNode == smiGetElementNode(smiElement)) {
508 cnt++;
509 }
510 }
511
512 return cnt;
513 }
514
515
516 static void
fprintRevisions(FILE * f,int indent,SmiModule * smiModule)517 fprintRevisions(FILE *f, int indent, SmiModule *smiModule)
518 {
519 int i;
520 SmiRevision *smiRevision;
521
522 for(i = 0, smiRevision = smiGetFirstRevision(smiModule);
523 smiRevision; smiRevision = smiGetNextRevision(smiRevision)) {
524 fprintSegment(f, indent, "revision ", 0);
525 fprint(f, "\"%s\" {\n", getStringDate(smiRevision->date));
526 fprintSegment(f, 2 * indent, "description", INDENTVALUE);
527 fprint(f, "\n");
528 fprintMultilineString(f, 2 * indent, smiRevision->description);
529 fprint(f, ";\n");
530 fprintSegment(f, indent, "}\n", 0);
531 i++;
532 }
533 if (i) {
534 fprint(f, "\n");
535 }
536 }
537
538
539 static void
fprintImports(FILE * f,SmiModule * smiModule)540 fprintImports(FILE *f, SmiModule *smiModule)
541 {
542 Import *import;
543 int i, len = 4;
544
545 for (import = importList; import; import = import->nextPtr) {
546 for (i = 0; ignoreImports[i]; i++) {
547 if (strcmp(ignoreImports[i], import->module) == 0) {
548 break;
549 }
550 }
551 if (ignoreImports[i] == NULL) {
552 if (strlen(import->module) > len) len = strlen(import->module);
553 }
554 }
555
556 for (import = importList; import; import = import->nextPtr) {
557 for (i = 0; ignoreImports[i]; i++) {
558 if (strcmp(ignoreImports[i], import->module) == 0) {
559 break;
560 }
561 }
562 if (ignoreImports[i] == NULL) {
563 fprintSegment(f, INDENT, "import", 0);
564 fprint(f, " %-*s { prefix \"%s\"; }\n", len,
565 import->module, import->prefix);
566 }
567 }
568 fprint(f, "\n");
569
570 }
571
572
573
574
575 static void
fprintSubtype(FILE * f,int indent,SmiType * smiType)576 fprintSubtype(FILE *f, int indent, SmiType *smiType)
577 {
578 SmiRange *range;
579 SmiNamedNumber *nn;
580 char s[1024];
581 char *tkw, *lkw, *vkw;
582 int i = 0;
583 int len = 4;
584
585 if ((smiType->basetype == SMI_BASETYPE_ENUM) ||
586 (smiType->basetype == SMI_BASETYPE_BITS)) {
587 for (nn = smiGetFirstNamedNumber(smiType);
588 nn ; nn = smiGetNextNamedNumber(nn)) {
589 if (strlen(nn->name) > len) len = strlen(nn->name);
590 }
591
592 for(i = 0, nn = smiGetFirstNamedNumber(smiType);
593 nn ; i++, nn = smiGetNextNamedNumber(nn)) {
594 if (! i) {
595 fprint(f, " {\n");
596 }
597 tkw = (smiType->basetype == SMI_BASETYPE_BITS) ? "bits" : "enumeration";
598 lkw = (smiType->basetype == SMI_BASETYPE_BITS) ? "bit" : "enum";
599 vkw = (smiType->basetype == SMI_BASETYPE_BITS) ? "position" : "value";
600 sprintf(s, "%s %-*s { %s %s; }\n",
601 lkw, len, nn->name,
602 vkw, getValueString(&nn->value, smiType));
603 fprintSegment(f, indent + INDENT, s, 0);
604 }
605 } else {
606 for(i = 0, range = smiGetFirstRange(smiType);
607 range ; i++, range = smiGetNextRange(range)) {
608 if (i) {
609 fprint(f, " | ");
610 } else {
611 fprint(f, " {\n");
612 if (smiType->basetype == SMI_BASETYPE_OCTETSTRING) {
613 fprintSegment(f, indent + INDENT, "length \"", 0);
614 } else {
615 fprintSegment(f, indent + INDENT, "range \"", 0);
616 }
617 }
618 if (memcmp(&range->minValue, &range->maxValue,
619 sizeof(SmiValue))) {
620 sprintf(s, "%s", getValueString(&range->minValue, smiType));
621 sprintf(&s[strlen(s)], "..%s",
622 getValueString(&range->maxValue, smiType));
623 } else {
624 sprintf(s, "%s", getValueString(&range->minValue, smiType));
625 }
626 fprint(f, s);
627 }
628 if (i) {
629 fprint(f, "\";\n");
630 }
631 }
632
633 if (smiType->format
634 && smiType->basetype == SMI_BASETYPE_OCTETSTRING) {
635
636 char *pattern;
637 pattern = smiFormatToPattern(smiType->format,
638 smiGetFirstRange(smiType));
639 if (pattern) {
640 if (! i) {
641 fprint(f, "{\n");
642 }
643 fprintSegment(f, indent + INDENT, "pattern \"", 0);
644 fprint(f, "%s\";\n", pattern);
645 xfree(pattern);
646 i++;
647 }
648 }
649
650 if (! i) {
651 fprint(f, ";\n");
652 } else {
653 fprintSegment(f, indent, "}\n", 0);
654 }
655 }
656
657
658 static void
fprintStatus(FILE * f,int indent,SmiStatus status)659 fprintStatus(FILE *f, int indent, SmiStatus status)
660 {
661 if ((status != SMI_STATUS_CURRENT) &&
662 (status != SMI_STATUS_UNKNOWN) &&
663 (status != SMI_STATUS_MANDATORY) &&
664 (status != SMI_STATUS_OPTIONAL)) {
665 fprintSegment(f, indent, "status", 0);
666 fprint(f, " %s;\n", getStringStatus(status));
667 }
668 }
669
670
671 static void
fprintUnits(FILE * f,int indent,const char * units)672 fprintUnits(FILE *f, int indent, const char *units)
673 {
674 if (units) {
675 fprintSegment(f, indent, "units", 0);
676 fprint(f, " \"%s\";\n", units);
677 }
678 }
679
680
681 static void
fprintFormat(FILE * f,int indent,const char * format)682 fprintFormat(FILE *f, int indent, const char *format)
683 {
684 if (sflag && format) {
685 fprintSegment(f, 2 * INDENT, "smi:display-hint", 0);
686 fprint(f, " \"%s\";\n", format);
687 }
688 }
689
690
691 static void
fprintObjectIdentifier(FILE * f,int indent,SmiSubid * oid,int oidlen)692 fprintObjectIdentifier(FILE *f, int indent, SmiSubid *oid, int oidlen)
693 {
694 int i;
695
696 if (sflag && oid && oidlen) {
697 fprintSegment(f, indent, "smi:oid", 0);
698 fprint(f, " \"");
699 for (i=0; i < oidlen; i++) {
700 fprint(f, "%s%d", i ? "." : "", oid[i]);
701 }
702 fprint(f, "\";\n");
703 }
704 }
705
706
707 static void
fprintDescription(FILE * f,int indent,const char * description)708 fprintDescription(FILE *f, int indent, const char *description)
709 {
710 if (description) {
711 fprintSegment(f, indent, "description", INDENTVALUE);
712 fprint(f, "\n");
713 fprintMultilineString(f, indent, description);
714 fprint(f, ";\n");
715 }
716 }
717
718
719 static void
fprintReference(FILE * f,int indent,const char * reference)720 fprintReference(FILE *f, int indent, const char *reference)
721 {
722 if (reference) {
723 fprintSegment(f, indent, "reference", INDENTVALUE);
724 fprint(f, "\n");
725 fprintMultilineString(f, indent, reference);
726 fprint(f, ";\n");
727 }
728 }
729
730
731 static void
fprintConfig(FILE * f,int indent,SmiAccess access)732 fprintConfig(FILE *f, int indent, SmiAccess access)
733 {
734 if (access == SMI_ACCESS_READ_WRITE) {
735 fprintSegment(f, indent, "config true;\n", 0);
736 } else {
737 fprintSegment(f, indent, "config false;\n", 0);
738 }
739 }
740
741
742 static void
fprintDefault(FILE * f,int indent,SmiValue * value,SmiType * smiType)743 fprintDefault(FILE *f, int indent, SmiValue *value, SmiType *smiType)
744 {
745 if (sflag && value->basetype != SMI_BASETYPE_UNKNOWN) {
746 fprintSegment(f, indent, "smi:default", 0);
747 fprint(f, " \"%s\";\n", getValueString(value, smiType));
748 }
749 }
750
751
752 static int
fprintTypename(FILE * f,SmiType * smiType,int format)753 fprintTypename(FILE *f, SmiType *smiType, int format)
754 {
755 const char *typeModule = NULL, *typeName = NULL;
756 SmiModule *smiModule;
757 int i;
758
759 if (! smiType) return 0;
760
761 smiModule = smiGetTypeModule(smiType);
762
763 if (smiType && ! smiType->name) {
764 return fprintTypename(f, smiGetParentType(smiType), format);
765 }
766
767 for (i = 0; convertType[i]; i += 4) {
768 if (strcmp(smiModule->name, convertType[i]) == 0
769 && strcmp(smiType->name, convertType[i+1]) == 0) {
770 typeModule = convertType[i+2];
771 typeName = convertType[i+3];
772 break;
773 }
774 }
775
776 if (! typeName) {
777 typeModule = smiModule->name;
778 typeName = smiType->name;
779 }
780
781 if (typeModule) {
782 typeModule = getModulePrefix(typeModule);
783 }
784
785 /*
786 * We handle a special case here. If we have a format string and
787 * the type is binary, we turn it into string.
788 */
789
790 if (! typeModule && typeName && strcmp(typeName, "binary") == 0) {
791 if (format) {
792 typeName = "string";
793 }
794 }
795
796 if (typeModule && typeName) {
797 fprint(f, "%s:%s", typeModule, typeName);
798 } else {
799 fprint(f, "%s", typeName);
800 }
801
802 return 1;
803 }
804
805
806 static void
fprintTypedefs(FILE * f,SmiModule * smiModule)807 fprintTypedefs(FILE *f, SmiModule *smiModule)
808 {
809 int i;
810 SmiType *smiType, *baseType;
811
812 for (i = 0, smiType = smiGetFirstType(smiModule);
813 smiType; smiType = smiGetNextType(smiType)) {
814
815 baseType = smiGetParentType(smiType);
816
817 if (!i && !silent) {
818 fprintSegment(f, INDENT, "/*** TYPE DEFINITIONS ***/\n\n", 0);
819 }
820 fprintSegment(f, INDENT, "", 0);
821 fprint(f, "typedef %s {\n", smiType->name);
822
823 fprintSegment(f, 2 * INDENT, "type ", 0);
824 fprintTypename(f, baseType, smiType->format != NULL);
825 fprintSubtype(f, 2 * INDENT, smiType);
826
827 fprintUnits(f, 2 * INDENT, smiType->units);
828 fprintStatus(f, 2 * INDENT, smiType->status);
829 fprintDescription(f, 2 * INDENT, smiType->description);
830 fprintReference(f, 2 * INDENT, smiType->reference);
831 fprintFormat(f, 2 * INDENT, smiType->format);
832 fprintDefault(f, 2 * INDENT, &smiType->value, smiType);
833
834 fprintSegment(f, INDENT, "}\n\n", 0);
835 i++;
836 }
837 }
838
839
840 static void
fprintPath(FILE * f,SmiNode * smiNode)841 fprintPath(FILE *f, SmiNode *smiNode)
842 {
843 SmiNode *entryNode = NULL;
844 SmiNode *tableNode = NULL;
845 SmiNode *contNode = NULL;
846 SmiModule *smiModule = NULL;
847
848 switch (smiNode->nodekind) {
849 case SMI_NODEKIND_SCALAR:
850 contNode = smiGetParentNode(smiNode);
851 break;
852 case SMI_NODEKIND_COLUMN:
853 entryNode = smiGetParentNode(smiNode);
854 tableNode = smiGetParentNode(entryNode);
855 contNode = smiGetParentNode(tableNode);
856 break;
857 case SMI_NODEKIND_ROW:
858 entryNode = smiNode;
859 tableNode = smiGetParentNode(entryNode);
860 contNode = smiGetParentNode(tableNode);
861 break;
862 case SMI_NODEKIND_TABLE:
863 contNode = smiGetParentNode(tableNode);
864 break;
865 default:
866 break;
867 }
868
869 smiModule = smiGetNodeModule(contNode);
870 if (smiModule) {
871 fprint(f, "/%s:%s", getModulePrefix(smiModule->name), contNode->name);
872 }
873 if (contNode == smiNode) return;
874
875 if (entryNode) {
876 smiModule = smiGetNodeModule(entryNode);
877 if (smiModule) {
878 fprint(f, "/%s:%s", getModulePrefix(smiModule->name), entryNode->name);
879 }
880 if (entryNode == smiNode) return;
881 }
882
883 smiModule = smiGetNodeModule(smiNode);
884 if (smiModule) {
885 fprint(f, "/%s:%s", getModulePrefix(smiModule->name), smiNode->name);
886 }
887 }
888
889
890 static void
fprintLeaf(FILE * f,int indent,SmiNode * smiNode,int flags)891 fprintLeaf(FILE *f, int indent, SmiNode *smiNode, int flags)
892 {
893 SmiType *smiType;
894 SmiAccess config;
895
896 smiType = smiGetNodeType(smiNode);
897
898 fprintSegment(f, indent, "leaf ", 0);
899 fprint(f, "%s {\n", smiNode->name);
900
901 fprintSegment(f, indent + INDENT, "type ", 0);
902 fprintTypename(f, smiType, smiNode->format != NULL);
903 if (! smiType->name) {
904 fprintSubtype(f, indent + INDENT, smiType);
905 } else {
906 fprint(f, ";\n");
907 }
908
909 fprintUnits(f, indent + INDENT, smiNode->units);
910 if (flags & FLAG_CONFIG_FALSE) {
911 config = SMI_ACCESS_READ_ONLY;
912 } else {
913 config = smiNode->access;
914 }
915 fprintConfig(f, indent + INDENT, config);
916 fprintStatus(f, indent + INDENT, smiNode->status);
917 fprintDescription(f, indent + INDENT, smiNode->description);
918 fprintReference(f, indent + INDENT, smiNode->reference);
919 fprintFormat(f, indent + INDENT, smiNode->format);
920 fprintDefault(f, indent + INDENT, &smiNode->value, smiType);
921 fprintObjectIdentifier(f, indent + INDENT, smiNode->oid, smiNode->oidlen);
922 fprintSegment(f, indent, "}\n", 0);
923 }
924
925
926 static void
fprintKeyrefLeaf(FILE * f,int indent,SmiNode * smiNode,int flags)927 fprintKeyrefLeaf(FILE *f, int indent, SmiNode *smiNode, int flags)
928 {
929 SmiNode *entryNode;
930 SmiAccess config;
931
932 entryNode = smiGetParentNode(smiNode);
933 fprintSegment(f, indent, "leaf ", 0);
934 fprint(f, "%s {\n", smiNode->name);
935 fprintSegment(f, indent + INDENT, "type keyref {\n", 0);
936 fprintSegment(f, indent + 2 * INDENT, "path \"", 0);
937 fprintPath(f, smiNode);
938 fprint(f, "\";\n");
939 fprintSegment(f, indent + INDENT, "}\n", 0);
940 if (flags & FLAG_CONFIG_FALSE) {
941 config = SMI_ACCESS_READ_ONLY;
942 } else {
943 config = entryNode->create
944 ? SMI_ACCESS_READ_WRITE : SMI_ACCESS_READ_ONLY;
945 }
946 fprintConfig(f, indent + INDENT, config);
947 fprintStatus(f, indent + INDENT, smiNode->status);
948 fprintDescription(f, indent + INDENT,
949 "Automagically generated keyref leaf.");
950 fprintSegment(f, indent, "}\n", 0);
951 }
952
953
954 static void
fprintKey(FILE * f,int indent,SmiNode * smiNode)955 fprintKey(FILE *f, int indent, SmiNode *smiNode)
956 {
957 SmiElement *smiElement;
958 int j;
959
960 fprintSegment(f, indent, "key \"", 0);
961
962 for (j = 0, smiElement = smiGetFirstElement(smiNode); smiElement;
963 j++, smiElement = smiGetNextElement(smiElement)) {
964 if (j) {
965 fprint(f, " ");
966 }
967 fprintWrapped(f, indent + 5,
968 smiGetElementNode(smiElement)->name);
969 }
970 fprint(f, "\";\n");
971 }
972
973
974 static void
fprintLeafs(FILE * f,int indent,SmiNode * smiNode)975 fprintLeafs(FILE *f, int indent, SmiNode *smiNode)
976 {
977 SmiNode *childNode;
978 int c;
979
980 for (c = 0, childNode = smiGetFirstChildNode(smiNode);
981 childNode;
982 childNode = smiGetNextChildNode(childNode)) {
983 if (childNode->nodekind == SMI_NODEKIND_COLUMN) {
984 fprint(f, "\n");
985 fprintLeaf(f, indent, childNode, 0);
986 c++;
987 }
988 }
989 }
990
991
992 static void
fprintList(FILE * f,int indent,SmiNode * smiNode)993 fprintList(FILE *f, int indent, SmiNode *smiNode)
994 {
995 SmiNode *entryNode;
996 SmiNode *childNode;
997 SmiNode *parentNode;
998 SmiElement *smiElement;
999
1000 entryNode = smiGetFirstChildNode(smiNode);
1001
1002 fprint(f, "\n");
1003 fprintSegment(f, indent, "/* XXX table comments here XXX */\n", 0);
1004 fprint(f, "\n");
1005
1006 fprintSegment(f, indent, "list", 0);
1007 fprint(f, " %s {\n\n", entryNode->name);
1008
1009 fprintKey(f, indent + INDENT, entryNode);
1010 fprintStatus(f, indent + INDENT, entryNode->status);
1011 fprintDescription(f, indent + INDENT, entryNode->description);
1012 fprintReference(f, indent + INDENT, entryNode->reference);
1013 fprintObjectIdentifier(f, indent + INDENT,
1014 entryNode->oid, entryNode->oidlen);
1015 fprint(f, "\n");
1016
1017 for (smiElement = smiGetFirstElement(entryNode); smiElement;
1018 smiElement = smiGetNextElement(smiElement)) {
1019 childNode = smiGetElementNode(smiElement);
1020 parentNode = smiGetParentNode(childNode);
1021 if (childNode->nodekind == SMI_NODEKIND_COLUMN
1022 && parentNode != entryNode) {
1023 fprintKeyrefLeaf(f, indent + INDENT, childNode, 0);
1024 }
1025 }
1026
1027 fprintLeafs(f, indent + INDENT, entryNode);
1028
1029 fprintSegment(f, indent, "}\n", 0);
1030 }
1031
1032
1033 static void
fprintAugment(FILE * f,int indent,SmiNode * smiNode)1034 fprintAugment(FILE *f, int indent, SmiNode *smiNode)
1035 {
1036 SmiNode *baseEntryNode = NULL;
1037
1038 if (smiNode) {
1039 baseEntryNode = smiGetRelatedNode(smiNode);
1040 }
1041 if (! smiNode || ! baseEntryNode) {
1042 return;
1043 }
1044
1045 fprint(f, "\n");
1046 fprintSegment(f, indent, "/* XXX table comments here XXX */\n", 0);
1047 fprint(f, "\n");
1048
1049 fprintSegment(f, indent, "augment", 0);
1050 fprint(f, " \"");
1051 fprintPath(f, baseEntryNode);
1052 fprint(f, "\" {\n");
1053 fprintStatus(f, indent + INDENT, smiNode->status);
1054 fprintDescription(f, indent + INDENT, smiNode->description);
1055 fprintReference(f, indent + INDENT, smiNode->reference);
1056
1057 fprintLeafs(f, indent + INDENT, smiNode);
1058 fprintObjectIdentifier(f, indent + INDENT,
1059 smiNode->oid, smiNode->oidlen);
1060 fprintSegment(f, indent, "}\n\n", 0);
1061 }
1062
1063
1064 static void
fprintAugments(FILE * f,SmiModule * smiModule)1065 fprintAugments(FILE *f, SmiModule *smiModule)
1066 {
1067 SmiNode *smiNode;
1068
1069 for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
1070 smiNode;
1071 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
1072 if (smiNode->nodekind == SMI_NODEKIND_ROW
1073 && smiNode->indexkind == SMI_INDEX_AUGMENT) {
1074 fprintAugment(f, INDENT, smiNode);
1075 }
1076 }
1077
1078 }
1079
1080
1081 static void
fprintContainer(FILE * f,int indent,SmiNode * smiNode)1082 fprintContainer(FILE *f, int indent, SmiNode *smiNode)
1083 {
1084 SmiNode *childNode;
1085 int c;
1086
1087 fprintSegment(f, indent, "container", 0);
1088 fprint(f, " %s {\n\n", smiNode->name);
1089
1090 for (c = 0, childNode = smiGetFirstChildNode(smiNode);
1091 childNode;
1092 childNode = smiGetNextChildNode(childNode)) {
1093 if (c) {
1094 fprint(f, "\n");
1095 }
1096 if (childNode->nodekind == SMI_NODEKIND_SCALAR) {
1097 fprintLeaf(f, indent + INDENT, childNode, 0);
1098 c++;
1099 }
1100 if (childNode->nodekind == SMI_NODEKIND_TABLE) {
1101 SmiNode *entryNode = smiGetFirstChildNode(childNode);
1102 if (entryNode) {
1103 switch (entryNode->indexkind) {
1104 case SMI_INDEX_INDEX:
1105 case SMI_INDEX_REORDER:
1106 case SMI_INDEX_SPARSE:
1107 case SMI_INDEX_EXPAND:
1108 fprintList(f, indent + INDENT, childNode);
1109 c++;
1110 break;
1111 #if 0
1112 case SMI_INDEX_AUGMENT:
1113 fprintAugment(f, indent + INDENT, childNode);
1114 c++;
1115 break;
1116 #endif
1117 default:
1118 break;
1119 }
1120 }
1121 }
1122 }
1123
1124 fprintObjectIdentifier(f, indent + INDENT,
1125 smiNode->oid, smiNode->oidlen);
1126
1127 fprintSegment(f, indent, "}\n\n", 0);
1128 }
1129
1130
1131 static void
fprintContainers(FILE * f,SmiModule * smiModule)1132 fprintContainers(FILE *f, SmiModule *smiModule)
1133 {
1134 SmiNode *smiNode;
1135
1136 for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
1137 smiNode;
1138 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
1139 if (isGroup(smiNode)) {
1140 fprintContainer(f, INDENT, smiNode);
1141 }
1142 }
1143 }
1144
1145
1146 static void
fprintNamespace(FILE * f,int indent,SmiModule * smiModule)1147 fprintNamespace(FILE *f, int indent, SmiModule *smiModule)
1148 {
1149 if (! silent) {
1150 fprintSegment(f, indent, "/*** NAMESPACE / PREFIX DEFINITION ***/\n\n", 0);
1151 }
1152
1153 fprintSegment(f, indent, "namespace ", 0);
1154 fprint(f, "\"%s%s\";\n", URNBASE, smiModule->name);
1155 fprintSegment(f, indent, "prefix ", 0);
1156 fprint(f, "\"%s\";\n\n", getModulePrefix(smiModule->name));
1157 }
1158
1159
1160 static void
fprintLinkage(FILE * f,int indent,SmiModule * smiModule)1161 fprintLinkage(FILE *f, int indent, SmiModule *smiModule)
1162 {
1163 if (! silent) {
1164 fprintSegment(f, indent, "/*** LINKAGE (IMPORTS / INCLUDES) ***/\n\n", 0);
1165 }
1166 fprintImports(f, smiModule);
1167 }
1168
1169
1170 static void
fprintMeta(FILE * f,int indent,SmiModule * smiModule)1171 fprintMeta(FILE *f, int indent, SmiModule *smiModule)
1172 {
1173 if (! silent) {
1174 fprintSegment(f, indent, "/*** META INFORMATION ***/\n\n", 0);
1175 }
1176 fprintSegment(f, indent, "organization", INDENTVALUE);
1177 fprint(f, "\n");
1178 fprintMultilineString(f, indent, smiModule->organization);
1179 fprint(f, ";\n\n");
1180 fprintSegment(f, indent, "contact", INDENTVALUE);
1181 fprint(f, "\n");
1182 fprintMultilineString(f, indent, smiModule->contactinfo);
1183 fprint(f, ";\n\n");
1184 fprintSegment(f, indent, "description", INDENTVALUE);
1185 fprint(f, "\n");
1186 fprintMultilineString(f, indent, smiModule->description);
1187 fprint(f, ";\n\n");
1188 if (smiModule->reference) {
1189 fprintSegment(f, indent, "reference", INDENTVALUE);
1190 fprint(f, "\n");
1191 fprintMultilineString(f, indent, smiModule->reference);
1192 fprint(f, ";\n\n");
1193 }
1194 }
1195
1196
1197 static void
fprintNotificationIndex(FILE * f,int indent,SmiNode * entryNode,SmiNode * ignoreNode)1198 fprintNotificationIndex(FILE *f, int indent,
1199 SmiNode *entryNode, SmiNode *ignoreNode)
1200 {
1201 SmiElement *smiElement;
1202 SmiNode *childNode;
1203 SmiNode *parentNode;
1204
1205 for (smiElement = smiGetFirstElement(entryNode); smiElement;
1206 smiElement = smiGetNextElement(smiElement)) {
1207 childNode = smiGetElementNode(smiElement);
1208 parentNode = smiGetParentNode(childNode);
1209 if (childNode != ignoreNode) {
1210 fprintKeyrefLeaf(f, indent, childNode, FLAG_CONFIG_FALSE);
1211 }
1212 }
1213 }
1214
1215
1216 static int
GetPosition(SmiElement * startElement,SmiElement * thisElement)1217 GetPosition(SmiElement *startElement, SmiElement *thisElement)
1218 {
1219 SmiElement *smiElement;
1220 SmiNode *smiNode;
1221 SmiNode *thisNode = smiGetElementNode(thisElement);
1222 int cnt = 0;
1223
1224 for (smiElement = startElement, cnt = 0;
1225 smiElement; smiElement = smiGetNextElement(smiElement)) {
1226 smiNode = smiGetElementNode(smiElement);
1227 if (smiNode == thisNode) cnt++;
1228 }
1229
1230 if (cnt <= 1) {
1231 return 0;
1232 }
1233
1234 for (smiElement = startElement, cnt = 0;
1235 smiElement; smiElement = smiGetNextElement(smiElement)) {
1236 smiNode = smiGetElementNode(smiElement);
1237 if (smiNode == thisNode) cnt++;
1238 if (smiElement == thisElement) {
1239 break;
1240 }
1241 }
1242 return cnt;
1243 }
1244
1245
1246 static void
fprintNotification(FILE * f,SmiNode * smiNode)1247 fprintNotification(FILE *f, SmiNode *smiNode)
1248 {
1249 SmiElement *smiElement;
1250 SmiNode *vbNode, *entryNode;
1251 int c, cnt;
1252
1253 fprintSegment(f, INDENT, "notification", 0);
1254 fprint(f, " %s {\n", smiNode->name);
1255 fprintStatus(f, INDENT + INDENT, smiNode->status);
1256 fprintDescription(f, INDENT + INDENT, smiNode->description);
1257 fprintReference(f, INDENT + INDENT, smiNode->reference);
1258 fprintObjectIdentifier(f, INDENT + INDENT, smiNode->oid, smiNode->oidlen);
1259 fprint(f, "\n");
1260
1261 for (c = 0, smiElement = smiGetFirstElement(smiNode); smiElement;
1262 c++, smiElement = smiGetNextElement(smiElement)) {
1263 vbNode = smiGetElementNode(smiElement);
1264 if (! vbNode) continue;
1265
1266 cnt = GetPosition(smiGetFirstElement(smiNode), smiElement);
1267
1268 entryNode = (vbNode->nodekind == SMI_NODEKIND_COLUMN)
1269 ? smiGetParentNode(vbNode) : NULL;
1270
1271 fprintSegment(f, INDENT + INDENT, "container ", 0);
1272 if (cnt) {
1273 fprintf(f, "%s-%s-%d {\n", smiNode->name, vbNode->name, cnt);
1274 } else {
1275 fprintf(f, "%s-%s {\n", smiNode->name, vbNode->name);
1276 }
1277
1278 if (entryNode) {
1279 switch (entryNode->indexkind) {
1280 case SMI_INDEX_INDEX:
1281 fprintNotificationIndex(f, INDENT + INDENT + INDENT,
1282 entryNode, vbNode);
1283 break;
1284 case SMI_INDEX_AUGMENT:
1285 fprintNotificationIndex(f, INDENT + INDENT + INDENT,
1286 smiGetRelatedNode(entryNode), vbNode);
1287 break;
1288 default:
1289 break;
1290 }
1291 }
1292
1293 if (entryNode && isIndex(entryNode, vbNode)) {
1294 fprintKeyrefLeaf(f, INDENT + INDENT + INDENT,
1295 vbNode, FLAG_CONFIG_FALSE);
1296 } else {
1297 fprintLeaf(f, INDENT + INDENT + INDENT,
1298 vbNode, FLAG_CONFIG_FALSE);
1299 }
1300 fprintSegment(f, INDENT + INDENT, "}\n\n", 0);
1301 }
1302
1303 fprintSegment(f, INDENT, "}\n", 0);
1304 }
1305
1306
1307 static void
fprintNotifications(FILE * f,SmiModule * smiModule)1308 fprintNotifications(FILE *f, SmiModule *smiModule)
1309 {
1310 SmiNode *smiNode;
1311 int c;
1312
1313 for (c = 0, smiNode = smiGetFirstNode(smiModule,
1314 SMI_NODEKIND_NOTIFICATION);
1315 smiNode;
1316 c++, smiNode = smiGetNextNode(smiNode,
1317 SMI_NODEKIND_NOTIFICATION)) {
1318 if (c) {
1319 fprint(f, "\n");
1320 }
1321 fprintNotification(f, smiNode);
1322 }
1323 }
1324
1325
1326 static void
dumpYang(int modc,SmiModule ** modv,int flags,char * output)1327 dumpYang(int modc, SmiModule **modv, int flags, char *output)
1328 {
1329 SmiModule *smiModule;
1330 int i;
1331 FILE *f = stdout;
1332
1333 silent = (flags & SMIDUMP_FLAG_SILENT);
1334
1335 fprint_indent_texts = INDENT;
1336
1337 if (output) {
1338 f = fopen(output, "w");
1339 if (!f) {
1340 fprintf(stderr, "smidump: cannot open %s for writing: ", output);
1341 perror(NULL);
1342 exit(1);
1343 }
1344 }
1345
1346 for (i = 0; i < modc; i++) {
1347
1348 smiModule = modv[i];
1349
1350 createImportList(smiModule);
1351
1352 fprint(f, "/*\n");
1353 fprint(f, " * This module has been generated by smidump "
1354 SMI_VERSION_STRING ":\n");
1355 fprint(f, " *\n");
1356 fprint(f, " * smidump -f yang");
1357 if (silent) {
1358 fprint(f, " -q");
1359 }
1360 if (sflag) {
1361 fprint(f, " --yang-smi-extensions");
1362 }
1363 if (nflag) {
1364 fprint(f, " --yang-no-notifications");
1365 }
1366 fprint(f, " %s\n", smiModule->name);
1367 fprint(f, " *\n");
1368 fprint(f, " * Do not edit. Edit the source file instead!\n");
1369 fprint(f, " */\n\n");
1370 fprint(f, "module %s {\n", smiModule->name);
1371 fprint(f, "\n");
1372
1373 fprintNamespace(f, INDENT, smiModule);
1374 fprintLinkage(f, INDENT, smiModule);
1375 fprintMeta(f, INDENT, smiModule);
1376 fprintRevisions(f, INDENT, smiModule);
1377
1378 fprintTypedefs(f, modv[i]);
1379 fprintContainers(f, modv[i]);
1380 fprintAugments(f, modv[i]);
1381
1382 if (! nflag) {
1383 fprintNotifications(f, modv[i]);
1384 }
1385
1386 fprint(f, "} /* end of module %s */\n", smiModule->name);
1387
1388 freeImportList();
1389 }
1390
1391 if (fflush(f) || ferror(f)) {
1392 perror("smidump: write error");
1393 exit(1);
1394 }
1395
1396 if (output) {
1397 fclose(f);
1398 }
1399 }
1400
1401
1402
initYang()1403 void initYang()
1404 {
1405 static SmidumpDriverOption opt[] = {
1406 { "smi-extensions", OPT_FLAG, &sflag, 0,
1407 "generate smi extensions" },
1408 { "no-notifications", OPT_FLAG, &nflag, 0,
1409 "do not generate notifications" },
1410 { "indent", OPT_INT, &INDENT, 0,
1411 "indentation (default 2)" },
1412 { 0, OPT_END, 0, 0 }
1413 };
1414
1415 static SmidumpDriver driver = {
1416 "yang",
1417 dumpYang,
1418 0,
1419 SMIDUMP_DRIVER_CANT_UNITE,
1420 "YANG format",
1421 opt,
1422 NULL
1423 };
1424
1425 smidumpRegisterDriver(&driver);
1426 }
1427