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) | Path absPath(Path path, Path dir) | ||||||
| { | { | ||||||
|     if (path[0] != '/') { |     if (path[0] != '/') { | ||||||
|  |  | ||||||
|  | @ -8,9 +8,11 @@ | ||||||
| #include <dirent.h> | #include <dirent.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
|  | 
 | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <limits> | #include <limits> | ||||||
| #include <cstdio> | #include <cstdio> | ||||||
|  | #include <map> | ||||||
| 
 | 
 | ||||||
| #ifndef HAVE_STRUCT_DIRENT_D_TYPE | #ifndef HAVE_STRUCT_DIRENT_D_TYPE | ||||||
| #define DT_UNKNOWN 0 | #define DT_UNKNOWN 0 | ||||||
|  | @ -25,6 +27,9 @@ namespace nix { | ||||||
| /* Return an environment variable. */ | /* Return an environment variable. */ | ||||||
| string getEnv(const string & key, const string & def = ""); | 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
 | /* Return an absolutized path, resolving paths relative to the
 | ||||||
|    specified directory, or the current directory otherwise.  The path |    specified directory, or the current directory otherwise.  The path | ||||||
|    is also canonicalised. */ |    is also canonicalised. */ | ||||||
|  |  | ||||||
|  | @ -16,8 +16,6 @@ | ||||||
| 
 | 
 | ||||||
| using namespace nix; | using namespace nix; | ||||||
| 
 | 
 | ||||||
| extern char ** environ; |  | ||||||
| 
 |  | ||||||
| /* Recreate the effect of the perl shellwords function, breaking up a
 | /* Recreate the effect of the perl shellwords function, breaking up a
 | ||||||
|  * string into arguments like a shell word, including escapes |  * 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); |                 runProgram(settings.nixBinDir + "/nix-store", false, nixStoreArgs); | ||||||
| 
 | 
 | ||||||
|                 // Set the environment.
 |                 // Set the environment.
 | ||||||
|  |                 auto env = getEnv(); | ||||||
|  | 
 | ||||||
|                 auto tmp = getEnv("TMPDIR", getEnv("XDG_RUNTIME_DIR", "/tmp")); |                 auto tmp = getEnv("TMPDIR", getEnv("XDG_RUNTIME_DIR", "/tmp")); | ||||||
|  | 
 | ||||||
|                 if (pure) { |                 if (pure) { | ||||||
|                     std::vector<string> skippedEnv{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"}; |                     std::set<string> keepVars{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"}; | ||||||
|                     std::vector<string> removed; |                     decltype(env) newEnv; | ||||||
|                     for (auto i = size_t{0}; environ[i]; ++i) { |                     for (auto & i : env) | ||||||
|                         auto eq = strchr(environ[i], '='); |                         if (keepVars.count(i.first)) | ||||||
|                         if (!eq) |                             newEnv.emplace(i); | ||||||
|                             // invalid env, just keep going
 |                     env = newEnv; | ||||||
|                             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()); |  | ||||||
|                     // NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
 |                     // 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); |                 env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp; | ||||||
|                 setenv("TEMPDIR", tmp.c_str(), 1); |                 env["NIX_STORE"] = store->storeDir; | ||||||
|                 setenv("TMP", tmp.c_str(), 1); | 
 | ||||||
|                 setenv("TEMP", tmp.c_str(), 1); |                 for (auto & var : drv.env) | ||||||
|                 setenv("NIX_STORE", store->storeDir.c_str(), 1); |                     env.emplace(var); | ||||||
|                 for (const auto & env : drv.env) |  | ||||||
|                     setenv(env.first.c_str(), env.second.c_str(), 1); |  | ||||||
| 
 | 
 | ||||||
|                 restoreAffinity(); |                 restoreAffinity(); | ||||||
| 
 | 
 | ||||||
|  | @ -424,11 +416,25 @@ int main(int argc, char ** argv) | ||||||
|                         "shopt -u nullglob; " |                         "shopt -u nullglob; " | ||||||
|                         "unset TZ; %4%" |                         "unset TZ; %4%" | ||||||
|                         "%5%" |                         "%5%" | ||||||
|                         ) % (Path) tmpDir % (pure ? "" : "p=$PATH") % (pure ? "" : "PATH=$PATH:$p; unset p; ") % (getenv("TZ") ? (string("export TZ='") + getenv("TZ") + "'; ") : "") % envCommand).str()); |                         ) | ||||||
|                 if (interactive) |                         % (Path) tmpDir | ||||||
|                     execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", "--rcfile", rcfile.c_str(), NULL); |                         % (pure ? "" : "p=$PATH; ") | ||||||
|                 else |                         % (pure ? "" : "PATH=$PATH:$p; unset p; ") | ||||||
|                     execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", rcfile.c_str(), NULL); |                         % (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"); |                 throw SysError("executing shell"); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue