Loading commands/system/env.cpp +74 −1 Changes for commands/system/env.cpp: 74 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -25,7 +25,11 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ // "env [NAME=VALUE]... [COMMAND [ARGS...]]": leading NAME=VALUE arguments // "env [-i] [-u NAME]... [--] [NAME=VALUE]... [COMMAND [ARGS...]]": // "-i" (also "-" and "--ignore-environment") starts from an empty // environment, "-u NAME" / "--unset=NAME" removes NAME. Everything below // happens in a forked child, so none of it (least of all "-i") leaks into // the calling shell when env runs as a builtin. Leading NAME=VALUE arguments // are applied to the variable store (which Environment::setVariable also // syncs into the real process environment, so a forked COMMAND inherits // them), then COMMAND runs via Shell::runCommandTokens() -- always in a Loading @@ -37,6 +41,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <iostream> #include <cctype> #include <cstdlib> #include <cstring> #include <sys/wait.h> #include <unistd.h> #include "shell.h" #include "envoirment.h" Loading @@ -48,7 +56,72 @@ namespace fresh { namespace cmd { EnvCommand():ShellCommand("env"){} int runCommand(int argc,const char **argv){ std::cout.flush(); pid_t pid=fork(); if(pid<0){ std::cerr << "env: fork failed" << std::endl; return 125; } if(pid==0){ int rc=runChild(argc,argv); std::cout.flush(); std::cerr.flush(); _exit(rc); } int status=0; while(waitpid(pid,&status,0)<0){} return WIFEXITED(status) ? WEXITSTATUS(status) : WIFSIGNALED(status) ? 128+WTERMSIG(status) : 125; } private: static void clearEnvironment(){ std::vector<std::string> names; const std::map<std::string,std::string> &vars=Environment::instance().variables(); for(std::map<std::string,std::string>::const_iterator it=vars.begin(); it!=vars.end(); ++it) names.push_back(it->first); for(size_t k=0; k<names.size(); ++k) Environment::instance().unsetVariable(names[k]); // No clearenv() in every libc (systempp lacks it): collect the // names first, since unsetenv() reshuffles environ as it goes. names.clear(); for(char **e=environ; e && *e; ++e){ const char *eq=strchr(*e,'='); names.push_back(eq ? std::string(*e,eq-*e) : std::string(*e)); } for(size_t k=0; k<names.size(); ++k) unsetenv(names[k].c_str()); } int runChild(int argc,const char **argv){ int i=1; for(; i<argc; ++i){ std::string opt=argv[i]; if(opt=="--"){ ++i; break; } if(opt=="-i" || opt=="-" || opt=="--ignore-environment"){ clearEnvironment(); }else if(opt=="-u" || opt=="--unset"){ if(i+1>=argc){ std::cerr << "env: option requires an argument -- 'u'" << std::endl; return 125; } Environment::instance().unsetVariable(argv[++i]); }else if(opt.rfind("--unset=",0)==0){ Environment::instance().unsetVariable(opt.substr(8)); }else if(opt.size()>2 && opt.compare(0,2,"-u")==0){ Environment::instance().unsetVariable(opt.substr(2)); }else if(opt.size()>1 && opt[0]=='-'){ std::cerr << "env: invalid option -- '" << opt << "'" << std::endl; return 125; }else{ break; } } for(; i<argc; ++i){ std::string arg=argv[i]; size_t eq=arg.find('='); Loading Loading
commands/system/env.cpp +74 −1 Changes for commands/system/env.cpp: 74 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -25,7 +25,11 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ // "env [NAME=VALUE]... [COMMAND [ARGS...]]": leading NAME=VALUE arguments // "env [-i] [-u NAME]... [--] [NAME=VALUE]... [COMMAND [ARGS...]]": // "-i" (also "-" and "--ignore-environment") starts from an empty // environment, "-u NAME" / "--unset=NAME" removes NAME. Everything below // happens in a forked child, so none of it (least of all "-i") leaks into // the calling shell when env runs as a builtin. Leading NAME=VALUE arguments // are applied to the variable store (which Environment::setVariable also // syncs into the real process environment, so a forked COMMAND inherits // them), then COMMAND runs via Shell::runCommandTokens() -- always in a Loading @@ -37,6 +41,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <iostream> #include <cctype> #include <cstdlib> #include <cstring> #include <sys/wait.h> #include <unistd.h> #include "shell.h" #include "envoirment.h" Loading @@ -48,7 +56,72 @@ namespace fresh { namespace cmd { EnvCommand():ShellCommand("env"){} int runCommand(int argc,const char **argv){ std::cout.flush(); pid_t pid=fork(); if(pid<0){ std::cerr << "env: fork failed" << std::endl; return 125; } if(pid==0){ int rc=runChild(argc,argv); std::cout.flush(); std::cerr.flush(); _exit(rc); } int status=0; while(waitpid(pid,&status,0)<0){} return WIFEXITED(status) ? WEXITSTATUS(status) : WIFSIGNALED(status) ? 128+WTERMSIG(status) : 125; } private: static void clearEnvironment(){ std::vector<std::string> names; const std::map<std::string,std::string> &vars=Environment::instance().variables(); for(std::map<std::string,std::string>::const_iterator it=vars.begin(); it!=vars.end(); ++it) names.push_back(it->first); for(size_t k=0; k<names.size(); ++k) Environment::instance().unsetVariable(names[k]); // No clearenv() in every libc (systempp lacks it): collect the // names first, since unsetenv() reshuffles environ as it goes. names.clear(); for(char **e=environ; e && *e; ++e){ const char *eq=strchr(*e,'='); names.push_back(eq ? std::string(*e,eq-*e) : std::string(*e)); } for(size_t k=0; k<names.size(); ++k) unsetenv(names[k].c_str()); } int runChild(int argc,const char **argv){ int i=1; for(; i<argc; ++i){ std::string opt=argv[i]; if(opt=="--"){ ++i; break; } if(opt=="-i" || opt=="-" || opt=="--ignore-environment"){ clearEnvironment(); }else if(opt=="-u" || opt=="--unset"){ if(i+1>=argc){ std::cerr << "env: option requires an argument -- 'u'" << std::endl; return 125; } Environment::instance().unsetVariable(argv[++i]); }else if(opt.rfind("--unset=",0)==0){ Environment::instance().unsetVariable(opt.substr(8)); }else if(opt.size()>2 && opt.compare(0,2,"-u")==0){ Environment::instance().unsetVariable(opt.substr(2)); }else if(opt.size()>1 && opt[0]=='-'){ std::cerr << "env: invalid option -- '" << opt << "'" << std::endl; return 125; }else{ break; } } for(; i<argc; ++i){ std::string arg=argv[i]; size_t eq=arg.find('='); Loading