From ed5ad59dc16d8207f14c23f7fca903ee408eb54e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 27 Jul 2021 14:23:24 +0200 Subject: [PATCH] nix develop: Support chroot stores Fixes #5024. --- src/nix/develop.cc | 9 ++----- src/nix/run.cc | 67 +++++++++++++++++++++++----------------------- src/nix/run.hh | 11 ++++++++ 3 files changed, 46 insertions(+), 41 deletions(-) create mode 100644 src/nix/run.hh diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 9a93cdb03..55023545d 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -7,6 +7,7 @@ #include "derivations.hh" #include "affinity.hh" #include "progress-bar.hh" +#include "run.hh" #include @@ -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); } }; diff --git a/src/nix/run.cc b/src/nix/run.cc index 0c8afec2d..7597b61f7 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -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, + const std::string & program, + const Strings & args) { + stopProgressBar(); - using Command::run; + restoreProcessContext(); - void runProgram(ref 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(); - 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(); + 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("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); } }; diff --git a/src/nix/run.hh b/src/nix/run.hh new file mode 100644 index 000000000..6180a87dd --- /dev/null +++ b/src/nix/run.hh @@ -0,0 +1,11 @@ +#pragma once + +#include "store-api.hh" + +namespace nix { + +void runProgramInStore(ref store, + const std::string & program, + const Strings & args); + +}