~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to setup.py

  • Committer: mattgiuca
  • Date: 2007-12-21 00:10:32 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:110
setup.py: Added to trampoline/conf.h an "allowed_uids" array. Asks the user
    for a single allowed UID.
trampoline/trampoline.c: Checks this array against the current UID who called
    the program, and exits early unless the UID is root, or on the whitelist.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
# Date:   12/12/2007
22
22
 
23
23
# This is a command-line application, for use by the administrator.
24
 
# This program is a frontend for the modules in the setup packages that 
25
 
# build and install IVLE in separate steps.
 
24
# This program configures, builds and installs IVLE in three separate steps.
26
25
# It is called with at least one argument, which specifies which operation to
27
26
# take.
28
27
 
 
28
# setup.py conf [args]
 
29
# Configures IVLE with machine-specific details, most notably, various paths.
 
30
# Either prompts the administrator for these details or accepts them as
 
31
# command-line args.
 
32
# Creates www/conf/conf.py and trampoline/conf.h.
 
33
 
 
34
# setup.py build
 
35
# Compiles all files and sets up a jail template in the source directory.
 
36
# Details:
 
37
# Compiles (GCC) trampoline/trampoline.c to trampoline/trampoline.
 
38
# Creates jail/.
 
39
# Creates standard subdirs inside the jail, eg bin, opt, home, tmp.
 
40
# Copies console/ to a location within the jail.
 
41
# Copies OS programs and files to corresponding locations within the jail
 
42
#   (eg. python and Python libs, ld.so, etc).
 
43
# Generates .pyc files for all the IVLE .py files.
 
44
 
 
45
# setup.py listmake (for developer use only)
 
46
# Recurses through the source tree and builds a list of all files which should
 
47
# be copied upon installation. This should be run by the developer before
 
48
# cutting a distribution, and the listfile it generates should be included in
 
49
# the distribution, avoiding the administrator having to run it.
 
50
 
 
51
# setup.py install [--nojail] [--dry|n]
 
52
# (Requires root)
 
53
# Create target install directory ($target).
 
54
# Create $target/bin.
 
55
# Copy trampoline/trampoline to $target/bin.
 
56
# chown and chmod the installed trampoline.
 
57
# Copy www/ to $target.
 
58
# Copy jail/ to jails template directory (unless --nojail specified).
 
59
 
 
60
# TODO: List in help, and handle, args for the conf operation
 
61
 
 
62
import os
29
63
import sys
30
 
import setup.build
31
 
import setup.install
 
64
import getopt
 
65
import string
 
66
import errno
 
67
 
 
68
# Main function skeleton from Guido van Rossum
 
69
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
 
70
 
 
71
class Usage(Exception):
 
72
    def __init__(self, msg):
 
73
        self.msg = msg
32
74
 
33
75
def main(argv=None):
34
76
    if argv is None:
37
79
    # Print the opening spiel including the GPL notice
38
80
 
39
81
    print """IVLE - Informatics Virtual Learning Environment Setup
40
 
Copyright (C) 2007-2009 The University of Melbourne
 
82
Copyright (C) 2007-2008 The University of Melbourne
41
83
IVLE comes with ABSOLUTELY NO WARRANTY.
42
84
This is free software, and you are welcome to redistribute it
43
85
under certain conditions. See LICENSE.txt for details.
53
95
        help([])
54
96
        return 1
55
97
 
56
 
    oper_func = call_operator(operation)
57
 
    return oper_func(argv[2:])
 
98
    # Call the requested operation's function
 
99
    try:
 
100
        return {
 
101
            'help' : help,
 
102
            'conf' : conf,
 
103
            'build' : build,
 
104
            'listmake' : listmake,
 
105
            'install' : install,
 
106
        }[operation](argv[2:])
 
107
    except KeyError:
 
108
        print >>sys.stderr, (
 
109
            """Invalid operation '%s'. Try python setup.py help."""
 
110
            % operation)
 
111
 
 
112
    try:
 
113
        try:
 
114
            opts, args = getopt.getopt(argv[1:], "h", ["help"])
 
115
        except getopt.error, msg:
 
116
            raise Usage(msg)
 
117
        # more code, unchanged
 
118
    except Usage, err:
 
119
        print >>sys.stderr, err.msg
 
120
        print >>sys.stderr, "for help use --help"
 
121
        return 2
 
122
 
 
123
# Operation functions
58
124
 
59
125
def help(args):
60
 
    if len(args)!=1:
61
 
        print """Usage: python setup.py operation [options]
62
 
Operation can be:
 
126
    if args == []:
 
127
        print """Usage: python setup.py operation [args]
 
128
Operation (and args) can be:
63
129
    help [operation]
 
130
    conf [args]
64
131
    build
65
 
    install
66
 
 
67
 
    For help and options for a specific operation use 'help [operation]'."""
68
 
    else:
69
 
        operator = args[0]
70
 
        oper_func = call_operator(operator)
71
 
        oper_func(['operator','--help'])
72
 
 
73
 
def call_operator(operation):
74
 
    # Call the requested operation's function
75
 
    try:
76
 
        oper_func = {
77
 
            'help' : help,
78
 
            'build' : setup.build.build,
79
 
            'install' : setup.install.install,
80
 
        }[operation]
81
 
    except KeyError:
 
132
    install [--nojail] [-n|--dry]
 
133
"""
 
134
        return 1
 
135
    elif len(args) != 1:
 
136
        print """Usage: python setup.py help [operation]"""
 
137
        return 2
 
138
    else:
 
139
        operation = args[0]
 
140
 
 
141
    if operation == 'help':
 
142
        print """python setup.py help [operation]
 
143
Prints the usage message or detailed help on an operation, then exits."""
 
144
    elif operation == 'conf':
 
145
        print """python setup.py conf [args]
 
146
Configures IVLE with machine-specific details, most notably, various paths.
 
147
Either prompts the administrator for these details or accepts them as
 
148
command-line args.
 
149
Creates www/conf/conf.py and trampoline/conf.h.
 
150
Args are:
 
151
"""
 
152
    elif operation == 'build':
 
153
        print """python setup.py build
 
154
Compiles all files and sets up a jail template in the source directory.
 
155
Details:
 
156
Compiles (GCC) trampoline/trampoline.c to trampoline/trampoline.
 
157
Creates jail/.
 
158
Creates standard subdirs inside the jail, eg bin, opt, home, tmp.
 
159
Copies console/ to a location within the jail.
 
160
Copies OS programs and files to corresponding locations within the jail
 
161
  (eg. python and Python libs, ld.so, etc).
 
162
Generates .pyc files for all the IVLE .py files."""
 
163
    elif operation == 'listmake':
 
164
        print """python setup.py listmake
 
165
(For developer use only)
 
166
Recurses through the source tree and builds a list of all files which should
 
167
be copied upon installation. This should be run by the developer before
 
168
cutting a distribution, and the listfile it generates should be included in
 
169
the distribution, avoiding the administrator having to run it."""
 
170
    elif operation == 'install':
 
171
        print """sudo python setup.py install [--nojail] [--dry|-n]
 
172
(Requires root)
 
173
Create target install directory ($target).
 
174
Create $target/bin.
 
175
Copy trampoline/trampoline to $target/bin.
 
176
chown and chmod the installed trampoline.
 
177
Copy www/ to $target.
 
178
Copy jail/ to jails template directory (unless --nojail specified).
 
179
 
 
180
--nojail    Do not copy the jail.
 
181
--dry | -n  Print out the actions but don't do anything."""
 
182
    else:
82
183
        print >>sys.stderr, (
83
184
            """Invalid operation '%s'. Try python setup.py help."""
84
185
            % operation)
85
 
        sys.exit(1)
86
 
    return oper_func
 
186
    return 1
 
187
 
 
188
def conf(args):
 
189
    # Set up some variables
 
190
 
 
191
    cwd = os.getcwd()
 
192
    # the files that will be created/overwritten
 
193
    conffile = os.path.join(cwd, "www/conf/conf.py")
 
194
    conf_hfile = os.path.join(cwd, "trampoline/conf.h")
 
195
 
 
196
    # Fixed config options that we don't ask the admin
 
197
 
 
198
    default_app = "dummy"
 
199
 
 
200
    print """This tool will create the following files:
 
201
    %s
 
202
    %s
 
203
prompting you for details about your configuration. The file will be
 
204
overwritten if it already exists. It will *not* install or deploy IVLE.
 
205
 
 
206
Please hit Ctrl+C now if you do not wish to do this.
 
207
""" % (conffile, conf_hfile)
 
208
 
 
209
    # Get information from the administrator
 
210
    # If EOF is encountered at any time during the questioning, just exit
 
211
    # silently
 
212
 
 
213
    root_dir = query_user(
 
214
    """Root directory where IVLE is located (in URL space):
 
215
    (eg. "/" or "/ivle")""")
 
216
    ivle_install_dir = query_user(
 
217
    'Root directory where IVLE is located (on the local file system):\n'
 
218
    '(eg. "/home/informatics/ivle")')
 
219
    jail_base = query_user(
 
220
    """Root directory where user files are stored (on the local file system):
 
221
    (eg. "/home/informatics/jails")""")
 
222
    allowed_uid = query_user(
 
223
    """UID of the web server process which will run IVLE.
 
224
Only this user may execute the trampoline. You can configure multiple users
 
225
by manually editing conf.h.
 
226
    (eg. "1002")""")
 
227
 
 
228
    # Error handling on input values
 
229
 
 
230
    try:
 
231
        allowed_uid = int(allowed_uid)
 
232
    except ValueError:
 
233
        print >>sys.stderr, "Invalid UID (%s)." % allowed_uid
 
234
        return 1
 
235
 
 
236
    # Write www/conf/conf.py
 
237
 
 
238
    try:
 
239
        conf = open(conffile, "w")
 
240
 
 
241
        conf.write("""# IVLE Configuration File
 
242
# conf.py
 
243
# Miscellaneous application settings
 
244
 
 
245
 
 
246
# In URL space, where in the site is IVLE located. (All URLs will be prefixed
 
247
# with this).
 
248
# eg. "/" or "/ivle".
 
249
root_dir = "%s"
 
250
 
 
251
# In the local file system, where IVLE is actually installed.
 
252
# This directory should contain the "www" and "bin" directories.
 
253
ivle_install_dir = "%s"
 
254
 
 
255
# In the local file system, where are the student/user file spaces located.
 
256
# The user jails are expected to be located immediately in subdirectories of
 
257
# this location.
 
258
jail_base = "%s"
 
259
 
 
260
# Which application to load by default (if the user navigates to the top level
 
261
# of the site). This is the app's URL name.
 
262
# Note that if this app requires authentication, the user will first be
 
263
# presented with the login screen.
 
264
default_app = "%s"
 
265
""" % (root_dir, ivle_install_dir, jail_base, default_app))
 
266
 
 
267
        conf.close()
 
268
    except IOError, (errno, strerror):
 
269
        print "IO error(%s): %s" % (errno, strerror)
 
270
        sys.exit(1)
 
271
 
 
272
    print "Successfully wrote www/conf/conf.py"
 
273
 
 
274
    # Write trampoline/conf.h
 
275
 
 
276
    try:
 
277
        conf = open(conf_hfile, "w")
 
278
 
 
279
        conf.write("""/* IVLE Configuration File
 
280
 * conf.h
 
281
 * Administrator settings required by trampoline.
 
282
 * Note: trampoline will have to be rebuilt in order for changes to this file
 
283
 * to take effect.
 
284
 */
 
285
 
 
286
/* In the local file system, where are the jails located.
 
287
 * The trampoline does not allow the creation of a jail anywhere besides
 
288
 * jail_base or a subdirectory of jail_base.
 
289
 */
 
290
static const char* jail_base = "%s";
 
291
 
 
292
/* Which user IDs are allowed to run the trampoline.
 
293
 * This list should be limited to the web server user.
 
294
 * (Note that root is an implicit member of this list).
 
295
 */
 
296
static const int allowed_uids[] = { %d };
 
297
""" % (jail_base, allowed_uid))
 
298
 
 
299
        conf.close()
 
300
    except IOError, (errno, strerror):
 
301
        print "IO error(%s): %s" % (errno, strerror)
 
302
        sys.exit(1)
 
303
 
 
304
    print "Successfully wrote trampoline/conf.h"
 
305
 
 
306
    print
 
307
    print "You may modify the configuration at any time by editing"
 
308
    print conffile
 
309
    print conf_hfile
 
310
    print
 
311
    return 0
 
312
 
 
313
def build(args):
 
314
    dry = False     # Set to True later if --dry
 
315
 
 
316
    # Compile the trampoline
 
317
    action_runprog('gcc', ['-Wall', '-o', 'trampoline/trampoline',
 
318
        'trampoline/trampoline.c'], dry)
 
319
 
 
320
    # Create the jail and its subdirectories
 
321
    action_mkdir('jail')
 
322
    action_mkdir('jail/bin')
 
323
    action_mkdir('jail/lib')
 
324
    action_mkdir('jail/usr')
 
325
    action_mkdir('jail/usr/bin')
 
326
    action_mkdir('jail/usr/lib')
 
327
    action_mkdir('jail/opt')
 
328
    action_mkdir('jail/home')
 
329
    action_mkdir('jail/tmp')
 
330
 
 
331
    # TODO: Copy console into the jail
 
332
    # TODO: Copy operating system files into the jail
 
333
    # TODO: Compile .py files into .pyc files
 
334
 
 
335
    return 0
 
336
 
 
337
def listmake(args):
 
338
    print "Listmake"
 
339
    return 0
 
340
 
 
341
def install(args):
 
342
    print "Install"
 
343
    return 0
 
344
 
 
345
# The actions call Python os functions but print actions and handle dryness.
 
346
# May still throw os exceptions if errors occur.
 
347
 
 
348
class RunError:
 
349
    """Represents an error when running a program (nonzero return)."""
 
350
    def __init__(self, prog, retcode):
 
351
        self.prog = prog
 
352
        self.retcode = retcode
 
353
    def __str__(self):
 
354
        return str(self.prog) + " returned " + repr(self.retcode)
 
355
 
 
356
def action_runprog(prog, args, dry):
 
357
    """Runs a unix program. Searches in $PATH. Synchronous (waits for the
 
358
    program to return). Runs in the current environment. First prints the
 
359
    action as a "bash" line.
 
360
 
 
361
    Throws a RunError with a retcode of the return value of the program,
 
362
    if the program did not return 0.
 
363
 
 
364
    prog: String. Name of the program. (No path required, if in $PATH).
 
365
    args: [String]. Arguments to the program.
 
366
    dry: Bool. If True, prints but does not execute.
 
367
    """
 
368
    print prog, string.join(args, ' ')
 
369
    if not dry:
 
370
        ret = os.spawnvp(os.P_WAIT, prog, args)
 
371
        if ret != 0:
 
372
            raise RunError(prog, ret)
 
373
 
 
374
def action_mkdir(path):
 
375
    """Calls mkdir. Silently ignored if the directory already exists."""
 
376
    print "mkdir", path
 
377
    try:
 
378
        os.mkdir(path)
 
379
    except OSError, (err, msg):
 
380
        if err != errno.EEXIST:
 
381
            raise
 
382
 
 
383
def query_user(prompt):
 
384
    """Prompts the user for a string, which is read from a line of stdin.
 
385
    Exits silently if EOF is encountered. Returns the string, with spaces
 
386
    removed from the beginning and end.
 
387
    """
 
388
    sys.stdout.write(prompt)
 
389
    sys.stdout.write("\n>")
 
390
    try:
 
391
        val = sys.stdin.readline()
 
392
    except KeyboardInterrupt:
 
393
        # Ctrl+C
 
394
        sys.stdout.write("\n")
 
395
        sys.exit(1)
 
396
    sys.stdout.write("\n")
 
397
    if val == '': sys.exit(1)
 
398
    return val.strip()
87
399
 
88
400
if __name__ == "__main__":
89
401
    sys.exit(main())
90