nix run: Mount the Nix store in a private namespace

This is a convenience command to allow users who are not privileged to
create /nix/store to use Nix with regular binary caches. For example,

  $ NIX_REMOTE="local?state=$HOME/nix/var&real=/$HOME/nix/store" nix run firefox bashInteractive

will download Firefox and bash from cache.nixos.org, then start a
shell in which $HOME/nix/store is mounted on /nix/store.
This commit is contained in:
Eelco Dolstra 2016-06-02 16:51:43 +02:00
parent 6f2d51287c
commit a24f2c9b84
2 changed files with 25 additions and 1 deletions

View file

@ -73,6 +73,8 @@ private:
Sync<State, std::recursive_mutex> _state; Sync<State, std::recursive_mutex> _state;
public:
const Path realStoreDir; const Path realStoreDir;
const Path dbDir; const Path dbDir;
const Path linksDir; const Path linksDir;
@ -80,6 +82,8 @@ private:
const Path schemaPath; const Path schemaPath;
const Path trashDir; const Path trashDir;
private:
bool requireSigs; bool requireSigs;
PublicKeys publicKeys; PublicKeys publicKeys;

View file

@ -4,6 +4,11 @@
#include "shared.hh" #include "shared.hh"
#include "store-api.hh" #include "store-api.hh"
#include "derivations.hh" #include "derivations.hh"
#include "local-store.hh"
#if __linux__
#include <sys/mount.h>
#endif
using namespace nix; using namespace nix;
@ -40,6 +45,20 @@ struct CmdRun : StoreCommand, MixInstallables
store->buildPaths(pathsToBuild); store->buildPaths(pathsToBuild);
auto store2 = store.dynamic_pointer_cast<LocalStore>();
if (store2 && store->storeDir != store2->realStoreDir) {
#if __linux__
if (unshare(CLONE_NEWUSER | CLONE_NEWNS) == -1)
throw SysError("setting up a private mount namespace");
if (mount(store2->realStoreDir.c_str(), store->storeDir.c_str(), "", MS_BIND, 0) == -1)
throw SysError(format("mounting %s on %s") % store2->realStoreDir % store->storeDir);
#else
throw Error(format("mounting the Nix store on %s is not supported on this platform") % store->storeDir);
#endif
}
PathSet outPaths; PathSet outPaths;
for (auto & path : pathsToBuild) for (auto & path : pathsToBuild)
if (isDerivation(path)) { if (isDerivation(path)) {
@ -55,7 +74,8 @@ struct CmdRun : StoreCommand, MixInstallables
unixPath.push_front(path + "/bin"); unixPath.push_front(path + "/bin");
setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1); setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1);
execlp("bash", "bash", nullptr); if (execlp("bash", "bash", nullptr) == -1)
throw SysError("unable to exec bash");
} }
}; };