5
by Colin Watson
Resynchronise with Debian. |
1 |
#!/usr/bin/python
|
2 |
||
3 |
import sys |
|
4 |
import os |
|
5 |
import shutil |
|
6 |
import socket |
|
22
by Matthias Klose
* Merge with Debian; remaining changes: |
7 |
import commands |
5
by Colin Watson
Resynchronise with Debian. |
8 |
from tempfile import NamedTemporaryFile |
9 |
from initdutils import load_lsbinstall_info, save_lsbinstall_info |
|
10 |
||
11 |
# These keep getting revised... *sigh*
|
|
12 |
objecttypes = ( |
|
13 |
#'init',
|
|
14 |
'profile', |
|
15 |
'service', |
|
22
by Matthias Klose
* Merge with Debian; remaining changes: |
16 |
'inet', # XXX - reenable when implemented |
5
by Colin Watson
Resynchronise with Debian. |
17 |
#'crontab',
|
18 |
#'man'
|
|
19 |
)
|
|
20 |
||
21 |
def installed_message(objectname): |
|
22 |
print objectname, 'is installed' |
|
23 |
||
24 |
def handle_generic_install(options, args, location, showinstloc=False): |
|
25 |
filename = args[0] |
|
26 |
basename = os.path.basename(filename) |
|
27 |
instloc = os.path.join(location, basename) |
|
28 |
package = args.package |
|
29 |
||
30 |
filemap = load_lsbinstall_info() |
|
31 |
fileinfo = filemap.get((package, filename)) |
|
32 |
||
33 |
if options.check: |
|
34 |
if fileinfo and os.path.exists(fileinfo): |
|
35 |
installed_message(fileinfo) |
|
36 |
return
|
|
37 |
else: |
|
38 |
sys.exit(1) |
|
39 |
elif options.remove: |
|
40 |
if os.path.exists(fileinfo): |
|
41 |
try: |
|
42 |
os.unlink(fileinfo) |
|
43 |
except (IOError, OSError, os.error), why: |
|
44 |
print >> sys.stderr, 'Removal of %s failed: %s' % ( |
|
45 |
instloc, str(why)) |
|
46 |
sys.exit(1) |
|
47 |
||
48 |
# Remove it from the database, even if it was previously removed
|
|
49 |
del filemap[(package, filename)] |
|
50 |
save_lsbinstall_info(filemap) |
|
51 |
return
|
|
52 |
||
53 |
if os.path.exists(instloc) and options.package: |
|
54 |
instloc = os.path.join(location, '%s.%s' % (options.package, basename)) |
|
55 |
||
56 |
if os.path.exists(instloc): |
|
57 |
print >> sys.stderr, 'Unable to install %s: %s exists' % ( |
|
58 |
filename, instloc) |
|
59 |
sys.exit(1) |
|
60 |
||
61 |
if not os.path.exists(location): |
|
62 |
try: |
|
63 |
os.makedirs(location) |
|
64 |
except (IOError, OSError, os.error), why: |
|
65 |
print >> sys.stderr, 'Unable to create %s to install %s: %s' % ( |
|
66 |
location, filename, str(why)) |
|
67 |
sys.exit(1) |
|
68 |
||
69 |
try: |
|
70 |
shutil.copy2(filename, instloc) |
|
71 |
except (IOError, os.error), why: |
|
72 |
print >> sys.stderr, 'Installation of %s as %s failed: %s' % ( |
|
73 |
filename, instloc, str(why)) |
|
74 |
sys.exit(1) |
|
75 |
||
76 |
if showinstloc: |
|
77 |
print instloc |
|
78 |
||
79 |
filemap[(package, filename)] = instloc |
|
80 |
save_lsbinstall_info(filemap) |
|
81 |
||
82 |
def handle_service(options, args): |
|
83 |
# LSB says we don't actually have to remove these things...
|
|
84 |
if options.remove: |
|
85 |
sys.exit(0) |
|
86 |
||
87 |
pkg = options.package or '<unknown package>' |
|
88 |
||
89 |
try: |
|
90 |
pproto = args[0] |
|
91 |
port, proto = pproto.split('/', 1) |
|
92 |
port = int(port) |
|
93 |
except: |
|
94 |
print >> sys.stderr, 'You must specify a port/protocol pair as the first argument.' |
|
95 |
sys.exit(2) |
|
96 |
||
97 |
if options.check: |
|
98 |
try: |
|
99 |
serv = socket.getservbyport(port, proto) |
|
100 |
except socket.error: |
|
101 |
sys.exit(1) |
|
102 |
||
103 |
print '%d/%s corresponds to service %s' % (port, proto, serv) |
|
104 |
return
|
|
105 |
||
106 |
sname = args[1] |
|
107 |
saliases = args[2:] |
|
108 |
||
109 |
try: |
|
110 |
serv = socket.getservbyport(port, proto) |
|
111 |
except socket.error: |
|
112 |
serv = None |
|
113 |
||
114 |
if serv: |
|
115 |
# Editing existing service
|
|
116 |
fpin = open('/etc/services') |
|
117 |
fpout = NamedTemporaryFile('w', prefix='services-', dir='/etc') |
|
118 |
newfname = fpout.name |
|
119 |
||
120 |
for line in fpin: |
|
121 |
line = line.rstrip() |
|
122 |
if not line.startswith('#'): |
|
123 |
lcomment = '' |
|
124 |
if '#' in line: |
|
125 |
line, lcomment = line.split('#', 1) |
|
126 |
||
127 |
bits = line.split(None, 2) |
|
128 |
lname, lpproto = bits[:2] |
|
129 |
laliases = [] |
|
130 |
if len(bits) > 2: |
|
131 |
laliases = bits[2].split() |
|
132 |
||
133 |
lport, lproto = lpproto.split('/') |
|
134 |
lport = int(lport) |
|
135 |
||
136 |
if lport == port and lproto == proto: |
|
137 |
# We've found the right line
|
|
138 |
if name != lname: |
|
139 |
aliases += [name] |
|
140 |
||
141 |
for a in aliases: |
|
142 |
if a != lname and a not in laliases: |
|
143 |
laliases += [a] |
|
144 |
elif name == lname or name in laliases: |
|
145 |
# name shows up, but in wrong protocol/port
|
|
146 |
print >> sys.stderr, 'Conflict between specified addition and /etc/services; aborting.' |
|
147 |
fpout.close() |
|
148 |
os.unlink(newfname) |
|
149 |
sys.exit(1) |
|
150 |
||
151 |
endbits = '' |
|
152 |
if laliases: |
|
153 |
endbits = ' '.join(laliases) + ' ' |
|
154 |
if lcomment: |
|
155 |
endbits += '#'+lcomment |
|
156 |
||
157 |
line = '%15s %15s %s' % lname, lpproto, endbits |
|
158 |
line = line.rstrip() |
|
159 |
||
160 |
print >> fpout, line |
|
161 |
||
162 |
fpin.close() |
|
163 |
fpout.close() |
|
164 |
# Make sure /etc/services is always available
|
|
165 |
shutil.copy2('/etc/services', '/etc/services~') |
|
166 |
os.rename(newfname, '/etc/services') |
|
167 |
return
|
|
168 |
||
169 |
fp = open('/etc/services', 'a') |
|
170 |
print >> fp, '%15s %15s %s # Added by lsbinstall for %s' % ( |
|
171 |
sname, pproto, ' '.join(saliases), pkg) |
|
172 |
fp.close() |
|
173 |
||
22
by Matthias Klose
* Merge with Debian; remaining changes: |
174 |
def handle_inet(options, args, parser): |
175 |
cmd = 'update-inetd --group LSB ' |
|
176 |
||
177 |
alist = list(args[0].split(':')) |
|
178 |
if len(alist) < 2: |
|
179 |
parser.error("The operand must include a service and protocol.") |
|
180 |
return
|
|
181 |
||
182 |
if not alist[1]: |
|
183 |
alist[1] = 'tcp' |
|
184 |
||
185 |
if options.remove: |
|
186 |
parts = r'%s\s+.*\s+%s\s+.*' % (re.escape(alist[0], alist[1])) |
|
187 |
cmd += '--remove '+commands.mkarg(parts) |
|
188 |
elif options.check: |
|
189 |
return
|
|
190 |
else: |
|
191 |
if len(alist) != 6: |
|
192 |
parser.error('The operand must have six colon-separated arguments.') |
|
193 |
return
|
|
194 |
newalist = [alist[0], alist[2], alist[1]] + alist[3:] |
|
195 |
cmd += '--add '+commands.mkarg('\t'.join(newalist)) |
|
196 |
||
197 |
os.system(cmd) |
|
5
by Colin Watson
Resynchronise with Debian. |
198 |
pass
|
199 |
||
200 |
def handle_man(options, args): |
|
201 |
# Try to figure out the man page section
|
|
202 |
section = 1 |
|
203 |
||
204 |
location = '/usr/local/share/man/man%d/' % section |
|
205 |
||
206 |
handle_generic_install(options, args, location) |
|
207 |
||
208 |
||
209 |
def main(): |
|
210 |
from optparse import OptionParser |
|
211 |
||
212 |
parser = OptionParser('usage: %prog [-r|-c] -t TYPE arguments...') |
|
213 |
parser.add_option('-c', '--check', dest="check", default=False, |
|
214 |
action="store_true", help='check whether or not an ' |
|
215 |
'object of this type is already installed') |
|
216 |
parser.add_option('-r', '--remove', action="store_true", |
|
217 |
dest="remove", default=False, |
|
218 |
help='remove the named object') |
|
219 |
parser.add_option('-t', '--type', dest="type", type='choice', |
|
220 |
default=None, choices=objecttypes, |
|
221 |
help='type of object to be ' |
|
222 |
'installed: one of %s' % ', '.join(objecttypes) ) |
|
223 |
parser.add_option('-p', '--package', dest="package", default=None, |
|
224 |
help='LSB package to operate on') |
|
225 |
||
226 |
(options, args) = parser.parse_args() |
|
227 |
||
228 |
if len(args) < 1: |
|
229 |
parser.error('You must specify at least one argument.') |
|
230 |
elif (options.remove or options.check) and len(args) > 1: |
|
231 |
parser.error('You may only specify one argument with --check or ' |
|
232 |
'--remove.') |
|
233 |
||
234 |
if not options.type: |
|
235 |
parser.error('You must specify an object type.') |
|
236 |
||
237 |
if not options.package and options.type not in ['service']: |
|
238 |
parser.error('You must specify a package with %s objects.' % |
|
239 |
options.type) |
|
240 |
||
241 |
if options.type == 'init': |
|
242 |
if len(args) > 1: |
|
243 |
parser.error('Only one argument supported for %s' % options.type) |
|
244 |
handle_generic_install(options, args, '/etc/init.d', showinstloc=True) |
|
245 |
elif options.type == 'profile': |
|
246 |
if len(args) > 1: |
|
247 |
parser.error('Only one argument supported for %s' % options.type) |
|
248 |
# profile.d does nothing on Debian... sigh
|
|
249 |
handle_generic_install(options, args, '/etc/profile.d') |
|
250 |
elif options.type == 'service': |
|
251 |
if len(args) < 2 and not (options.remove or options.check): |
|
252 |
parser.error('You must specify at least two arguments when adding a service entry.') |
|
253 |
elif len(args) != 1 and (options.remove or options.check): |
|
254 |
parser.error('You must specify one argument when removing or checking a service entry.') |
|
255 |
handle_service(options, args) |
|
256 |
elif options.type == 'inet': |
|
22
by Matthias Klose
* Merge with Debian; remaining changes: |
257 |
handle_inet(options, args, parser) |
5
by Colin Watson
Resynchronise with Debian. |
258 |
elif options.type == 'crontab': |
259 |
if len(args) > 1: |
|
260 |
parser.error('Only one argument supported for %s' % options.type) |
|
261 |
handle_generic_install(options, args, '/etc/cron.d') |
|
262 |
elif options.type == 'man': |
|
263 |
if len(args) > 1: |
|
264 |
parser.error('Only one argument supported for %s' % options.type) |
|
265 |
handle_man(options, args) |
|
266 |
else: |
|
267 |
print >> sys.stderr, 'Unsupported type %s' % options.type |
|
268 |
sys.exit(1) |
|
269 |
||
270 |
if __name__ == '__main__': |
|
271 |
main() |