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',
71
130
# Try importing existing conf, but if we can't just set up defaults
72
131
# The reason for this is that these settings are used by other phases
73
132
# of setup besides conf, so we need to know them.
74
133
# Also this allows you to hit Return to accept the existing value.
76
135
confmodule = __import__("www/conf/conf")
77
root_dir = confmodule.root_dir
78
ivle_install_dir = confmodule.ivle_install_dir
79
jail_base = confmodule.jail_base
137
root_dir = confmodule.root_dir
141
ivle_install_dir = confmodule.ivle_install_dir
143
ivle_install_dir = "/opt/ivle"
145
public_host = confmodule.public_host
147
public_host = "public.localhost"
149
jail_base = confmodule.jail_base
151
jail_base = "/home/informatics/jails"
153
subjects_base = confmodule.subjects_base
155
subjects_base = "/home/informatics/subjects"
80
156
except ImportError:
81
157
# Just set reasonable defaults
82
158
root_dir = "/ivle"
83
159
ivle_install_dir = "/opt/ivle"
160
public_host = "public.localhost"
84
161
jail_base = "/home/informatics/jails"
162
subjects_base = "/home/informatics/subjects"
86
164
allowed_uids = "0"
175
262
Either prompts the administrator for these details or accepts them as
176
263
command-line args. Will be interactive only if there are no arguments given.
177
264
Takes defaults from existing conf file if it exists.
266
To run IVLE out of the source directory (allowing development without having
267
to rebuild/install), just provide ivle_install_dir as the IVLE trunk
268
directory, and run build/install one time.
178
270
Creates www/conf/conf.py and trampoline/conf.h.
181
274
--ivle_install_dir
184
279
As explained in the interactive prompt or conf.py.
331
430
jail_base = query_user(jail_base,
332
431
"""Root directory where the jails (containing user files) are stored
333
432
(on the local file system):""")
433
subjects_base = query_user(subjects_base,
434
"""Root directory where the subject directories (containing worksheets
435
and other per-subject files) are stored (on the local file system):""")
436
public_host = query_user(public_host,
437
"""Hostname which will cause the server to go into "public mode",
438
providing login-free access to student's published work:""")
334
439
allowed_uids = query_user(allowed_uids,
335
440
"""UID of the web server process which will run IVLE.
336
441
Only this user may execute the trampoline. May specify multiple users as
377
486
# This directory should contain the "www" and "bin" directories.
378
487
ivle_install_dir = "%s"
489
# The server goes into "public mode" if the browser sends a request with this
490
# host. This is for security reasons - we only serve public student files on a
491
# separate domain to the main IVLE site.
492
# Public mode does not use cookies, and serves only public content.
493
# Private mode (normal mode) requires login, and only serves files relevant to
494
# the logged-in user.
380
497
# In the local file system, where are the student/user file spaces located.
381
498
# The user jails are expected to be located immediately in subdirectories of
385
# Which application to load by default (if the user navigates to the top level
386
# of the site). This is the app's URL name.
387
# Note that if this app requires authentication, the user will first be
388
# presented with the login screen.
390
""" % (root_dir, ivle_install_dir, jail_base, default_app))
502
# In the local file system, where are the per-subject file spaces located.
503
# The individual subject directories are expected to be located immediately
504
# in subdirectories of this location.
506
""" % (root_dir, ivle_install_dir, public_host, jail_base, subjects_base))
393
509
except IOError, (errno, strerror):
468
587
"""Copies necessary Operating System files from their usual locations
469
588
into the jail/ directory of the cwd."""
470
589
# Currently source paths are configured for Ubuntu.
471
copy_file_to_jail('/lib/ld-linux.so.2', dry)
472
copy_file_to_jail('/lib/tls/i686/cmov/libc.so.6', dry)
473
copy_file_to_jail('/lib/tls/i686/cmov/libdl.so.2', dry)
474
copy_file_to_jail('/lib/tls/i686/cmov/libm.so.6', dry)
475
copy_file_to_jail('/lib/tls/i686/cmov/libpthread.so.0', dry)
476
copy_file_to_jail('/lib/tls/i686/cmov/libutil.so.1', dry)
477
copy_file_to_jail('/usr/bin/python2.5', dry)
478
# TODO: ln -s jail/usr/bin/python2.5 jail/usr/bin/python
479
action_copytree('/usr/lib/python2.5', 'jail/usr/lib/python2.5', dry)
590
for filename in JAIL_FILES:
591
copy_file_to_jail(filename, dry)
592
for src, dst in JAIL_LINKS.items():
593
action_symlink(src, dst, dry)
594
for src, dst in JAIL_COPYTREES.items():
595
action_copytree(src, dst, dry)
481
597
def copy_file_to_jail(src, dry):
482
598
"""Copies a single file from an absolute location into the same location
518
634
# for all the students' jails).
519
635
action_copytree('jail', os.path.join(jail_base, 'template'), dry)
637
# Append IVLE path to ivle.pth in python site packages
638
# (Unless it's already there)
639
ivle_pth = os.path.join(sys.prefix,
640
"lib/python2.5/site-packages/ivle.pth")
641
ivle_www = os.path.join(ivle_install_dir, "www")
642
write_ivle_pth = True
644
file = open(ivle_pth, 'r')
646
if line.strip() == ivle_www:
647
write_ivle_pth = False
649
except (IOError, OSError):
652
action_append(ivle_pth, ivle_www)
656
def updatejails(args):
657
# Get "dry" variable from command line
658
(opts, args) = getopt.gnu_getopt(args, "n", ['dry'])
660
dry = '-n' in opts or '--dry' in opts
663
print "Dry run (no actions will be executed\n"
665
if not dry and os.geteuid() != 0:
666
print >>sys.stderr, "Must be root to run install"
667
print >>sys.stderr, "(I need to chown some files)."
670
# Update the template jail directory in case it hasn't been installed
672
action_copytree('jail', os.path.join(jail_base, 'template'), dry)
674
# Re-link all the files in all students jails.
675
for dir in os.listdir(jail_base):
676
if dir == 'template': continue
677
# First back up the student's home directory
678
temp_home = os.tmpnam()
679
action_rename(os.path.join(jail_base, dir, 'home'), temp_home, dry)
680
# Delete the student's jail and relink the jail files
681
action_linktree(os.path.join(jail_base, 'template'),
682
os.path.join(jail_base, dir), dry)
683
# Restore the student's home directory
684
action_rename(temp_home, os.path.join(jail_base, dir, 'home'), dry)
685
# Set up the user's home directory just in case they don't have a
686
# directory for this yet
687
action_mkdir(os.path.join(jail_base, dir, 'home', dir), dry)
523
691
# The actions call Python os functions but print actions and handle dryness.
550
718
raise RunError(prog, ret)
720
def action_rename(src, dst, dry):
721
"""Calls rename. Deletes the target if it already exists."""
722
if os.access(dst, os.F_OK):
725
shutil.rmtree(dst, True)
726
print "mv ", src, dst
730
except OSError, (err, msg):
731
if err != errno.EEXIST:
552
734
def action_mkdir(path, dry):
553
735
"""Calls mkdir. Silently ignored if the directory already exists.
554
736
Creates all parent directories as necessary."""
572
754
shutil.rmtree(dst, True)
573
755
print "cp -r", src, dst
575
shutil.copytree(src, dst)
757
shutil.copytree(src, dst, True)
759
def action_linktree(src, dst, dry):
760
"""Hard-links an entire directory tree. Same as copytree but the created
761
files are hard-links not actual copies. Removes the existing destination.
763
if os.access(dst, os.F_OK):
766
shutil.rmtree(dst, True)
767
print "<cp with hardlinks> -r", src, dst
769
common.makeuser.linktree(src, dst)
577
771
def action_copylist(srclist, dst, dry):
578
772
"""Copies all files in a list to a new location. The files in the list
586
780
action_mkdir(dstdir, dry)
587
781
print "cp -f", srcfile, dstfile
589
shutil.copyfile(srcfile, dstfile)
784
shutil.copyfile(srcfile, dstfile)
785
shutil.copymode(srcfile, dstfile)
591
789
def action_copyfile(src, dst, dry):
592
790
"""Copies one file to a new location. Creates all parent directories
606
808
dstdir = os.path.split(dst)[0]
607
809
if not os.path.isdir(dstdir):
608
810
action_mkdir(dstdir, dry)
609
print "ln -s", src, dst
811
# Delete existing file
812
if os.path.exists(dst):
814
print "ln -fs", src, dst
611
816
os.symlink(src, dst)
818
def action_append(ivle_pth, ivle_www):
819
file = open(ivle_pth, 'a+')
820
file.write(ivle_www + '\n')
613
823
def action_chown_setuid(file, dry):
614
824
"""Chowns a file to root, and sets the setuid bit on the file.
615
825
Calling this function requires the euid to be root.
624
834
os.chmod(file, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
625
835
| stat.S_ISUID | stat.S_IRUSR | stat.S_IWUSR)
837
def action_chmod_x(file, dry):
838
"""Chmod +xs a file (sets execute permission)."""
839
print "chmod u+rwx", file
841
os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR)
627
843
def query_user(default, prompt):
628
844
"""Prompts the user for a string, which is read from a line of stdin.
629
845
Exits silently if EOF is encountered. Returns the string, with spaces