~ubuntu-branches/ubuntu/raring/lsb/raring-proposed

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()