Git init
[external/lsb.git] / initdutils.py
1 # Support for scanning init scripts for LSB info
2
3 import re, sys, os, cStringIO
4 import cPickle
5
6 try:
7     assert True
8 except:
9     True = 1
10     False = 0
11
12 class RFC822Parser(dict):
13     "A dictionary-like object."
14     __linere = re.compile(r'([^:]+):\s*(.*)$')
15     
16     def __init__(self, fileob=None, strob=None, startcol=0, basedict=None):
17         if not fileob and not strob:
18             raise ValueError, 'need a file or string'
19         if not basedict:
20             basedict = {}
21         
22         super(RFC822Parser, self).__init__(basedict)
23
24         if not fileob:
25             fileob = cStringIO.StringIO(strob)
26
27         key = None
28         for line in fileob:
29             if startcol:
30                 line = line[startcol:]
31
32             if not line.strip():
33                 continue
34
35             # Continuation line
36             if line[0].isspace():
37                 if not key:
38                     continue
39                 self[key] += '\n' + line.strip()
40                 continue
41
42             m = self.__linere.match(line)
43             if not m:
44                 # Not a valid RFC822 header
45                 continue
46             key, value = m.groups()
47             self[key] = value.strip()
48
49 # End of RFC882Parser
50
51 LSBLIB = '/var/lib/lsb'
52 FACILITIES = os.path.join(LSBLIB, 'facilities')
53 DEPENDS = os.path.join(LSBLIB, 'depends')
54 LSBINSTALL = os.path.join(LSBLIB, 'lsbinstall')
55
56 beginre = re.compile(re.escape('### BEGIN INIT INFO'))
57 endre = re.compile(re.escape('### END INIT INFO'))
58 #linere = re.compile(r'\#\s+([^:]+):\s*(.*)')
59
60 def scan_initfile(initfile):
61     headerlines = ''
62     scanning = False
63     
64     for line in file(initfile):
65         line = line.rstrip()
66         if beginre.match(line):
67             scanning = True
68             continue
69         elif scanning and endre.match(line):
70             scanning = False
71             continue
72         elif not scanning:
73             continue
74
75         if line.startswith('# '):
76             headerlines += line[2:] + '\n'
77         elif line.startswith('#\t'):
78             headerlines += line[1:] + '\n'
79
80     inheaders = RFC822Parser(strob=headerlines)
81     headers = {}
82     for header, body in inheaders.iteritems():
83         # Ignore empty headers
84         if not body.strip():
85             continue
86         
87         if header in ('Default-Start', 'Default-Stop'):
88             headers[header] = map(int, body.split())
89         elif header in ('Required-Start', 'Required-Stop', 'Provides',
90                         'Should-Start', 'Should-Stop'):
91             headers[header] = body.split()
92         else:
93             headers[header] = body
94
95     return headers
96
97 def save_facilities(facilities):
98     if not facilities:
99         try:
100             os.unlink(FACILITIES)
101         except OSError:
102             pass
103         return
104     
105     fh = file(FACILITIES, 'w')
106     for facility, entries in facilities.items():
107         # Ignore system facilities
108         if facility.startswith('$'): continue
109         for (scriptname, pri) in entries.items():
110             start, stop = pri
111             print >> fh, "%(scriptname)s %(facility)s %(start)d %(stop)d" % locals()
112     fh.close()
113
114 def load_facilities():
115     facilities = {}
116     if os.path.exists(FACILITIES):
117         for line in open(FACILITIES).xreadlines():
118             try:
119                 scriptname, name, start, stop = line.strip().split()
120                 facilities.setdefault(name, {})[scriptname] = (int(start),
121                                                                int(stop))
122             except ValueError, x:
123                 print >> sys.stderr, 'Invalid facility line', line
124
125     return facilities
126
127 def load_depends():
128     depends = {}
129
130     if os.path.exists(DEPENDS):
131         independs = RFC822Parser(fileob=file(DEPENDS))
132         for initfile, facilities in independs.iteritems():
133             depends[initfile] = facilities.split()
134     return depends
135
136 def save_depends(depends):
137     if not depends:
138         try:
139             os.unlink(DEPENDS)
140         except OSError:
141             pass
142         return
143     
144     fh = file(DEPENDS, 'w')
145     for initfile, facilities in depends.iteritems():
146         print >> fh, '%s: %s' % (initfile, ' '.join(facilities))
147     fh.close()
148
149 # filemap entries are mappings, { (package, filename) : instloc }
150 def load_lsbinstall_info():
151     if not os.path.exists(LSBINSTALL):
152         return {}
153     
154     fh = open(LSBINSTALL, 'rb')
155     filemap = cPickle.load(fh)
156     fh.close()
157
158     # Just in case it's corrupted somehow
159     if not isinstance(filemap, dict):
160         return {}
161
162     return filemap
163
164 def save_lsbinstall_info(filemap):
165     if not filemap:
166         try:
167             os.unlink(LSBINSTALL)
168         except OSError:
169             pass
170         return
171     
172     fh = open(LSBINSTALL, 'wb')
173     cPickle.dump(fh, filemap)
174     fh.close()
175
176 if __name__ == '__main__':
177     print scan_initfile('init-fragment')