Merge pull request #5057 from edolstra/nix-develop-chroot

nix develop: Support chroot stores
This commit is contained in:
Eelco Dolstra 2021-07-28 12:30:38 +02:00 committed by GitHub
commit 64a07d3d18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 41 deletions

View file

@ -7,6 +7,7 @@
#include "derivations.hh" #include "derivations.hh"
#include "affinity.hh" #include "affinity.hh"
#include "progress-bar.hh" #include "progress-bar.hh"
#include "run.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -472,8 +473,6 @@ struct CmdDevelop : Common, MixEnvironment
writeFull(rcFileFd.get(), script); writeFull(rcFileFd.get(), script);
stopProgressBar();
setEnviron(); setEnviron();
// prevent garbage collection until shell exits // prevent garbage collection until shell exits
setenv("NIX_GCROOT", gcroot.data(), 1); setenv("NIX_GCROOT", gcroot.data(), 1);
@ -506,11 +505,7 @@ struct CmdDevelop : Common, MixEnvironment
auto args = phase || !command.empty() ? Strings{std::string(baseNameOf(shell)), rcFilePath} auto args = phase || !command.empty() ? Strings{std::string(baseNameOf(shell)), rcFilePath}
: Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath}; : Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath};
restoreProcessContext(); runProgramInStore(store, shell, args);
execvp(shell.c_str(), stringsToCharPtrs(args).data());
throw SysError("executing shell '%s'", shell);
} }
}; };

View file

@ -1,3 +1,4 @@
#include "run.hh"
#include "command.hh" #include "command.hh"
#include "common-args.hh" #include "common-args.hh"
#include "shared.hh" #include "shared.hh"
@ -20,45 +21,43 @@ using namespace nix;
std::string chrootHelperName = "__run_in_chroot"; std::string chrootHelperName = "__run_in_chroot";
struct RunCommon : virtual Command namespace nix {
void runProgramInStore(ref<Store> store,
const std::string & program,
const Strings & args)
{ {
stopProgressBar();
using Command::run; restoreProcessContext();
void runProgram(ref<Store> store, /* If this is a diverted store (i.e. its "logical" location
const std::string & program, (typically /nix/store) differs from its "physical" location
const Strings & args) (e.g. /home/eelco/nix/store), then run the command in a
{ chroot. For non-root users, this requires running it in new
stopProgressBar(); mount and user namespaces. Unfortunately,
unshare(CLONE_NEWUSER) doesn't work in a multithreaded program
(which "nix" is), so we exec() a single-threaded helper program
(chrootHelper() below) to do the work. */
auto store2 = store.dynamic_pointer_cast<LocalStore>();
restoreProcessContext(); if (store2 && store->storeDir != store2->getRealStoreDir()) {
Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), program };
for (auto & arg : args) helperArgs.push_back(arg);
/* If this is a diverted store (i.e. its "logical" location execv(readLink("/proc/self/exe").c_str(), stringsToCharPtrs(helperArgs).data());
(typically /nix/store) differs from its "physical" location
(e.g. /home/eelco/nix/store), then run the command in a
chroot. For non-root users, this requires running it in new
mount and user namespaces. Unfortunately,
unshare(CLONE_NEWUSER) doesn't work in a multithreaded
program (which "nix" is), so we exec() a single-threaded
helper program (chrootHelper() below) to do the work. */
auto store2 = store.dynamic_pointer_cast<LocalStore>();
if (store2 && store->storeDir != store2->getRealStoreDir()) { throw SysError("could not execute chroot helper");
Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), program };
for (auto & arg : args) helperArgs.push_back(arg);
execv(readLink("/proc/self/exe").c_str(), stringsToCharPtrs(helperArgs).data());
throw SysError("could not execute chroot helper");
}
execvp(program.c_str(), stringsToCharPtrs(args).data());
throw SysError("unable to execute '%s'", program);
} }
};
struct CmdShell : InstallablesCommand, RunCommon, MixEnvironment execvp(program.c_str(), stringsToCharPtrs(args).data());
throw SysError("unable to execute '%s'", program);
}
}
struct CmdShell : InstallablesCommand, MixEnvironment
{ {
using InstallablesCommand::run; using InstallablesCommand::run;
@ -125,13 +124,13 @@ struct CmdShell : InstallablesCommand, RunCommon, MixEnvironment
Strings args; Strings args;
for (auto & arg : command) args.push_back(arg); for (auto & arg : command) args.push_back(arg);
runProgram(store, *command.begin(), args); runProgramInStore(store, *command.begin(), args);
} }
}; };
static auto rCmdShell = registerCommand<CmdShell>("shell"); static auto rCmdShell = registerCommand<CmdShell>("shell");
struct CmdRun : InstallableCommand, RunCommon struct CmdRun : InstallableCommand
{ {
using InstallableCommand::run; using InstallableCommand::run;
@ -183,7 +182,7 @@ struct CmdRun : InstallableCommand, RunCommon
Strings allArgs{app.program}; Strings allArgs{app.program};
for (auto & i : args) allArgs.push_back(i); for (auto & i : args) allArgs.push_back(i);
runProgram(store, app.program, allArgs); runProgramInStore(store, app.program, allArgs);
} }
}; };

11
src/nix/run.hh Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include "store-api.hh"
namespace nix {
void runProgramInStore(ref<Store> store,
const std::string & program,
const Strings & args);
}