* Delete the chroot directory automatically.
* Removed some debug messages.
This commit is contained in:
parent
9397cd30c8
commit
dc6f373842
5 changed files with 80 additions and 19 deletions
|
@ -118,6 +118,9 @@
|
||||||
the channel hasn’t changed.</para></listitem>
|
the channel hasn’t changed.</para></listitem>
|
||||||
|
|
||||||
|
|
||||||
|
<listitem><para>TODO: chroot support.</para></listitem>
|
||||||
|
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -135,6 +135,44 @@
|
||||||
#build-users-group =
|
#build-users-group =
|
||||||
|
|
||||||
|
|
||||||
|
### Option `build-use-chroot'
|
||||||
|
#
|
||||||
|
# If set to `true', builds will be performed in a chroot environment,
|
||||||
|
# i.e., the build will be isolated from the normal file system
|
||||||
|
# hierarchy and will only see the Nix store, the temporary build
|
||||||
|
# directory, and the directories configured with the
|
||||||
|
# `build-chroot-dirs' option (such as /proc and /dev). This is useful
|
||||||
|
# to prevent undeclared dependencies on files in directories such as
|
||||||
|
# /usr/bin.
|
||||||
|
#
|
||||||
|
# The use of a chroot requires that Nix is run as root (but you can
|
||||||
|
# still use the "build users" feature to perform builds under
|
||||||
|
# different users than root). Currently, chroot builds only work on
|
||||||
|
# Linux because Nix uses "bind mounts" to make the Nix store and other
|
||||||
|
# directories available inside the chroot.
|
||||||
|
#
|
||||||
|
# The default is `false'.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# build-use-chroot = true
|
||||||
|
#build-use-chroot = false
|
||||||
|
|
||||||
|
|
||||||
|
### Option `build-chroot-dirs'
|
||||||
|
#
|
||||||
|
# When builds are performed in a chroot environment, Nix will mount
|
||||||
|
# (using `mount --bind' on Linux) some directories from the normal
|
||||||
|
# file system hierarchy inside the chroot. These are the Nix store,
|
||||||
|
# the temporary build directory (usually /tmp/nix-<pid>-<number>) and
|
||||||
|
# the directories listed here. The default is "/dev /proc". Files
|
||||||
|
# in /dev (such as /dev/null) are needed by many builds, and some
|
||||||
|
# files in /proc may also be needed occasionally.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# build-use-chroot = /dev /proc /bin
|
||||||
|
#build-chroot-dirs = /dev /proc
|
||||||
|
|
||||||
|
|
||||||
### Option `system'
|
### Option `system'
|
||||||
#
|
#
|
||||||
# This option specifies the canonical Nix system name of the current
|
# This option specifies the canonical Nix system name of the current
|
||||||
|
|
|
@ -586,7 +586,8 @@ void deletePathWrapped(const Path & path)
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
|
||||||
|
|
||||||
/* Helper class for automatically unmounting bind-mounts in chroots. */
|
/* Helper RAII class for automatically unmounting bind-mounts in
|
||||||
|
chroots. */
|
||||||
struct BindMount
|
struct BindMount
|
||||||
{
|
{
|
||||||
Path source, target;
|
Path source, target;
|
||||||
|
@ -612,7 +613,7 @@ struct BindMount
|
||||||
|
|
||||||
void bind(const Path & source, const Path & target)
|
void bind(const Path & source, const Path & target)
|
||||||
{
|
{
|
||||||
printMsg(lvlError, format("bind mounting `%1%' to `%2%'") % source % target);
|
debug(format("bind mounting `%1%' to `%2%'") % source % target);
|
||||||
|
|
||||||
this->source = source;
|
this->source = source;
|
||||||
this->target = target;
|
this->target = target;
|
||||||
|
@ -626,7 +627,8 @@ struct BindMount
|
||||||
void unbind()
|
void unbind()
|
||||||
{
|
{
|
||||||
if (source == "") return;
|
if (source == "") return;
|
||||||
printMsg(lvlError, format("umount `%1%'") % target);
|
|
||||||
|
debug(format("unmount bind-mount `%1%'") % target);
|
||||||
|
|
||||||
/* Urgh. Unmount sometimes doesn't succeed right away because
|
/* Urgh. Unmount sometimes doesn't succeed right away because
|
||||||
the mount point is still busy. It shouldn't be, because
|
the mount point is still busy. It shouldn't be, because
|
||||||
|
@ -644,16 +646,18 @@ struct BindMount
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw SysError(format("unmounting `%1%' failed") % target);
|
throw SysError(format("unmounting bind-mount `%1%' failed") % target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get rid of the directories for the mount point created in
|
/* Get rid of the directories for the mount point created in
|
||||||
bind(). */
|
bind(). */
|
||||||
for (Paths::reverse_iterator i = created.rbegin(); i != created.rend(); ++i) {
|
for (Paths::reverse_iterator i = created.rbegin(); i != created.rend(); ++i) {
|
||||||
printMsg(lvlError, format("delete `%1%'") % *i);
|
debug(format("deleting `%1%'") % *i);
|
||||||
if (remove(i->c_str()) == -1)
|
if (remove(i->c_str()) == -1)
|
||||||
throw SysError(format("cannot unlink `%1%'") % *i);
|
throw SysError(format("cannot unlink `%1%'") % *i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source = "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -704,6 +708,9 @@ private:
|
||||||
/* Whether we're currently doing a chroot build. */
|
/* Whether we're currently doing a chroot build. */
|
||||||
bool useChroot;
|
bool useChroot;
|
||||||
|
|
||||||
|
/* A RAII object to delete the chroot directory. */
|
||||||
|
boost::shared_ptr<AutoDelete> autoDelChroot;
|
||||||
|
|
||||||
/* In chroot builds, the list of bind mounts currently active.
|
/* In chroot builds, the list of bind mounts currently active.
|
||||||
The destructor of BindMount will cause the binds to be
|
The destructor of BindMount will cause the binds to be
|
||||||
unmounted. */
|
unmounted. */
|
||||||
|
@ -797,18 +804,11 @@ DerivationGoal::~DerivationGoal()
|
||||||
/* Careful: we should never ever throw an exception from a
|
/* Careful: we should never ever throw an exception from a
|
||||||
destructor. */
|
destructor. */
|
||||||
try {
|
try {
|
||||||
printMsg(lvlError, "DESTROY");
|
|
||||||
killChild();
|
killChild();
|
||||||
deleteTmpDir(false);
|
deleteTmpDir(false);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
ignoreException();
|
ignoreException();
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
//sleep(1);
|
|
||||||
bindMounts.clear();
|
|
||||||
} catch (...) {
|
|
||||||
ignoreException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1646,7 +1646,27 @@ void DerivationGoal::startBuilder()
|
||||||
Path tmpRootDir;
|
Path tmpRootDir;
|
||||||
|
|
||||||
if (useChroot) {
|
if (useChroot) {
|
||||||
tmpRootDir = createTempDir();
|
/* Create a temporary directory in which we set up the chroot
|
||||||
|
environment using bind-mounts.
|
||||||
|
|
||||||
|
!!! Big danger here: since we're doing this in /tmp, there
|
||||||
|
is a risk that the admin does something like "rm -rf
|
||||||
|
/tmp/chroot-nix-*" to clean up aborted builds, and if some
|
||||||
|
of the bind-mounts are still active, then "rm -rf" will
|
||||||
|
happily recurse into those mount points (thereby deleting,
|
||||||
|
say, /nix/store). Ideally, tmpRootDir should be created in
|
||||||
|
some special location (maybe in /nix/var/nix) where Nix
|
||||||
|
takes care of unmounting / deleting old chroots
|
||||||
|
automatically. */
|
||||||
|
tmpRootDir = createTempDir("", "chroot-nix");
|
||||||
|
|
||||||
|
/* Clean up the chroot directory automatically, but don't
|
||||||
|
recurse; that would be very very bad if the unmount of a
|
||||||
|
bind-mount fails. Instead BindMount::unbind() unmounts and
|
||||||
|
deletes exactly those directories that it created to
|
||||||
|
produce the mount point, so that after all the BindMount
|
||||||
|
destructors have run, tmpRootDir should be empty. */
|
||||||
|
autoDelChroot = boost::shared_ptr<AutoDelete>(new AutoDelete(tmpRootDir, false));
|
||||||
|
|
||||||
printMsg(lvlChatty, format("setting up chroot environment in `%1%'") % tmpRootDir);
|
printMsg(lvlChatty, format("setting up chroot environment in `%1%'") % tmpRootDir);
|
||||||
|
|
||||||
|
|
|
@ -318,19 +318,19 @@ void makePathReadOnly(const Path & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Path tempName(const Path & tmpRoot)
|
static Path tempName(const Path & tmpRoot, const Path & prefix)
|
||||||
{
|
{
|
||||||
static int counter = 0;
|
static int counter = 0;
|
||||||
Path tmpRoot2 = canonPath(tmpRoot.empty() ? getEnv("TMPDIR", "/tmp") : tmpRoot, true);
|
Path tmpRoot2 = canonPath(tmpRoot.empty() ? getEnv("TMPDIR", "/tmp") : tmpRoot, true);
|
||||||
return (format("%1%/nix-%2%-%3%") % tmpRoot2 % getpid() % counter++).str();
|
return (format("%1%/%2%-%3%-%4%") % tmpRoot2 % prefix % getpid() % counter++).str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path createTempDir(const Path & tmpRoot)
|
Path createTempDir(const Path & tmpRoot, const Path & prefix)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
Path tmpDir = tempName(tmpRoot);
|
Path tmpDir = tempName(tmpRoot, prefix);
|
||||||
if (mkdir(tmpDir.c_str(), 0777) == 0) {
|
if (mkdir(tmpDir.c_str(), 0777) == 0) {
|
||||||
/* Explicitly set the group of the directory. This is to
|
/* Explicitly set the group of the directory. This is to
|
||||||
work around around problems caused by BSD's group
|
work around around problems caused by BSD's group
|
||||||
|
|
|
@ -70,7 +70,7 @@ void deletePath(const Path & path, unsigned long long & bytesFreed);
|
||||||
void makePathReadOnly(const Path & path);
|
void makePathReadOnly(const Path & path);
|
||||||
|
|
||||||
/* Create a temporary directory. */
|
/* Create a temporary directory. */
|
||||||
Path createTempDir(const Path & tmpRoot = "");
|
Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix");
|
||||||
|
|
||||||
/* Create a directory and all its parents, if necessary. Returns the
|
/* Create a directory and all its parents, if necessary. Returns the
|
||||||
list of created directories, in order of creation. */
|
list of created directories, in order of creation. */
|
||||||
|
|
Loading…
Reference in a new issue