about summary refs log tree commit diff
path: root/src/nix/main.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-08-29T11·21+0200
committerEelco Dolstra <edolstra@gmail.com>2017-08-29T11·21+0200
commit93a5ef0516881ec133fc5e54069add6dd64ffbdd (patch)
tree9712db5c125630ae11560a6a80561a28bbac7ffc /src/nix/main.cc
parent1c58e13bee6715c668e93cd4ec93bc5d5fd1a4ad (diff)
nix run: Fix chroot execution
Running "nix run" with a diverted store, e.g.

  $ nix run --store local?root=/tmp/nix nixpkgs.hello

stopped working when Nix became multithreaded, because
unshare(CLONE_NEWUSER) doesn't work in multithreaded processes. The
obvious solution is to terminate all other threads first, but 1) there
is no way to terminate Boehm GC marker threads; and 2) it appears that
the kernel has a race where unshare(CLONE_NEWUSER) will still fail for
some indeterminate amount of time after joining other threads.

So instead, "nix run" will now exec() a single-threaded helper ("nix
__run_in_chroot") that performs the actual unshare()/chroot()/exec().
Diffstat (limited to 'src/nix/main.cc')
-rw-r--r--src/nix/main.cc11
1 files changed, 11 insertions, 0 deletions
diff --git a/src/nix/main.cc b/src/nix/main.cc
index 7fece5b87b..0990549aee 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -9,6 +9,10 @@
 #include "store-api.hh"
 #include "progress-bar.hh"
 
+extern std::string chrootHelperName;
+
+void chrootHelper(int argc, char * * argv);
+
 namespace nix {
 
 struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
@@ -57,6 +61,13 @@ void mainWrapped(int argc, char * * argv)
     verbosity = lvlError;
     settings.verboseBuild = false;
 
+    /* The chroot helper needs to be run before any threads have been
+       started. */
+    if (argc > 0 && argv[0] == chrootHelperName) {
+        chrootHelper(argc, argv);
+        return;
+    }
+
     initNix();
     initGC();