#! /usr/bin/env python
## PyRT: Python Routeing Toolkit
## MRTd module: provides MRT writing/reading using protocol
## parsers from appropriate module.
## Copyright (C) 2001 Richard Mortier <mort@sprintlabs.com>, Sprint ATL
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
## 02111-1307 USA
#
# $Id: mrtd.py,v 1.24 2002/02/26 01:57:03 mort Exp $
#
import os, time, struct, getopt, sys, bgp, isis, math, pprint
from mutils import *
#-------------------------------------------------------------------------------
DEFAULT_FILE = "/tmp/mrtd.mrtd"
DEFAULT_SIZE = 50*1024*1024
MIN_FILE_SZ = 50*1024
BUF_SZ = 8192*8
INDENT = " "
COMMON_HDR_LEN = 12
TABLE_DUMP_HDR_LEN = 4
BGP_SUBTYPE_HDR_LEN = 12
BGP4MP_SUBTYPE_HDR_LEN = 16
BGP4PY_SUBTYPE_HDR_LEN = 20
ISIS_SUBTYPE_HDR_LEN = 0
ISIS2_SUBTYPE_HDR_LEN = 4
################################################################################
DLIST = []
#
# MRTD values
#
MSG_TYPES = { 0L: "NULL",
1L: "START", # sender is starting up
2L: "DIE", # receiver should shutdown
3L: "I_AM_DEAD", # sender is shutting down
4L: "PEER_DOWN", # sender's peer is down
5L: "PROTOCOL_BGP",
6L: "PROTOCOL_RIP",
7L: "PROTOCOL_IDRP",
8L: "PROTOCOL_RIPNG",
9L: "PROTOCOL_BGP4PLUS",
10L: "PROTOCOL_BGP4PLUS_01",
11L: "PROTOCOL_OSPF2",
12L: "TABLE_DUMP", # routing table dump
16L: "PROTOCOL_BGP4MP", # Zebra BGP4
17L: "PROTOCOL_BGP4PY", # PyRT BGP4 (ext. time stamp)
32L: "PROTOCOL_ISIS", # ISIS
33L: "PROTOCOL_ISIS2", # ISIS + ext. time stamp
}
DLIST = DLIST + [MSG_TYPES]
TABLE_DUMP_SUBTYPES = bgp.AFI_TYPES
DLIST = DLIST + [TABLE_DUMP_SUBTYPES]
BGP_SUBTYPES = { 0L: "NULL",
1L: "UPDATE", # raw update
2L: "PREF_UPDATE", # (T,L,V) prefs. followed by raw update
3L: "STATE_CHANGE", # state change
4L: "SYNC",
# XXX RMM XXX apparently bogo-extensions for some of RIS data?
# See, eg., updates.20000814.1631
5L: "BOGO_RIS_EXTN_1",
7L: "BOGO_RIS_EXTN_2",
# XXX RMM XXX extensions for other raw messages
129L: "OPEN",
131L: "NOTIFICATION",
132L: "KEEPALIVE",
133L: "ROUTE_REFRESH",
}
DLIST = DLIST + [BGP_SUBTYPES]
BGP4MP_SUBTYPES = { 0L: "STATE_CHANGE",
1L: "MESSAGE",
2L: "ENTRY",
3L: "SNAPSHOT"
}
DLIST = DLIST + [BGP4MP_SUBTYPES]
BGP4PY_SUBTYPES = { 0L: "STATE_CHANGE",
1L: "MESSAGE",
2L: "ENTRY",
3L: "SNAPSHOT"
}
DLIST = DLIST + [BGP4PY_SUBTYPES]
ISIS_SUBTYPES = isis.MSG_TYPES
DLIST = DLIST + [ISIS_SUBTYPES]
#
# GNU Zebra dump specific values
#
ZEBRA_STATES = { 1L: "IDLE",
2L: "CONNECT",
3L: "ACTIVE",
4L: "OPENSENT",
5L: "OPENCONFIRM",
6L: "ESTABLISHED"
}
DLIST = DLIST + [ZEBRA_STATES]
ZEBRA_EVENTS = { 1L: "BGP_START",
2L: "BGP_STOP",
3L: "BGP_TRANS_CONN_OPEN",
4L: "BGP_TRANS_CONN_CLOSED",
5L: "BGP_TRANS_CONN_OPEN_FAILED",
6L: "BGP_TRANS_FATAL_ERROR",
7L: "CONNECTRETRY_TIMER_EXPIRED",
8L: "HOLD_TIMER_EXPIRED",
9L: "KEEPALIVE_TIMER_EXPIRED",
10L: "RCV_OPEN_MSG",
11L: "RCV_KEEPALIVE_MSG",
12L: "RCV_UPDATE_MSG",
13L: "RCV_NOTIFICATION_MSG"
}
DLIST = DLIST + [ZEBRA_EVENTS]
#-------------------------------------------------------------------------------
for d in DLIST:
for k in d.keys():
d[ d[k] ] = k
################################################################################
def parseBgp4mpMrtHdr(hdr, verbose=1, level=0):
src_as, dst_as, ifc, afi, src_ip, dst_ip = struct.unpack(">HHHH LL", hdr)
if verbose > 0:
if afi == bgp.AFI_TYPES["IP"]:
print level*INDENT + "AS(src): %d, AS(dst): %d" %\
(src_as, dst_as)
print level*INDENT + "ifc idx: %d, AFI: %s" %\
(ifc, bgp.AFI_TYPES[afi])
print level*INDENT + "IP(src): %s, IP(dst): %s" %\
(id2str(src_ip), id2str(dst_ip))
else:
print INDENT*level + "[ UNKNOWN ADDRESS FAMILY", `afi`, "]"
return src_as, dst_as, ifc, afi, src_ip, dst_ip
#-------------------------------------------------------------------------------
def parseBgp4pyMrtHdr(hdr, verbose=1, level=0):
src_as, dst_as, ifc, afi, src_ip, dst_ip, ts_frac =\
struct.unpack(">HHHH LLL", hdr)
if verbose > 0:
if afi == bgp.AFI_TYPES["IP"]:
print level*INDENT + "AS(src): %d, AS(dst): %d" %\
(src_as, dst_as)
print level*INDENT + "ifc idx: %d, AFI: %s" %\
(ifc, bgp.AFI_TYPES[afi])
print level*INDENT + "IP(src): %s, IP(dst): %s" %\
(id2str(src_ip), id2str(dst_ip))
else:
print INDENT*LEVEL + "[ UNKNOWN ADDRESS FAMILY", `afi`, "]"
return src_as, dst_as, ifc, afi, src_ip, dst_ip, ts_frac
################################################################################
class EOFExc(Exception): pass
class ParseExc(Exception): pass
#-------------------------------------------------------------------------------
class Mrtd:
_extn_fmt = ".%Y-%m-%d_%H.%M.%S"
def __init__(self, file_pfx=DEFAULT_FILE, file_mode="w+b",
file_size=None, mrt_type=None, msg_src=None):
self._mrt_type = mrt_type
self._msg_src = msg_src # message source object, typed by mrt_type
self._file_pfx = file_pfx
if not mrt_type:
self._file_name = file_pfx
else:
self._file_name = file_pfx +\
time.strftime(Mrtd._extn_fmt, time.gmtime())
self._file_size = file_size
self._file_mode = file_mode
self._of = open(self._file_name, file_mode)
self._read = ""
#---------------------------------------------------------------------------
def close(self):
# XXX RMM XXX this should possibly be __del__() method?
self._of.flush()
self._of.close()
def write(self, msg):
if self._of.tell() + len(msg) > self._file_size:
self._of.close()
self._file_name = self._file_pfx +\
time.strftime(Mrtd._extn_fmt, time.gmtime())
self._of = open(self._file_name, self._file_mode)
self._of.write(msg)
self._of.flush()
def read(self):
if len(self._read) < COMMON_HDR_LEN:
self._read = self._read + self._of.read(BUF_SZ)
if len(self._read) < COMMON_HDR_LEN:
raise EOFExc
ptime, ptype, psubtype, plen =\
struct.unpack(">LHHL", self._read[:COMMON_HDR_LEN])
plen = int(plen)
phdr = self._read[:COMMON_HDR_LEN]
self._read = self._read[COMMON_HDR_LEN:]
if len(self._read) < plen:
self._read = self._read + self._of.read(BUF_SZ)
if len(self._read) < plen:
raise EOFExc
pdata = self._read[:plen]
self._read = self._read[plen:]
return (ptime, ptype, psubtype, plen, phdr, pdata)
def parse(self, msg, verbose=1, level=0):
(ptime, ptype, psubtype, plen, phdr, pdata) = msg
if verbose > 1:
print prtbin(level*INDENT, phdr)
if verbose > 0:
print level*INDENT + "[ " + time.ctime(ptime) + " ]"
print level*INDENT + "MRT packet: len: %d, type: %s, subtype:" %\
(plen, MSG_TYPES[ptype]),
try:
if ptype == MSG_TYPES["PROTOCOL_BGP4MP"]:
print BGP4MP_SUBTYPES[psubtype]
elif ptype == MSG_TYPES["PROTOCOL_BGP4PY"]:
print BGP4MP_SUBTYPES[psubtype]
elif ptype == MSG_TYPES["PROTOCOL_BGP"]:
print BGP_SUBTYPES[psubtype]
elif ptype == MSG_TYPES["PROTOCOL_ISIS"]:
print ISIS_SUBTYPES[psubtype]
elif ptype == MSG_TYPES["PROTOCOL_ISIS2"]:
print ISIS_SUBTYPES[psubtype]
elif ptype == MSG_TYPES["TABLE_DUMP"]:
print TABLE_DUMP_SUBTYPES[psubtype]
except (KeyError):
if verbose:
print level*INDENT +\
'[ *** Unsupported subtype: %d *** ]' % psubtype
return None
if ptype == MSG_TYPES["PROTOCOL_BGP"]:
rv = self.parseBgpMsg(psubtype, plen, pdata, verbose, level+1)
elif ptype == MSG_TYPES["PROTOCOL_BGP4MP"]:
rv = self.parseBgp4mpMsg(psubtype, plen, pdata, verbose, level+1)
elif ptype == MSG_TYPES["PROTOCOL_BGP4PY"]:
rv = self.parseBgp4pyMsg(psubtype, plen, pdata, verbose, level+1)
elif ptype == MSG_TYPES["PROTOCOL_ISIS"]:
rv = self.parseIsisMsg(plen, pdata, verbose, level+1)
elif ptype == MSG_TYPES["PROTOCOL_ISIS2"]:
rv = self.parseIsis2Msg(plen, pdata, verbose, level+1)
elif ptype == MSG_TYPES["TABLE_DUMP"]:
rv = self.parseTableDump(psubtype, plen, pdata, verbose, level+1)
else:
rv = {"T": None, "L": 0, "V": None, "H": {"TIME":0L}}
if verbose:
print level*INDENT +\
"[ *** Unsupported message type [ '%s' ] *** ]" %\
self._file_name
print (level+1)*INDENT + 'time:', time.ctime(ptime)
print (level+1)*INDENT + 'header:', str2hex(phdr)
print (level+1)*INDENT + 'data:', str2hex(pdata)
rv["H"]["TIME"] = rv["H"]["TIME"] + ptime
if verbose:
print (level+1)*INDENT +\
"extended timestamp: %f\n" % rv["H"]["TIME"]
return rv
def mkHdr(self, subtype, msg_len):
ts = time.time()
hdr = struct.pack(">LHHL", int(ts), self._mrt_type, subtype, msg_len)
return (ts, hdr)
#---------------------------------------------------------------------------
def writeBgpMsg(self, msg_type, msg_len, msg):
subtype = BGP_SUBTYPES[bgp.MSG_TYPES[msg_type]]
(ts, hdr) = self.mkHdr(subtype, msg_len+BGP_SUBTYPE_HDR_LEN)
src_as = self._msg_src._bgp_peer_as
src_ip = self._msg_src._bgp_peer_id
dst_as = self._msg_src._bgp_as
dst_ip = self._msg_src._bgp_id
msg = struct.pack(">%ds HLHL %ds" % (COMMON_HDR_LEN, msg_len),
hdr,
src_as, src_ip, dst_as, dst_ip,
msg)
self.write(msg)
def parseBgpMsg(self, psubtype, plen, pdata, verbose=1, level=0):
rv = { "T": MSG_TYPES["PROTOCOL_BGP"],
"ST": psubtype,
"L": plen,
"H": { 'TIME': 0L },
"V": {}
}
if psubtype in (BGP_SUBTYPES['BOGO_RIS_EXTN_1'],
BGP_SUBTYPES['BOGO_RIS_EXTN_2']):
print INDENT*level + '[ *** skipping *** ]'
return rv
if verbose > 1:
print prtbin(level*INDENT, pdata[:BGP_SUBTYPE_HDR_LEN])
try:
src_as, src_ip, dst_as, dst_ip =\
struct.unpack(">HLHL", pdata[:BGP_SUBTYPE_HDR_LEN])
rv["H"]["SRC_AS"] = src_as
rv["H"]["SRC_IP"] = src_ip
rv["H"]["DST_AS"] = dst_as
rv["H"]["DST_IP"] = dst_ip
except (struct.error):
print INDENT*level + '[ *** struct error: bogus RIS data?! *** ]'
if psubtype == BGP_SUBTYPES['STATE_CHANGE']:
src, dst = struct.unpack(">HH", pdata[-4:])
print INDENT*level +\
'state change: %s -> %s' %\
(ZEBRA_STATES[src], ZEBRA_STATES[dst])
return rv
if verbose > 0:
print level*INDENT + "IP(src): %s, AS(src): %d" %\
(id2str(src_ip), src_as)
print level*INDENT + "IP(dst): %s, AS(dst): %d" %\
(id2str(dst_ip), dst_as)
pdata = pdata[BGP_SUBTYPE_HDR_LEN:]
if pdata[0:len(bgp.BGP_MARKER)] != bgp.BGP_MARKER:
raise ParseExc
else:
msg_len, msg_type =\
struct.unpack(">HB", pdata[len(bgp.BGP_MARKER):
len(bgp.BGP_MARKER)+3])
if verbose > 1:
print prtbin(level*INDENT, pdata[:bgp.BGP_HDR_LEN])
if verbose > 0:
print level*INDENT + "BGP message type: %s len=%d" %\
(bgp.MSG_TYPES[msg_type], msg_len)
rv["V"] = bgp.parseBgpPdu(msg_type, msg_len, pdata, verbose, level+1)
return rv
#---------------------------------------------------------------------------
# NOTE: Bgp4mp is essentially GNU Zebra specific; as of version 0.89 and
# 0.91a, Zebra's bgpd appears to have a couple of bugs wrt. dumping MRT
# traces -- workarounds to patch things up before calling into the bgp
# module are below.
def writeBgp4mpMsg(self, ptype, plen, pkt):
subtype = BGP4MP_SUBTYPES["MESSAGE"]
(ts, hdr) = self.mkHdr(subtype, plen+BGP4MP_SUBTYPE_HDR_LEN)
src_as = self._msg_src._bgp_peer_as
dst_as = self._msg_src._bgp_as
src_ip = self._msg_src._bgp_peer_id
dst_ip = self._msg_src._bgp_id
msg = struct.pack(">%ds HHHHLL %ds" % (COMMON_HDR_LEN, plen),
hdr,
src_as, dst_as, 0, bgp.AFI_TYPES["IP"], src_ip, dst_ip,
pkt)
self.write(msg)
def parseBgp4mpMsg(self, psubtype, plen, pdata, verbose=1, level=0):
rv = { "T": MSG_TYPES["PROTOCOL_BGP4MP"],
"ST": psubtype,
"L": plen,
"H": { "TIME": 0L },
"V": {}
}
if psubtype == BGP4MP_SUBTYPES["STATE_CHANGE"]:
if verbose > 1:
print prtbin(level*INDENT, pdata)
# XXX HACK get occasional 8 byte packets dumped, which I don't
# _believe_ to be valid; seem to have a "valid" state changes in
# though. Bizarre.
if plen == 8:
if verbose > 0:
print level*INDENT +\
"[ *** BOGUS 8 byte PAYLOAD PACKET *** ]"
pdata = pdata[4:]
else:
src_as, dst_as, ifc, afi, src_ip, dst_ip =\
parseBgp4mpMrtHdr(pdata[0:BGP4MP_SUBTYPE_HDR_LEN],
verbose, level)
rv["H"]["SRC_AS"] = src_as
rv["H"]["DST_AS"] = dst_as
rv["H"]["SRC_IP"] = src_ip
rv["H"]["DST_IP"] = dst_ip
rv["H"]["IFC"] = ifc
rv["H"]["AFI"] = afi
pdata = pdata[BGP4MP_SUBTYPE_HDR_LEN:]
start_st, end_st = struct.unpack(">HH", pdata)
rv["V"] = (start_st, end_st)
if verbose > 0:
print level*INDENT + "%s -> %s\n" %\
(ZEBRA_STATES[start_st], ZEBRA_STATES[end_st])
elif psubtype == BGP4MP_SUBTYPES["MESSAGE"]:
# XXX HACK similarly, get either (a) 4 null bytes instead of MRT
# header, or (b) bogus MRT header for subtype MESSAGE. Skip them.
if pdata[0:4+bgp.BGP_MARKER_LEN] == ("\000\000\000\000" +
bgp.BGP_MARKER):
if verbose > 1:
print prtbin(level*INDENT, pdata[:4])
if verbose > 0:
print level*INDENT + "[ *** BOGUS NULL MRT HEADER *** ]"
pdata = pdata[4:]
else:
if verbose > 1:
print prtbin(level*INDENT, pdata[:BGP4MP_SUBTYPE_HDR_LEN])
src_as, dst_as, ifc, afi, src_ip, dst_ip =\
parseBgp4mpMrtHdr(pdata[0:BGP4MP_SUBTYPE_HDR_LEN],
verbose, level)
rv["H"]["SRC_AS"] = src_as
rv["H"]["DST_AS"] = dst_as
rv["H"]["SRC_IP"] = src_ip
rv["H"]["DST_IP"] = dst_ip
rv["H"]["IFC"] = ifc
rv["H"]["AFI"] = afi
pdata = pdata[BGP4MP_SUBTYPE_HDR_LEN:]
msg_len, msg_type =\
struct.unpack(">HB",
pdata[bgp.BGP_MARKER_LEN:bgp.BGP_HDR_LEN])
rv["V"] = bgp.parseBgpPdu(msg_type, msg_len, pdata, verbose, level)
else:
print level*INDENT + "[ *** SUBTYPE: %d NOT PARSED *** ]" % psubtype
return rv
#---------------------------------------------------------------------------
def writeBgp4pyMsg(self, ptype, plen, pkt):
subtype = BGP4PY_SUBTYPES["MESSAGE"]
(ts, hdr) = self.mkHdr(subtype, plen+BGP4PY_SUBTYPE_HDR_LEN)
src_as = self._msg_src._bgp_peer_as
dst_as = self._msg_src._bgp_as
src_ip = self._msg_src._bgp_peer_id
dst_ip = self._msg_src._bgp_id
(ts_frac, ts_int) = math.modf(ts)
msg = struct.pack(">%ds HH HH LLL %ds" % (COMMON_HDR_LEN, plen),
hdr,
src_as, dst_as, 0, bgp.AFI_TYPES["IP"],
src_ip, dst_ip, ts_frac*1000000,
pkt)
self.write(msg)
def parseBgp4pyMsg(self, psubtype, plen, pdata, verbose=1, level=0):
rv = { "T": MSG_TYPES["PROTOCOL_BGP4PY"],
"ST": psubtype,
"L": plen,
"H": { "TIME": 0L },
"V": {}
}
if verbose > 1:
print prtbin(level*INDENT, pdata[:BGP4PY_SUBTYPE_HDR_LEN])
src_as, dst_as, ifc, afi, src_ip, dst_ip, ts_frac =\
parseBgp4pyMrtHdr(pdata[0:BGP4PY_SUBTYPE_HDR_LEN], verbose, level)
rv["H"]["SRC_AS"] = src_as
rv["H"]["DST_AS"] = dst_as
rv["H"]["SRC_IP"] = src_ip
rv["H"]["DST_IP"] = dst_ip
rv["H"]["IFC"] = ifc
rv["H"]["AFI"] = afi
rv["H"]["TIME"] = ts_frac*0.000001
pdata = pdata[BGP4PY_SUBTYPE_HDR_LEN:]
if psubtype == BGP4PY_SUBTYPES["STATE_CHANGE"]:
start_st, end_st = struct.unpack(">HH", pdata)
rv["V"] = (start_st, end_st)
if verbose > 0:
print level*INDENT + "%s -> %s\n" %\
(ZEBRA_STATES[start_st], ZEBRA_STATES[end_st])
elif psubtype == BGP4PY_SUBTYPES["MESSAGE"]:
msg_len, msg_type =\
struct.unpack(">HB",
pdata[bgp.BGP_MARKER_LEN:bgp.BGP_HDR_LEN])
rv["V"] = bgp.parseBgpPdu(msg_type, msg_len, pdata, verbose, level)
else:
print level*INDENT + "[ *** SUBTYPE: %d NOT PARSED *** ]" % psubtype
return rv
#---------------------------------------------------------------------------
def writeIsisMsg(self, ptype, plen, pkt):
(ts, hdr) = self.mkHdr(ptype, plen+ISIS_SUBTYPE_HDR_LEN)
msg = struct.pack(">%ds %ds" % (len(hdr), len(pkt)), hdr, pkt)
self.write(msg)
def parseIsisMsg(self, plen, pdata, verbose=1, level=0):
rv = { "T": MSG_TYPES["PROTOCOL_ISIS"],
"ST": 0L,
"L": plen,
"H": { "TIME": 0L },
"V": {}
}
rv["V"].update(isis.parseIsisMsg(plen, pdata, verbose, level))
return rv
#---------------------------------------------------------------------------
def writeIsis2Msg(self, ptype, plen, pkt):
(ts, hdr) = self.mkHdr(ptype, plen+ISIS2_SUBTYPE_HDR_LEN)
(ts_frac, ts_int) = math.modf(ts)
msg = struct.pack(">%ds L %ds" % (COMMON_HDR_LEN, len(pkt)),
hdr, ts_frac*1000000, pkt)
self.write(msg)
def parseIsis2Msg(self, plen, pdata, verbose=1, level=0):
rv = { "T": MSG_TYPES["PROTOCOL_ISIS2"],
"ST": 0L,
"L": plen,
"H": { "TIME": 0L },
"V": {}
}
(ts_frac, ) = struct.unpack(">L", pdata[:ISIS2_SUBTYPE_HDR_LEN])
rv["H"]["TIME"] = ts_frac*0.000001
rv["V"].update(isis.parseIsisMsg(plen, pdata[ISIS2_SUBTYPE_HDR_LEN:],
verbose, level))
return rv
#---------------------------------------------------------------------------
def parseTableDump(self, psubtype, plen, pdata, verbose=1, level=0):
rv = { "T": MSG_TYPES["TABLE_DUMP"],
"ST": psubtype,
"L": plen,
"H": { "TIME": 0L },
"V": []
}
if verbose > 1:
print prtbin(level*INDENT, pdata[:TABLE_DUMP_HDR_LEN])
view, seqno = struct.unpack(">HH", pdata[:TABLE_DUMP_HDR_LEN])
rv["H"]["VIEW"] = view
rv["H"]["SEQNO"] = seqno
if verbose:
print INDENT*level + "view: %d, seqno: %d" % (view, seqno)
pdata = pdata[TABLE_DUMP_HDR_LEN:]
while len(pdata):
erv = bgp.parseTableEntry(plen, pdata, verbose, level)
pdata = pdata[erv["L"]:]
rv["V"].append(erv)
return rv
#---------------------------------------------------------------------------
################################################################################
if __name__ == "__main__":
VERBOSE = 1
file_name = DEFAULT_FILE
file_size = -1
#---------------------------------------------------------------------------
def usage():
print """Usage: %s [ options ]:
-h|--help : Help
-q|--quiet : Be quiet
-v|--verbose : Be verbose
-f|--file : Set file name to parse (def: %s)
-z|--file-size : Set size of output file(s)""" %\
(os.path.basename(sys.argv[0]), DEFAULT_FILE)
sys.exit(0)
#---------------------------------------------------------------------------
if len(sys.argv) < 2:
usage()
try:
try:
opts, args = getopt.getopt(sys.argv[1:],
"hqvf:z:",
("help", "quiet", "verbose",
"file=", "size=" ))
except (getopt.error):
usage()
for (x, y) in opts:
if x in ('-h', '--help'):
usage()
elif x in ('-q', '--quiet'):
VERBOSE = 0
elif x in ('-v', '--verbose'):
VERBOSE = 2
elif x in ('-f', '--file'):
file_name = y
elif x in ('-z', '--size'):
file_size = string.atof(y)
else:
usage()
#-----------------------------------------------------------------------
mrt = Mrtd(file_name, "rb", file_size)
while 1:
rv = mrt.parse(mrt.read(), VERBOSE)
except (EOFExc):
print "End of file"
except (KeyboardInterrupt):
print "Interrupted"
mrt.close()
sys.exit(0)
################################################################################
################################################################################
syntax highlighted by Code2HTML, v. 0.9.1