125
def make_jail(username, uid, force=True):
125
def generate_manifest(basedir, targetdir, parent=''):
126
""" From a basedir and a targetdir work out which files are missing or out
127
of date and need to be added/updated and which files are redundant and need
130
parent: This is used for the recursive call to track the relative paths
131
that we have decended.
134
cmp = filecmp.dircmp(basedir, targetdir)
136
# Add all new files and files that have changed
137
to_add = [os.path.join(parent,x) for x in (cmp.left_only + cmp.diff_files)]
139
# Remove files that are redundant
140
to_remove = [os.path.join(parent,x) for x in cmp.right_only]
143
for d in cmp.common_dirs:
144
newbasedir = os.path.join(basedir, d)
145
newtargetdir = os.path.join(targetdir, d)
146
newparent = os.path.join(parent, d)
147
(sadd,sremove) = generate_manifest(newbasedir, newtargetdir, newparent)
151
return (to_add, to_remove)
154
def make_jail(username, uid, force=True, manifest=None):
126
155
"""Creates a new user's jail space, in the jail directory as configured in
129
This expects there to be a "template" directory within the jail root which
158
This expects there to be a "staging" directory within the jail root which
130
159
contains all the files for a sample student jail. It creates the student's
131
160
directory in the jail root, by making a hard-link copy of every file in the
132
template directory, recursively.
161
staging directory, recursively.
134
163
Returns the path to the user's home directory.
143
172
force: If false, exception if jail already exists for this user.
144
173
If true (default), overwrites it, but preserves home directory.
175
manifest: If provided this will be a tupple (to_add, to_remove) of files or
176
directories to add or remove from the jail.
146
178
# MUST run as root or some of this may fail
147
179
if os.getuid() != 0:
148
180
raise Exception("Must run make_jail as root")
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: " +
182
stagingdir = os.path.join(conf.jail_base, '__staging__')
183
if not os.path.isdir(stagingdir):
184
raise Exception("Staging jail directory does not exist: " +
154
186
# tempdir is for putting backup homes in
155
tempdir = os.path.join(conf.jail_base, 'temp')
187
tempdir = os.path.join(conf.jail_base, '__temp__')
156
188
if not os.path.exists(tempdir):
157
189
os.makedirs(tempdir)
158
190
elif not os.path.isdir(tempdir):
179
211
# the backup will be un-made.
180
212
# XXX This will still leave the user's jail in an unusable state,
181
213
# but at least they won't lose their files.
182
shutil.rmtree(userdir)
184
# Hard-link (copy aliasing) the entire tree over
185
linktree(templatedir, userdir)
215
(to_add, to_remove) = manifest
216
# Remove redundant files and directories
218
dst = os.path.join(userdir, d)
219
src = os.path.join(stagingdir, d)
220
if os.path.isdir(dst):
222
elif os.path.isfile(dst):
226
dst = os.path.join(userdir, d)
227
src = os.path.join(stagingdir, d)
228
# Clear the previous file/dir
229
if os.path.isdir(dst):
231
elif os.path.isfile(dst):
234
if os.path.isdir(src):
236
elif os.path.isfile(src):
240
# No manifest, do a full rebuild
241
shutil.rmtree(userdir)
242
# Hard-link (copy aliasing) the entire tree over
243
linktree(stagingdir, userdir)
187
245
# Set up the user's home directory (restore backup)
188
246
# First make sure the directory is empty and its parent exists
199
257
# No user jail exists
200
258
# Hard-link (copy aliasing) the entire tree over
201
linktree(templatedir, userdir)
259
linktree(stagingdir, userdir)
203
261
# Set up the user's home directory
204
262
userhomedir = os.path.join(homedir, username)