-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathip.py
More file actions
100 lines (95 loc) · 3.01 KB
/
Copy pathip.py
File metadata and controls
100 lines (95 loc) · 3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/usr/bin'python
#
# Functions for working with the Internet Protocol (IP).
# - Cameron Simpson <cs@cskk.id.au> 27jan2017
#
from collections import namedtuple, OrderedDict
from cs.logutils import error, warning
from cs.pfx import Pfx
from cs.x import X
ETC_SERVICES = '/etc/services'
_PortInfo = namedtuple('PortInfo', 'portnum proto name aliases comment')
class PortInfo(_PortInfo):
def line(self):
line = "%-15s %d/%s" % (self.name if self.name else '',
self.portnum,
self.proto)
if self.aliases:
X("line=%s, aliases=%s", line, self.aliases)
line += ' ' + ' '.join(self.aliases)
if self.comment:
line += ' # ' + self.comment
return line
def read_services(fp, start_lineno=1):
''' Parse the services(5) format, yield (prelines, PortInfo(portnum, proto, name, aliases)).
'''
textlines = []
for lineno, line in enumerate(fp, start_lineno):
with Pfx("%s:%d", fp, lineno):
if not line.endswith('\n'):
raise ValueError("missing terminating newline")
line0 = line[:-1]
line = line0.rstrip()
comment_pos = line.find('#')
if comment_pos >= 0:
line = line[:comment_pos].rstrip()
comment = line[comment_pos+1:].strip()
else:
comment = ''
words = line.split()
if not words:
textlines.append(line0)
continue
if line[0].isspace():
name = None
else:
name = words.pop(0)
with Pfx(name):
try:
portspec = words.pop(0)
except IndexError:
raise ValueError("missing portnum/proto")
with Pfx(portspec):
try:
portnum, proto = portspec.split('/')
portnum = int(portnum)
proto = proto.lower()
except ValueError as e:
raise ValueError("invalid portspec: %s" % (e,))
yield textlines, PortInfo(portnum, proto, name, words, comment)
textlines = []
if textlines:
yield textlines, None
def merge_services(fp, portmap=None, namemap=None):
if portmap is None:
portmap = OrderedDict() # mapping from (portnum, proto) to PortInfo
if namemap is None:
namemap = {} # mapping from name or alias to PortInfo
for prelines, PI in read_services(fp):
##X("PI=%s, %d prelines", PI, len(prelines))
prelines = list(prelines)
##for line in prelines:
## print(line)
if PI is None:
continue
##print(PI.line())
key = PI.portnum, PI.name
if key not in portmap:
portmap[key] = (PI, prelines)
else:
PI0, prelines = portmap[key]
if PI.name is not None:
PI0.aliases.append(PI.name)
PI0.aliases.extend(PI.aliases)
if PI.comment:
PI0.comments.append("; "+PI.comment)
prelines.extend(prelines)
names = []
if PI.name is not None:
names.append(PI.name)
names.extend(PI.aliases)
for name in set(names):
key = name + '/' + PI.proto
if key not in namemap:
namemap[key] = PI
return portmap, namemap