nix-shell: Fix $PATH handling in the impure case
We were passing "p=$PATH" rather than "p=$PATH;", resulting in some invalid shell code. Also, construct a separate environment for the child rather than overwriting the parent's.
This commit is contained in:
parent
9fc4cb2ae9
commit
4de0639105
3 changed files with 55 additions and 29 deletions
|
@ -59,6 +59,21 @@ string getEnv(const string & key, const string & def)
|
|||
}
|
||||
|
||||
|
||||
std::map<std::string, std::string> getEnv()
|
||||
{
|
||||
std::map<std::string, std::string> env;
|
||||
for (size_t i = 0; environ[i]; ++i) {
|
||||
auto s = environ[i];
|
||||
auto eq = strchr(s, '=');
|
||||
if (!eq)
|
||||
// invalid env, just keep going
|
||||
continue;
|
||||
env.emplace(std::string(s, eq), std::string(eq + 1));
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
|
||||
Path absPath(Path path, Path dir)
|
||||
{
|
||||
if (path[0] != '/') {
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
|
||||
#ifndef HAVE_STRUCT_DIRENT_D_TYPE
|
||||
#define DT_UNKNOWN 0
|
||||
|
@ -25,6 +27,9 @@ namespace nix {
|
|||
/* Return an environment variable. */
|
||||
string getEnv(const string & key, const string & def = "");
|
||||
|
||||
/* Get the entire environment. */
|
||||
std::map<std::string, std::string> getEnv();
|
||||
|
||||
/* Return an absolutized path, resolving paths relative to the
|
||||
specified directory, or the current directory otherwise. The path
|
||||
is also canonicalised. */
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
using namespace nix;
|
||||
|
||||
extern char ** environ;
|
||||
|
||||
/* Recreate the effect of the perl shellwords function, breaking up a
|
||||
* string into arguments like a shell word, including escapes
|
||||
*/
|
||||
|
@ -375,32 +373,26 @@ int main(int argc, char ** argv)
|
|||
runProgram(settings.nixBinDir + "/nix-store", false, nixStoreArgs);
|
||||
|
||||
// Set the environment.
|
||||
auto env = getEnv();
|
||||
|
||||
auto tmp = getEnv("TMPDIR", getEnv("XDG_RUNTIME_DIR", "/tmp"));
|
||||
|
||||
if (pure) {
|
||||
std::vector<string> skippedEnv{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"};
|
||||
std::vector<string> removed;
|
||||
for (auto i = size_t{0}; environ[i]; ++i) {
|
||||
auto eq = strchr(environ[i], '=');
|
||||
if (!eq)
|
||||
// invalid env, just keep going
|
||||
continue;
|
||||
std::string name(environ[i], eq);
|
||||
if (find(skippedEnv.begin(), skippedEnv.end(), name) == skippedEnv.end())
|
||||
removed.emplace_back(std::move(name));
|
||||
}
|
||||
for (const auto & name : removed)
|
||||
unsetenv(name.c_str());
|
||||
std::set<string> keepVars{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"};
|
||||
decltype(env) newEnv;
|
||||
for (auto & i : env)
|
||||
if (keepVars.count(i.first))
|
||||
newEnv.emplace(i);
|
||||
env = newEnv;
|
||||
// NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
|
||||
setenv("__ETC_PROFILE_SOURCED", "1", 1);
|
||||
env["__ETC_PROFILE_SOURCED"] = "1";
|
||||
}
|
||||
setenv("NIX_BUILD_TOP", tmp.c_str(), 1);
|
||||
setenv("TMPDIR", tmp.c_str(), 1);
|
||||
setenv("TEMPDIR", tmp.c_str(), 1);
|
||||
setenv("TMP", tmp.c_str(), 1);
|
||||
setenv("TEMP", tmp.c_str(), 1);
|
||||
setenv("NIX_STORE", store->storeDir.c_str(), 1);
|
||||
for (const auto & env : drv.env)
|
||||
setenv(env.first.c_str(), env.second.c_str(), 1);
|
||||
|
||||
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp;
|
||||
env["NIX_STORE"] = store->storeDir;
|
||||
|
||||
for (auto & var : drv.env)
|
||||
env.emplace(var);
|
||||
|
||||
restoreAffinity();
|
||||
|
||||
|
@ -424,11 +416,25 @@ int main(int argc, char ** argv)
|
|||
"shopt -u nullglob; "
|
||||
"unset TZ; %4%"
|
||||
"%5%"
|
||||
) % (Path) tmpDir % (pure ? "" : "p=$PATH") % (pure ? "" : "PATH=$PATH:$p; unset p; ") % (getenv("TZ") ? (string("export TZ='") + getenv("TZ") + "'; ") : "") % envCommand).str());
|
||||
if (interactive)
|
||||
execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", "--rcfile", rcfile.c_str(), NULL);
|
||||
else
|
||||
execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", rcfile.c_str(), NULL);
|
||||
)
|
||||
% (Path) tmpDir
|
||||
% (pure ? "" : "p=$PATH; ")
|
||||
% (pure ? "" : "PATH=$PATH:$p; unset p; ")
|
||||
% (getenv("TZ") ? (string("export TZ='") + getenv("TZ") + "'; ") : "")
|
||||
% envCommand).str());
|
||||
|
||||
Strings envStrs;
|
||||
for (auto & i : env)
|
||||
envStrs.push_back(i.first + "=" + i.second);
|
||||
|
||||
auto args = interactive
|
||||
? Strings{"bash", "--rcfile", rcfile}
|
||||
: Strings{"bash", rcfile};
|
||||
|
||||
execvpe(getEnv("NIX_BUILD_SHELL", "bash").c_str(),
|
||||
stringsToCharPtrs(args).data(),
|
||||
stringsToCharPtrs(envStrs).data());
|
||||
|
||||
throw SysError("executing shell");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue