makemib revision 56893
1#!/bin/sh
2#
3# Copyright (c) 1990, 1996, by John Robert LoVerso.
4# All rights reserved.
5# SMIv2 parsing copyright (c) 1999 by William C. Fenner.
6#
7# Redistribution and use in source and binary forms are permitted
8# provided that the above copyright notice and this paragraph are
9# duplicated in all such forms and that any documentation,
10# advertising materials, and other materials related to such
11# distribution and use acknowledge that the software was developed
12# by John Robert LoVerso.
13# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16#
17# @(#) $Id: makemib,v 1.2 1999/11/21 17:24:15 fenner Exp $ (jlv)
18
19#
20# This script will read either ASN.1-style MIB files or the ".defs" files
21# created by the ISODE "mosy" program on such files.
22#
23# The output of this script is the "mib.h" file used by tcpdumps' ASN.1/SNMP
24# decoding code.
25#
26# This script needs to be run by "gawk" (GNU awk).  "nawk" will work, but
27# dump will get a recursion error if you process LARGE mibs.  While it would
28# by farily easy to rewrite this not to use recursion (and also easy to
29# eliminate use of gsub and functions to use classic "awk"), you have to 
30# order the structure declarations in defined-first order for the compiler
31# not to barf; too bad tsort doesn't take arguments.
32#
33
34cat << EOF
35/*
36 * This file was generated by tcpdump/makemib on `date`
37 * You probably don't want to edit this by hand!
38 *
39 * struct mib somename = { desc, oid-octet, type, child-pointer, next-pointer 
40};
41 */
42
43EOF
44
45awk '
46BEGIN {
47	debug=0;
48	# for sanity, we prep the namespace with objects from RFC-1155
49	# (we manually establish the root)
50	oid["iso"]=1
51	oidadd("org", "iso", 3)
52	oidadd("dod", "org", 6)
53	oidadd("internet", "dod", 1)
54	oidadd("directory", "internet", 1)
55	oidadd("mgmt", "internet", 2)
56#XXX	oidadd("mib", "mgmt", 1)
57	oidadd("mib-2", "mgmt", 1)
58	oidadd("experimental", "internet", 3)
59	oidadd("private", "internet", 4)
60	oidadd("enterprises", "private", 1)
61	oidadd("ip", "mib-2", 4)
62	oidadd("transmission", "mib-2", 10)
63
64	holddesc="none"
65}
66
67#
68# Read mosy "*.defs" file.  mosy does all the parsing work; we just read
69# its simple and straightforward output.  It would not be too hard to make
70# tcpdump directly read mosy output, but...
71#
72# Ignore these unless the current file is called something.defs; false
73# positives are too common in DESCRIPTIONs.
74
75NF > 1 && index($2,".")>0 && FILENAME ~ /\.defs/ {
76	# currently ignore items of the form "{ iso.3.6.1 }"
77	if (split($2, p, ".") == 2) {
78		oidadd($1, p[1], p[2])
79	}
80	next
81}
82
83#
84# Must be a MIB file
85# Make it easier to parse - used to be done by sed
86{ sub(/--\*.*\*--/, ""); sub(/--.*/, ""); gsub(/[{}]/, " & "); }
87
88#
89# this next section is simple and naive, but does the job ok
90#
91
92# foo OBJECT IDENTIFIER ::= { baz 17 }
93# or
94# foo OBJECT IDENTIFIER ::=
95# { baz 17 }
96$2$3$4 == "OBJECTIDENTIFIER::=" {
97	holddesc="none"
98	if (NF == 8)
99		oidadd($1, $6, $7)
100	if (NF == 4)
101		holddesc=$1
102	next
103}
104$1 == "{" && holddesc != "none" && NF == 4 {
105	oidadd(holddesc, $2, $3)
106	holddesc="none"
107}
108#
109# foo OBJECT IDENTIFIER
110#  ::= { bar 1 }
111$2$3 == "OBJECTIDENTIFIER" && $1 != "SYNTAX" && NF == 3 {
112	holddesc=$1
113}
114#
115# foo
116# OBJECT IDENTIFIER ::= { bar 1 }
117# a couple of heuristics to exclude single words in e.g. long
118#  DESCRIPTION clauses
119NF == 1 && $1 ~ "[a-z][a-z]*[A-Z]" && $1 !~ /[(){}.,]/ && holddesc == "none" {
120	holddesc=$1
121}
122$1$2$3 == "OBJECTIDENTIFIER::=" && holddesc != "none" {
123	oidadd(holddesc, $5, $6)
124	holddesc="none"
125}
126#
127# "normal" style
128# foo OBJECT-TYPE ...
129# ...
130#   ::= { baz 5 }
131$2 == "MODULE-IDENTITY" || $2 == "MODULE-COMPLIANCE" ||
132	$2 == "OBJECT-IDENTITY" || $2 == "OBJECT-TYPE" ||
133	$2 == "OBJECT-GROUP" ||
134	$2 == "NOTIFICATION-TYPE" || $2 == "NOTIFICATION-GROUP" {
135	holddesc=$1
136}
137$1 == "::=" && holddesc != "none" && NF == 5 {
138	oidadd(holddesc, $3, $4)
139	holddesc="none"
140}
141#
142# foo ::= { baz 17 }
143$2$3 == "::={" {
144	oidadd($1,$4,$5)
145	holddesc="none"
146}
147
148
149# 
150# End of the road - output the data.
151#
152
153END {
154	print "struct obj"
155	dump("iso")
156	print "*mibroot = &_iso_obj;"
157}
158
159function inn(file) {
160	if (file == "" || file == "-")
161		return ""
162	return " in " file
163}
164
165#
166# add a new object to the tree
167#
168#		new OBJECT IDENTIFIER ::= { parent value }
169#
170
171function oidadd(new, parent, value) {
172	# Ignore 0.0
173	if (parent == "0" && value == 0)
174		return
175	if (debug)
176		print "/* oidadd" inn(FILENAME) ":", new, "in", parent, "as", value, "line", $0, "*/"
177	# use safe C identifiers
178	gsub(/[-&\/]/,"",new)
179	gsub(/[-&\/]/,"",parent)
180	# check if parent missing
181	if (oid[parent] == "") {
182		printf "/* parse problem%s: no parent for %s.%s(%d) */\n", \
183			inn(FILENAME), parent, new, value
184		return
185	}
186	# check if parent.value already exists
187	if (oid[new] > 0 && oid[new] != value) {
188		printf "/* parse problem%s: dup %s.%s(%d) != old (%d) */\n", \
189			inn(FILENAME), parent, new, value, oid[new]
190		return
191	}
192	# check for new name for parent.value
193	if (child[parent] != "") {
194		for (sib = child[parent]; sib != ""; sib = sibling[sib])
195			if (oid[sib] == value) {
196				if (new != sib)
197					printf "/* parse problem%s: new name" \
198						" \"%s\"" \
199						" for %s.%s(%d) ignored */\n", \
200						inn(FILENAME), new, parent, \
201						sib, value
202				return
203			}
204	}
205
206	oid[new]=value
207	if (child[parent] == "") {
208		child[parent] = new
209	} else {
210		sibling[new] = child[parent]
211		child[parent] = new
212	}
213}
214
215#
216# old(?) routine to recurse down the tree (in postfix order for convenience)
217#
218
219function dump(item, c, s) {
220#	newitem=sofar"."item"("oid[item]")"
221#	printf "/* %s c=%s s=%s */\n", newitem, child[item], sibling[item]
222	c="NULL"
223	if (child[item] != "") {
224		dump(child[item])
225		c = "&_"child[item]"_obj"
226	}
227	s="NULL"
228	if (sibling[item] != "") {
229		dump(sibling[item])
230		s = "&_"sibling[item]"_obj"
231	}
232	printf "_%s_obj = {\n\t\"%s\", %d, 0,\n\t%s, %s\n},\n", \
233		item, item, oid[item], c, s
234}
235' $@
236exit 0
237