From 93a5ef0516881ec133fc5e54069add6dd64ffbdd Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 29 Aug 2017 13:21:07 +0200 Subject: 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(). --- src/nix/main.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/nix/main.cc') diff --git a/src/nix/main.cc b/src/nix/main.cc index 7fece5b87b0b..0990549aeecd 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(); -- cgit 1.4.1