32
32
# TODO: When creating a new home directory, chown it to its owner
34
# TODO: In chown_to_webserver:
35
# Do not call os.system("chown www-data") - use Python lib
36
# and use the web server uid given in conf. (Several places).
49
def chown_to_webserver(filename):
51
Chowns a file so the web server user owns it.
52
(This is useful in setting up Subversion conf files).
56
os.system("chown -R www-data:www-data %s" % filename)
60
45
def make_svn_repo(login, throw_on_error=True):
61
46
"""Create a repository for the given user.
103
90
os.rename(conf.svn_conf + ".new", conf.svn_conf)
104
chown_to_webserver(conf.svn_conf)
106
92
def make_svn_config(login, throw_on_error=True):
107
93
"""Add an entry to the apache-svn config file for the given user.
135
120
if res != 0 and throw_on_error:
136
121
raise Exception("Unable to create ivle-auth for %s" % login)
138
# Make sure the file is owned by the web server
140
chown_to_webserver(conf.svn_auth_ivle)
144
def generate_manifest(basedir, targetdir, parent=''):
145
""" From a basedir and a targetdir work out which files are missing or out
146
of date and need to be added/updated and which files are redundant and need
149
parent: This is used for the recursive call to track the relative paths
150
that we have decended.
153
cmp = filecmp.dircmp(basedir, targetdir)
155
# Add all new files and files that have changed
156
to_add = [os.path.join(parent,x) for x in (cmp.left_only + cmp.diff_files)]
158
# Remove files that are redundant
159
to_remove = [os.path.join(parent,x) for x in cmp.right_only]
162
for d in cmp.common_dirs:
163
newbasedir = os.path.join(basedir, d)
164
newtargetdir = os.path.join(targetdir, d)
165
newparent = os.path.join(parent, d)
166
(sadd,sremove) = generate_manifest(newbasedir, newtargetdir, newparent)
170
return (to_add, to_remove)
173
def make_jail(username, uid, force=True, manifest=None):
125
def make_jail(username, uid, force=True):
174
126
"""Creates a new user's jail space, in the jail directory as configured in
177
This expects there to be a "staging" directory within the jail root which
129
This expects there to be a "template" directory within the jail root which
178
130
contains all the files for a sample student jail. It creates the student's
179
131
directory in the jail root, by making a hard-link copy of every file in the
180
staging directory, recursively.
132
template directory, recursively.
182
134
Returns the path to the user's home directory.
191
143
force: If false, exception if jail already exists for this user.
192
144
If true (default), overwrites it, but preserves home directory.
194
manifest: If provided this will be a tupple (to_add, to_remove) of files or
195
directories to add or remove from the jail.
197
146
# MUST run as root or some of this may fail
198
147
if os.getuid() != 0:
199
148
raise Exception("Must run make_jail as root")
201
stagingdir = os.path.join(conf.jail_base, '__staging__')
202
if not os.path.isdir(stagingdir):
203
raise Exception("Staging jail directory does not exist: " +
150
templatedir = os.path.join(conf.jail_base, 'template')
151
if not os.path.isdir(templatedir):
152
raise Exception("Template jail directory does not exist: " +
205
154
# tempdir is for putting backup homes in
206
tempdir = os.path.join(conf.jail_base, '__temp__')
155
tempdir = os.path.join(conf.jail_base, 'temp')
207
156
if not os.path.exists(tempdir):
208
157
os.makedirs(tempdir)
209
158
elif not os.path.isdir(tempdir):
230
179
# the backup will be un-made.
231
180
# XXX This will still leave the user's jail in an unusable state,
232
181
# but at least they won't lose their files.
234
(to_add, to_remove) = manifest
235
# Remove redundant files and directories
237
dst = os.path.join(userdir, d)
238
src = os.path.join(stagingdir, d)
239
if os.path.isdir(dst):
241
elif os.path.isfile(dst):
245
dst = os.path.join(userdir, d)
246
src = os.path.join(stagingdir, d)
247
# Clear the previous file/dir
248
if os.path.isdir(dst):
250
elif os.path.isfile(dst):
253
if os.path.isdir(src):
255
elif os.path.isfile(src):
259
# No manifest, do a full rebuild
260
shutil.rmtree(userdir)
261
# Hard-link (copy aliasing) the entire tree over
262
linktree(stagingdir, userdir)
182
shutil.rmtree(userdir)
184
# Hard-link (copy aliasing) the entire tree over
185
linktree(templatedir, userdir)
264
187
# Set up the user's home directory (restore backup)
265
188
# First make sure the directory is empty and its parent exists
276
199
# No user jail exists
277
200
# Hard-link (copy aliasing) the entire tree over
278
linktree(stagingdir, userdir)
201
linktree(templatedir, userdir)
280
203
# Set up the user's home directory
281
204
userhomedir = os.path.join(homedir, username)