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 "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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
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