Commit 72112774 authored by jan.koester's avatar jan.koester
Browse files

test

parent 1d995cd7
Loading
Loading
Loading
Loading
+74 −1
Changes for commands/system/env.cpp: 74 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -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
@@ -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"
@@ -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('=');