forked from lix-project/lix
Merge pull request #5057 from edolstra/nix-develop-chroot
nix develop: Support chroot stores
This commit is contained in:
commit
64a07d3d18
|
@ -7,6 +7,7 @@
|
|||
#include "derivations.hh"
|
||||
#include "affinity.hh"
|
||||
#include "progress-bar.hh"
|
||||
#include "run.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
@ -472,8 +473,6 @@ struct CmdDevelop : Common, MixEnvironment
|
|||
|
||||
writeFull(rcFileFd.get(), script);
|
||||
|
||||
stopProgressBar();
|
||||
|
||||
setEnviron();
|
||||
// prevent garbage collection until shell exits
|
||||
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}
|
||||
: Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath};
|
||||
|
||||
restoreProcessContext();
|
||||
|
||||
execvp(shell.c_str(), stringsToCharPtrs(args).data());
|
||||
|
||||
throw SysError("executing shell '%s'", shell);
|
||||
runProgramInStore(store, shell, args);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "run.hh"
|
||||
#include "command.hh"
|
||||
#include "common-args.hh"
|
||||
#include "shared.hh"
|
||||
|
@ -20,45 +21,43 @@ using namespace nix;
|
|||
|
||||
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,
|
||||
const std::string & program,
|
||||
const Strings & args)
|
||||
{
|
||||
stopProgressBar();
|
||||
/* If this is a diverted store (i.e. its "logical" location
|
||||
(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>();
|
||||
|
||||
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
|
||||
(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>();
|
||||
execv(readLink("/proc/self/exe").c_str(), stringsToCharPtrs(helperArgs).data());
|
||||
|
||||
if (store2 && store->storeDir != store2->getRealStoreDir()) {
|
||||
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);
|
||||
throw SysError("could not execute chroot helper");
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
@ -125,13 +124,13 @@ struct CmdShell : InstallablesCommand, RunCommon, MixEnvironment
|
|||
Strings args;
|
||||
for (auto & arg : command) args.push_back(arg);
|
||||
|
||||
runProgram(store, *command.begin(), args);
|
||||
runProgramInStore(store, *command.begin(), args);
|
||||
}
|
||||
};
|
||||
|
||||
static auto rCmdShell = registerCommand<CmdShell>("shell");
|
||||
|
||||
struct CmdRun : InstallableCommand, RunCommon
|
||||
struct CmdRun : InstallableCommand
|
||||
{
|
||||
using InstallableCommand::run;
|
||||
|
||||
|
@ -183,7 +182,7 @@ struct CmdRun : InstallableCommand, RunCommon
|
|||
Strings allArgs{app.program};
|
||||
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
11
src/nix/run.hh
Normal 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);
|
||||
|
||||
}
|
Loading…
Reference in a new issue