1#!/usr/bin/env python
2#
3# This file is part of snmpclitools software.
4#
5# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
6# License: http://snmplabs.com/snmpclitools/license.html
7#
8# Command-line MIB browser
9#
10import sys
11import traceback
12from pysnmp.entity import engine
13from snmpclitools.cli import main, pdu, mibview, base
14from pysnmp.smi.error import NoSuchObjectError
15from pysnmp import error
16from pyasn1.type import univ
17
18
19def getUsage():
20    return "Usage: %s [OPTIONS] <PARAMETERS>\n\
21%s%s\
22TRANSLATE options:\n\
23   -T TRANSOPTS   Set various options controlling report produced:\n\
24              d:  print full details of the given OID\n\
25              a:  dump the loaded MIB in a trivial form\n\
26              l:  enable labeled OID report\n\
27              o:  enable OID report\n\
28              s:  enable dotted symbolic report\n\
29%s\n" % (sys.argv[0],
30         main.getUsage(),
31         mibview.getUsage(),
32         pdu.getReadUsage())
33
34# Construct c/l interpreter for this app
35
36
37class Scanner(mibview.MibViewScannerMixIn,
38              pdu.ReadPduScannerMixIn,
39              main.MainScannerMixIn,
40              base.ScannerTemplate):
41    def t_transopts(self, s):
42        r' -T '
43        self.rv.append(base.ConfigToken('transopts'))
44
45
46class Parser(mibview.MibViewParserMixIn,
47             pdu.ReadPduParserMixIn,
48             main.MainParserMixIn,
49             base.ParserTemplate):
50    def p_transOptions(self, args):
51        '''
52        Cmdline ::= Options whitespace Params
53        Cmdline ::= Options Params
54
55        Option ::= TranslateOption
56
57        TranslateOption ::= transopts whitespace string
58        TranslateOption ::= transopts string
59
60        '''
61
62
63class __Generator(base.GeneratorTemplate):
64    def n_TranslateOption(self, cbCtx, node):
65        snmpEngine, ctx = cbCtx
66        mibViewProxy = ctx['mibViewProxy']
67        if len(node) > 2:
68            opt = node[2].attr
69        else:
70            opt = node[1].attr
71        for c in opt:
72            mibViewProxy.translateMassMode = 1
73            if c == 'd':
74                mibViewProxy.translateFullDetails = 1
75                mibViewProxy.translateMassMode = 0
76            elif c == 'a':
77                mibViewProxy.translateTrivial = 1
78            elif c == 'l':
79                mibViewProxy.translateLabeledOid = 1
80            elif c == 'o':
81                mibViewProxy.translateNumericOid = 1
82            elif c == 's':
83                mibViewProxy.translateSymbolicOid = 1
84            else:
85                raise error.PySnmpError('unsupported sub-option \"%s\"' % c)
86
87
88def generator(cbCtx, ast):
89    snmpEngine, ctx = cbCtx
90    return __Generator().preorder((snmpEngine, ctx), ast)
91
92
93class MibViewProxy(mibview.MibViewProxy):
94    # MIB translate options
95    translateFullDetails = 0
96    translateTrivial = 0
97    translateLabeledOid = 0
98    translateNumericOid = 0
99    translateSymbolicOid = 0
100
101    # Implies SNMPWALK mode
102    translateMassMode = 0
103
104    # Override base class defaults
105    buildEqualSign = 0
106
107    _null = univ.Null()
108
109    def getPrettyOidVal(self, mibViewController, oid, val):
110        prefix, label, suffix = mibViewController.getNodeName(oid)
111        modName, nodeDesc, _suffix = mibViewController.getNodeLocation(prefix)
112        mibNode, = mibViewController.mibBuilder.importSymbols(
113            modName, nodeDesc
114        )
115        out = ''
116        if self.translateFullDetails:
117            if suffix:
118                out = '%s::%s' % (modName, nodeDesc)
119                out += ' [ %s ]' % '.'.join([str(x) for x in suffix])
120                out += '\n'
121            else:
122                out += '%s::%s\n%s ::= { %s }' % (
123                    modName,
124                    nodeDesc,
125                    mibNode.asn1Print(),
126                    ' '.join(map(lambda x, y: '%s(%s)' % (y, x), prefix, label))
127                )
128        elif self.translateTrivial:
129            out = '%s ::= { %s %s' % (
130                len(label) > 1 and label[-2] or ".", label[-1], prefix[-1]
131            )
132            if suffix:
133                out += ' [ %s ]' % '.'.join([str(x) for x in suffix])
134            out += ' }'
135        elif self.translateLabeledOid:
136            out = '.' + '.'.join(
137                map(lambda x, y: '%s(%s)' % (y, x),  prefix, label)
138            )
139            if suffix:
140                out += ' [ %s ]' % '.'.join([str(x) for x in suffix])
141        elif self.translateNumericOid:
142            out = '.' + '.'.join([str(x) for x in prefix])
143            if suffix:
144                out += ' [ %s ]' % '.'.join([str(x) for x in suffix])
145        elif self.translateSymbolicOid:
146            out = '.' + '.'.join(label)
147            if suffix:
148                out += ' [ %s ]' % '.'.join([str(x) for x in suffix])
149        if not out:
150            out = mibview.MibViewProxy.getPrettyOidVal(
151                self, mibViewController, oid, self._null
152            )
153        return out
154
155snmpEngine = engine.SnmpEngine()
156
157# Load up MIB texts (DESCRIPTION, etc.)
158mibBuilder = snmpEngine.getMibBuilder()
159mibBuilder.loadTexts = True
160
161ctx = {}
162
163try:
164    # Parse c/l into AST
165    ast = Parser().parse(
166        Scanner().tokenize(' '.join(sys.argv[1:]))
167    )
168
169    # Apply configuration to SNMP entity
170    main.generator((snmpEngine, ctx), ast)
171    ctx['mibViewProxy'] = MibViewProxy(ctx['mibViewController'])
172    mibview.generator((snmpEngine, ctx), ast)
173    pdu.readPduGenerator((snmpEngine, ctx), ast)
174    generator((snmpEngine, ctx), ast)
175
176except KeyboardInterrupt:
177    sys.stderr.write('Shutting down...\n')
178
179except error.PySnmpError:
180    sys.stderr.write('Error: %s\n%s' % (sys.exc_info()[1], getUsage()))
181    sys.exit(-1)
182
183except Exception:
184    sys.stderr.write('Process terminated: %s\n' % sys.exc_info()[1])
185    for line in traceback.format_exception(*sys.exc_info()):
186        sys.stderr.write(line.replace('\n', ';'))
187    sys.exit(-1)
188
189ctx['mibViewProxy'].buildValue = 0  # disable value printout
190
191for oid, val in ctx['varBinds']:
192    while 1:
193        if val is None:
194            val = univ.Null()
195        sys.stdout.write(
196            '%s\n' % ctx['mibViewProxy'].getPrettyOidVal(
197                ctx['mibViewController'], oid, val
198            )
199        )
200        if not ctx['mibViewProxy'].translateMassMode:
201            break
202        try:
203            oid, label, suffix = ctx['mibViewController'].getNextNodeName(oid)
204        except NoSuchObjectError:
205            break
206