71
# Import modules from the website is tricky since they're in the www
73
sys.path.append(os.path.join(os.getcwd(), 'www'))
75
import common.makeuser
77
# Operating system files to copy over into the jail.
78
# These will be copied from the given place on the OS file system into the
79
# same place within the jail.
82
'/lib/tls/i686/cmov/libc.so.6',
83
'/lib/tls/i686/cmov/libdl.so.2',
84
'/lib/tls/i686/cmov/libm.so.6',
85
'/lib/tls/i686/cmov/libpthread.so.0',
86
'/lib/tls/i686/cmov/libutil.so.1',
89
# These 2 files do not exist in Ubuntu
90
#'/etc/ld.so.preload',
91
#'/etc/ld.so.nohwcap',
98
# Needed by matplotlib
99
'/usr/lib/i686/cmov/libssl.so.0.9.8',
100
'/usr/lib/i686/cmov/libcrypto.so.0.9.8',
101
'/lib/tls/i686/cmov/libnsl.so.1',
102
'/usr/lib/libz.so.1',
103
'/usr/lib/atlas/liblapack.so.3',
104
'/usr/lib/atlas/libblas.so.3',
105
'/usr/lib/libg2c.so.0',
106
'/usr/lib/libstdc++.so.6',
107
'/usr/lib/libfreetype.so.6',
108
'/usr/lib/libpng12.so.0',
109
'/usr/lib/libBLT.2.4.so.8.4',
110
'/usr/lib/libtk8.4.so.0',
111
'/usr/lib/libtcl8.4.so.0',
112
'/usr/lib/tcl8.4/init.tcl',
113
'/usr/lib/libX11.so.6',
114
'/usr/lib/libXau.so.6',
115
'/usr/lib/libXdmcp.so.6',
116
'/lib/libgcc_s.so.1',
119
# Symlinks to make within the jail. Src mapped to dst.
121
'python2.5': 'jail/usr/bin/python',
123
# Trees to copy. Src mapped to dst (these will be passed to action_copytree).
125
'/usr/lib/python2.5': 'jail/usr/lib/python2.5',
126
'/usr/share/matplotlib': 'jail/usr/share/matplotlib',
127
'/etc/ld.so.conf.d': 'jail/etc/ld.so.conf.d',
130
71
# Try importing existing conf, but if we can't just set up defaults
131
72
# The reason for this is that these settings are used by other phases
132
73
# of setup besides conf, so we need to know them.
143
84
ivle_install_dir = "/opt/ivle"
145
public_host = confmodule.public_host
147
public_host = "public.localhost"
149
86
jail_base = confmodule.jail_base
151
88
jail_base = "/home/informatics/jails"
153
subjects_base = confmodule.subjects_base
155
subjects_base = "/home/informatics/subjects"
156
89
except ImportError:
157
90
# Just set reasonable defaults
158
91
root_dir = "/ivle"
159
92
ivle_install_dir = "/opt/ivle"
160
public_host = "public.localhost"
161
93
jail_base = "/home/informatics/jails"
162
subjects_base = "/home/informatics/subjects"
164
95
allowed_uids = "0"
176
107
# as necessary, and include it in the distribution.
177
108
listmake_mimetypes = ['text/x-python', 'text/html',
178
109
'application/x-javascript', 'application/javascript',
179
'text/css', 'image/png', 'application/xml']
110
'text/css', 'image/png']
181
112
# Main function skeleton from Guido van Rossum
182
113
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
301
228
chown and chmod the installed trampoline.
302
229
Copy www/ to $target.
303
230
Copy jail/ to jails template directory (unless --nojail specified).
304
Copy subjects/ to subjects directory (unless --nosubjects specified).
306
--nojail Do not copy the jail.
307
--nosubjects Do not copy the subjects.
308
--dry | -n Print out the actions but don't do anything."""
309
elif operation == 'updatejails':
310
print """sudo python setup.py updatejails [--dry|-n]
312
Copy jail/ to each subdirectory in jails directory.
232
--nojail Do not copy the jail.
314
233
--dry | -n Print out the actions but don't do anything."""
316
235
print >>sys.stderr, (
322
241
# We build two separate lists, by walking www and console
323
242
list_www = build_list_py_files('www')
324
243
list_console = build_list_py_files('console')
325
list_subjects = build_list_py_files('subjects', no_top_level=True)
326
244
# Make sure that the files generated by conf are in the list
327
245
# (since listmake is typically run before conf)
328
246
if "www/conf/conf.py" not in list_www:
352
270
# List of all installable files in console directory.
353
271
list_console = """)
354
272
writelist_pretty(file, list_console)
356
# List of all installable files in subjects directory.
357
# This is to install sample subjects and material.
359
writelist_pretty(file, list_subjects)
362
275
except IOError, (errno, strerror):
376
def build_list_py_files(dir, no_top_level=False):
289
def build_list_py_files(dir):
377
290
"""Builds a list of all py files found in a directory and its
378
subdirectories. Returns this as a list of strings.
379
no_top_level=True means the file paths will not include the top-level
291
subdirectories. Returns this as a list of strings."""
383
293
for (dirpath, dirnames, filenames) in os.walk(dir):
384
294
# Exclude directories beginning with a '.' (such as '.svn')
386
296
# All *.py files are added to the list
387
297
pylist += [os.path.join(dirpath, item) for item in filenames
388
298
if mimetypes.guess_type(item)[0] in listmake_mimetypes]
390
for i in range(0, len(pylist)):
391
_, pylist[i] = pylist[i].split(os.sep, 1)
394
301
def writelist_pretty(file, list):
444
350
jail_base = query_user(jail_base,
445
351
"""Root directory where the jails (containing user files) are stored
446
352
(on the local file system):""")
447
subjects_base = query_user(subjects_base,
448
"""Root directory where the subject directories (containing worksheets
449
and other per-subject files) are stored (on the local file system):""")
450
public_host = query_user(public_host,
451
"""Hostname which will cause the server to go into "public mode",
452
providing login-free access to student's published work:""")
453
353
allowed_uids = query_user(allowed_uids,
454
354
"""UID of the web server process which will run IVLE.
455
355
Only this user may execute the trampoline. May specify multiple users as
465
365
ivle_install_dir = opts['--ivle_install_dir']
466
366
if '--jail_base' in opts:
467
367
jail_base = opts['--jail_base']
468
if '--subjects_base' in opts:
469
jail_base = opts['--subjects_base']
470
if '--public_host' in opts:
471
public_host = opts['--public_host']
472
368
if '--allowed_uids' in opts:
473
369
allowed_uids = opts['--allowed_uids']
500
396
# This directory should contain the "www" and "bin" directories.
501
397
ivle_install_dir = "%s"
503
# The server goes into "public mode" if the browser sends a request with this
504
# host. This is for security reasons - we only serve public student files on a
505
# separate domain to the main IVLE site.
506
# Public mode does not use cookies, and serves only public content.
507
# Private mode (normal mode) requires login, and only serves files relevant to
508
# the logged-in user.
511
399
# In the local file system, where are the student/user file spaces located.
512
400
# The user jails are expected to be located immediately in subdirectories of
516
# In the local file system, where are the per-subject file spaces located.
517
# The individual subject directories are expected to be located immediately
518
# in subdirectories of this location.
520
""" % (root_dir, ivle_install_dir, public_host, jail_base, subjects_base))
403
""" % (root_dir, ivle_install_dir, jail_base))
523
406
except IOError, (errno, strerror):
587
470
# Copy all console and operating system files into the jail
588
471
action_copylist(install_list.list_console, 'jail/opt/ivle', dry)
589
472
copy_os_files_jail(dry)
590
# Chmod the python console
591
action_chmod_x('jail/opt/ivle/console/python-console', dry)
594
474
# Compile .py files into .pyc or .pyo files
595
475
compileall.compile_dir('www', quiet=True)
601
481
"""Copies necessary Operating System files from their usual locations
602
482
into the jail/ directory of the cwd."""
603
483
# Currently source paths are configured for Ubuntu.
604
for filename in JAIL_FILES:
605
copy_file_to_jail(filename, dry)
606
for src, dst in JAIL_LINKS.items():
607
action_symlink(src, dst, dry)
608
for src, dst in JAIL_COPYTREES.items():
609
action_copytree(src, dst, dry)
484
copy_file_to_jail('/lib/ld-linux.so.2', dry)
485
copy_file_to_jail('/lib/tls/i686/cmov/libc.so.6', dry)
486
copy_file_to_jail('/lib/tls/i686/cmov/libdl.so.2', dry)
487
copy_file_to_jail('/lib/tls/i686/cmov/libm.so.6', dry)
488
copy_file_to_jail('/lib/tls/i686/cmov/libpthread.so.0', dry)
489
copy_file_to_jail('/lib/tls/i686/cmov/libutil.so.1', dry)
490
copy_file_to_jail('/usr/bin/python2.5', dry)
491
action_symlink('python2.5', 'jail/usr/bin/python', dry)
492
action_copytree('/usr/lib/python2.5', 'jail/usr/lib/python2.5', dry)
611
494
def copy_file_to_jail(src, dry):
612
495
"""Copies a single file from an absolute location into the same location
617
500
def install(args):
618
501
# Get "dry" and "nojail" variables from command line
619
(opts, args) = getopt.gnu_getopt(args, "n",
620
['dry', 'nojail', 'nosubjects'])
502
(opts, args) = getopt.gnu_getopt(args, "n", ['dry', 'nojail'])
621
503
opts = dict(opts)
622
504
dry = '-n' in opts or '--dry' in opts
623
505
nojail = '--nojail' in opts
624
nosubjects = '--nosubjects' in opts
627
508
print "Dry run (no actions will be executed\n"
649
530
# to the jails template directory (it will be used as a template
650
531
# for all the students' jails).
651
532
action_copytree('jail', os.path.join(jail_base, 'template'), dry)
653
# Copy the subjects directory across
654
action_copylist(install_list.list_subjects, subjects_base, dry,
657
# Append IVLE path to ivle.pth in python site packages
658
# (Unless it's already there)
659
ivle_pth = os.path.join(sys.prefix,
660
"lib/python2.5/site-packages/ivle.pth")
661
ivle_www = os.path.join(ivle_install_dir, "www")
662
write_ivle_pth = True
664
file = open(ivle_pth, 'r')
666
if line.strip() == ivle_www:
667
write_ivle_pth = False
669
except (IOError, OSError):
672
action_append(ivle_pth, ivle_www)
676
def updatejails(args):
677
# Get "dry" variable from command line
678
(opts, args) = getopt.gnu_getopt(args, "n", ['dry'])
680
dry = '-n' in opts or '--dry' in opts
683
print "Dry run (no actions will be executed\n"
685
if not dry and os.geteuid() != 0:
686
print >>sys.stderr, "Must be root to run install"
687
print >>sys.stderr, "(I need to chown some files)."
690
# Update the template jail directory in case it hasn't been installed
692
action_copytree('jail', os.path.join(jail_base, 'template'), dry)
694
# Re-link all the files in all students jails.
695
for dir in os.listdir(jail_base):
696
if dir == 'template': continue
697
# First back up the student's home directory
698
temp_home = os.tmpnam()
699
action_rename(os.path.join(jail_base, dir, 'home'), temp_home, dry)
700
# Delete the student's jail and relink the jail files
701
action_linktree(os.path.join(jail_base, 'template'),
702
os.path.join(jail_base, dir), dry)
703
# Restore the student's home directory
704
action_rename(temp_home, os.path.join(jail_base, dir, 'home'), dry)
705
# Set up the user's home directory just in case they don't have a
706
# directory for this yet
707
action_mkdir(os.path.join(jail_base, dir, 'home', dir), dry)
738
563
raise RunError(prog, ret)
740
def action_rename(src, dst, dry):
741
"""Calls rename. Deletes the target if it already exists."""
742
if os.access(dst, os.F_OK):
745
shutil.rmtree(dst, True)
746
print "mv ", src, dst
750
except OSError, (err, msg):
751
if err != errno.EEXIST:
754
565
def action_mkdir(path, dry):
755
566
"""Calls mkdir. Silently ignored if the directory already exists.
756
567
Creates all parent directories as necessary."""
777
588
shutil.copytree(src, dst, True)
779
def action_linktree(src, dst, dry):
780
"""Hard-links an entire directory tree. Same as copytree but the created
781
files are hard-links not actual copies. Removes the existing destination.
783
if os.access(dst, os.F_OK):
786
shutil.rmtree(dst, True)
787
print "<cp with hardlinks> -r", src, dst
789
common.makeuser.linktree(src, dst)
791
def action_copylist(srclist, dst, dry, srcdir="."):
590
def action_copylist(srclist, dst, dry):
792
591
"""Copies all files in a list to a new location. The files in the list
793
592
are read relative to the current directory, and their destinations are the
794
593
same paths relative to dst. Creates all parent directories as necessary.
795
srcdir is "." by default, can be overridden.
797
595
for srcfile in srclist:
798
596
dstfile = os.path.join(dst, srcfile)
799
srcfile = os.path.join(srcdir, srcfile)
800
597
dstdir = os.path.split(dstfile)[0]
801
598
if not os.path.isdir(dstdir):
802
599
action_mkdir(dstdir, dry)
838
635
os.symlink(src, dst)
840
def action_append(ivle_pth, ivle_www):
841
file = open(ivle_pth, 'a+')
842
file.write(ivle_www + '\n')
845
637
def action_chown_setuid(file, dry):
846
638
"""Chowns a file to root, and sets the setuid bit on the file.
847
639
Calling this function requires the euid to be root.
856
648
os.chmod(file, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
857
649
| stat.S_ISUID | stat.S_IRUSR | stat.S_IWUSR)
859
def action_chmod_x(file, dry):
860
"""Chmod +xs a file (sets execute permission)."""
861
print "chmod u+rwx", file
863
os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR)
865
651
def query_user(default, prompt):
866
652
"""Prompts the user for a string, which is read from a line of stdin.
867
653
Exits silently if EOF is encountered. Returns the string, with spaces