nix-gh/src/nix/run.cc
Eelco Dolstra a24f2c9b84 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.
2016-06-02 16:51:43 +02:00

83 lines
2.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "command.hh"
#include "common-args.hh"
#include "installables.hh"
#include "shared.hh"
#include "store-api.hh"
#include "derivations.hh"
#include "local-store.hh"
#if __linux__
#include <sys/mount.h>
#endif
using namespace nix;
struct CmdRun : StoreCommand, MixInstallables
{
CmdRun()
{
}
std::string name() override
{
return "run";
}
std::string description() override
{
return "run a shell in which the specified packages are available";
}
void run(ref<Store> store) override
{
auto elems = evalInstallables(store);
PathSet pathsToBuild;
for (auto & elem : elems) {
if (elem.isDrv)
pathsToBuild.insert(elem.drvPath);
else
pathsToBuild.insert(elem.outPaths.begin(), elem.outPaths.end());
}
printMissing(store, 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;
for (auto & path : pathsToBuild)
if (isDerivation(path)) {
Derivation drv = store->derivationFromPath(path);
for (auto & output : drv.outputs)
outPaths.insert(output.second.path);
} else
outPaths.insert(path);
auto unixPath = tokenizeString<Strings>(getEnv("PATH"), ":");
for (auto & path : outPaths)
if (pathExists(path + "/bin"))
unixPath.push_front(path + "/bin");
setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1);
if (execlp("bash", "bash", nullptr) == -1)
throw SysError("unable to exec bash");
}
};
static RegisterCommand r1(make_ref<CmdRun>());