Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Maybe `simple' is a misnomer.
 */
#include "rc.h"
#include "getflags.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
/*
 * Search through the following code to see if we're just going to exit.
 */
int
exitnext(void){
        union code *c=&runq->code[runq->pc];
        while(c->f==Xpopredir) c++;
        return c->f==Xexit;
}

void
Xsimple(void)
{
        word *a;
        thread *p = runq;
        var *v;
        struct builtin *bp;
        int pid;
        globlist();
        a = runq->argv->words;
        if(a==0){
                Xerror1("empty argument list");
                return;
        }
        if(flag['x'])
                pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
        v = gvlook(a->word);
        if(v->fn)
                execfunc(v);
        else{
                if(strcmp(a->word, "builtin")==0){
                        if(count(a)==1){
                                pfmt(err, "builtin: empty argument list\n");
                                setstatus("empty arg list");
                                poplist();
                                return;
                        }
                        a = a->next;
                        popword();
                }
                for(bp = Builtin;bp->name;bp++)
                        if(strcmp(a->word, bp->name)==0){
                                (*bp->fnc)();
                                return;
                        }
                if(exitnext()){
                        /* fork and wait is redundant */
                        pushword("exec");
                        execexec();
                        Xexit();
                }
                else{
                        flush(err);
                        Updenv();       /* necessary so changes don't go out again */
                        if((pid = execforkexec()) < 0){
                                Xerror("try again");
                                return;
                        }

                        /* interrupts don't get us out */
                        poplist();
                        while(Waitfor(pid, 1) < 0)
                                ;
                }
        }
}
struct word nullpath = { "", 0};

void
doredir(redir *rp)
{
        if(rp){
                doredir(rp->next);
                switch(rp->type){
                case ROPEN:
                        if(rp->from!=rp->to){
                                Dup(rp->from, rp->to);
                                close(rp->from);
                        }
                        break;
                case RDUP:
                        Dup(rp->from, rp->to);
                        break;
                case RCLOSE:
                        close(rp->from);
                        break;
                }
        }
}

word*
searchpath(char *w)
{
        word *path;
        if(strncmp(w, "/", 1)==0
        || strncmp(w, "#", 1)==0
        || strncmp(w, "./", 2)==0
        || strncmp(w, "../", 3)==0
        || (path = vlook("path")->val)==0)
                path=&nullpath;
        return path;
}

void
execexec(void)
{
        popword();      /* "exec" */
        if(runq->argv->words==0){
                Xerror1("empty argument list");
                return;
        }
        doredir(runq->redir);
        Execute(runq->argv->words, searchpath(runq->argv->words->word));
        poplist();
}

void
execfunc(var *func)
{
        word *starval;
        popword();
        starval = runq->argv->words;
        runq->argv->words = 0;
        poplist();
        start(func->fn, func->pc, runq->local);
        runq->local = newvar(strdup("*"), runq->local);
        runq->local->val = starval;
        runq->local->changed = 1;
}

int
dochdir(char *word)
{
        /* report to /dev/wdir if it exists and we're interactive */
        static int wdirfd = -2;
        if(chdir(word)<0) return -1;
        if(flag['i']!=0){
                if(wdirfd==-2)  /* try only once */
                        wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
                if(wdirfd>=0) {
                        fcntl(wdirfd, F_SETFD, FD_CLOEXEC);
                        write(wdirfd, word, strlen(word));
                }
        }
        return 1;
}

static char *
appfile(char *dir, char *comp)
{
        int dirlen, complen;
        char *s, *p;

        dirlen = strlen(dir);
        complen = strlen(comp);
        s = emalloc(dirlen + 1 + complen + 1);
        memmove(s, dir, dirlen);
        p = s + dirlen;
        *p++ = '/';
        memmove(p, comp, complen);
        p[complen] = '\0';
        return s;
}

void
execcd(void)
{
        word *a = runq->argv->words;
        word *cdpath;
        char *dir;

        setstatus("can't cd");
        cdpath = vlook("cdpath")->val;
        switch(count(a)){
        default:
                pfmt(err, "Usage: cd [directory]\n");
                break;
        case 2:
                if(a->next->word[0]=='/' || cdpath==0)
                        cdpath = &nullpath;
                for(; cdpath; cdpath = cdpath->next){
                        if(cdpath->word[0] != '\0')
                                dir = appfile(cdpath->word, a->next->word);
                        else
                                dir = strdup(a->next->word);

                        if(dochdir(dir) >= 0){
                                if(cdpath->word[0] != '\0' &&
                                    strcmp(cdpath->word, ".") != 0)
                                        pfmt(err, "%s\n", dir);
                                free(dir);
                                setstatus("");
                                break;
                        }
                        free(dir);
                }
                if(cdpath==0)
                        pfmt(err, "Can't cd %s: %r\n", a->next->word);
                break;
        case 1:
                a = vlook("home")->val;
                if(count(a)>=1){
                        if(dochdir(a->word)>=0)
                                setstatus("");
                        else
                                pfmt(err, "Can't cd %s: %r\n", a->word);
                }
                else
                        pfmt(err, "Can't cd -- $home empty\n");
                break;
        }
        poplist();
}

void
execexit(void)
{
        switch(count(runq->argv->words)){
        default:
                pfmt(err, "Usage: exit [status]\nExiting anyway\n");
        case 2:
                setstatus(runq->argv->words->next->word);
        case 1: Xexit();
        }
}

void
execshift(void)
{
        int n;
        word *a;
        var *star;
        switch(count(runq->argv->words)){
        default:
                pfmt(err, "Usage: shift [n]\n");
                setstatus("shift usage");
                poplist();
                return;
        case 2:
                n = atoi(runq->argv->words->next->word);
                break;
        case 1:
                n = 1;
                break;
        }
        star = vlook("*");
        for(;n && star->val;--n){
                a = star->val->next;
                efree(star->val->word);
                efree((char *)star->val);
                star->val = a;
                star->changed = 1;
        }
        setstatus("");
        poplist();
}

int
octal(char *s)
{
        int n = 0;
        while(*s==' ' || *s=='\t' || *s=='\n') s++;
        while('0'<=*s && *s<='7') n = n*8+*s++-'0';
        return n;
}

int
mapfd(int fd)
{
        redir *rp;
        for(rp = runq->redir;rp;rp = rp->next){
                switch(rp->type){
                case RCLOSE:
                        if(rp->from==fd)
                                fd=-1;
                        break;
                case RDUP:
                case ROPEN:
                        if(rp->to==fd)
                                fd = rp->from;
                        break;
                }
        }
        return fd;
}
union code rdcmds[4];

void
execcmds(io *f)
{
        static int first = 1;
        if(first){
                rdcmds[0].i = 1;
                rdcmds[1].f = Xrdcmds;
                rdcmds[2].f = Xreturn;
                first = 0;
        }
        start(rdcmds, 1, runq->local);
        runq->cmdfd = f;
        runq->iflast = 0;
}

void
execeval(void)
{
        char *cmdline, *s, *t;
        int len = 0;
        word *ap;
        if(count(runq->argv->words)<=1){
                Xerror1("Usage: eval cmd ...");
                return;
        }
        eflagok = 1;
        for(ap = runq->argv->words->next;ap;ap = ap->next)
                len+=1+strlen(ap->word);
        cmdline = emalloc(len);
        s = cmdline;
        for(ap = runq->argv->words->next;ap;ap = ap->next){
                for(t = ap->word;*t;) *s++=*t++;
                *s++=' ';
        }
        s[-1]='\n';
        poplist();
        execcmds(opencore(cmdline, len));
        efree(cmdline);
}
union code dotcmds[14];

void
execdot(void)
{
        int iflag = 0;
        int fd;
        list *av;
        thread *p = runq;
        char *zero, *file;
        word *path;
        static int first = 1;

        if(first){
                dotcmds[0].i = 1;
                dotcmds[1].f = Xmark;
                dotcmds[2].f = Xword;
                dotcmds[3].s="0";
                dotcmds[4].f = Xlocal;
                dotcmds[5].f = Xmark;
                dotcmds[6].f = Xword;
                dotcmds[7].s="*";
                dotcmds[8].f = Xlocal;
                dotcmds[9].f = Xrdcmds;
                dotcmds[10].f = Xunlocal;
                dotcmds[11].f = Xunlocal;
                dotcmds[12].f = Xreturn;
                first = 0;
        }
        else
                eflagok = 1;
        popword();
        if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
                iflag = 1;
                popword();
        }
        /* get input file */
        if(p->argv->words==0){
                Xerror1("Usage: . [-i] file [arg ...]");
                return;
        }
        zero = strdup(p->argv->words->word);
        popword();
        fd = -1;
        for(path = searchpath(zero); path; path = path->next){
                if(path->word[0] != '\0')
                        file = appfile(path->word, zero);
                else
                        file = strdup(zero);

                fd = open(file, 0);
                free(file);
                if(fd >= 0)
                        break;
                if(strcmp(file, "/dev/stdin")==0){      /* for sun & ucb */
                        fd = Dup1(0);
                        if(fd>=0)
                                break;
                }
        }
        if(fd<0){
                pfmt(err, "%s: ", zero);
                setstatus("can't open");
                Xerror(".: can't open");
                return;
        }
        /* set up for a new command loop */
        start(dotcmds, 1, (struct var *)0);
        pushredir(RCLOSE, fd, 0);
        runq->cmdfile = zero;
        runq->cmdfd = openfd(fd);
        runq->iflag = iflag;
        runq->iflast = 0;
        /* push $* value */
        pushlist();
        runq->argv->words = p->argv->words;
        /* free caller's copy of $* */
        av = p->argv;
        p->argv = av->next;
        efree((char *)av);
        /* push $0 value */
        pushlist();
        pushword(zero);
        ndot++;
}

void
execflag(void)
{
        char *letter, *val;
        switch(count(runq->argv->words)){
        case 2:
                setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
                break;
        case 3:
                letter = runq->argv->words->next->word;
                val = runq->argv->words->next->next->word;
                if(strlen(letter)==1){
                        if(strcmp(val, "+")==0){
                                flag[(uchar)letter[0]] = flagset;
                                break;
                        }
                        if(strcmp(val, "-")==0){
                                flag[(uchar)letter[0]] = 0;
                                break;
                        }
                }
        default:
                Xerror1("Usage: flag [letter] [+-]");
                return;
        }
        poplist();
}

void
execwhatis(void){       /* mildly wrong -- should fork before writing */
        word *a, *b, *path;
        var *v;
        struct builtin *bp;
        char *file;
        struct io out[1];
        int found, sep;
        a = runq->argv->words->next;
        if(a==0){
                Xerror1("Usage: whatis name ...");
                return;
        }
        setstatus("");
        memset(out, 0, sizeof out);
        out->fd = mapfd(1);
        out->bufp = out->buf;
        out->ebuf = &out->buf[NBUF];
        out->strp = 0;
        for(;a;a = a->next){
                v = vlook(a->word);
                if(v->val){
                        pfmt(out, "%s=", a->word);
                        if(v->val->next==0)
                                pfmt(out, "%q\n", v->val->word);
                        else{
                                sep='(';
                                for(b = v->val;b && b->word;b = b->next){
                                        pfmt(out, "%c%q", sep, b->word);
                                        sep=' ';
                                }
                                pfmt(out, ")\n");
                        }
                        found = 1;
                }
                else
                        found = 0;
                v = gvlook(a->word);
                if(v->fn)
                        pfmt(out, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
                else{
                        for(bp = Builtin;bp->name;bp++)
                                if(strcmp(a->word, bp->name)==0){
                                        pfmt(out, "builtin %s\n", a->word);
                                        break;
                                }
                        if(!bp->name){
                                for(path = searchpath(a->word); path;
                                    path = path->next){
                                        if(path->word[0] != '\0')
                                                file = appfile(path->word,
                                                        a->word);
                                        else
                                                file = strdup(a->word);
                                        if(Executable(file)){
                                                pfmt(out, "%s\n", file);
                                                free(file);
                                                break;
                                        }
                                        free(file);
                                }
                                if(!path && !found){
                                        pfmt(err, "%s: not found\n", a->word);
                                        setstatus("not found");
                                }
                        }
                }
        }
        poplist();
        flush(err);
}

void
execwait(void)
{
        switch(count(runq->argv->words)){
        default:
                Xerror1("Usage: wait [pid]");
                return;
        case 2:
                Waitfor(atoi(runq->argv->words->next->word), 0);
                break;
        case 1:
                Waitfor(-1, 0);
                break;
        }
        poplist();
}