/* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley Software License Agreement * specifies the terms and conditions for redistribution. */ #include "sh.h" #include "sh.tconst.h" /* * C shell */ #define IGNORE 1 /* in ignore, it means to ignore value, just parse */ #define NOGLOB 2 /* in ignore, it means not to globone */ #define ADDOP 1 #define MULOP 2 #define EQOP 4 #define RELOP 8 #define RESTOP 16 #define ANYOP 31 #define EQEQ 1 #define GTR 2 #define LSS 4 #define NOTEQ 6 #define EQMATCH 7 #define NOTEQMATCH 8 int uid; int exp0(tchar ***, bool); int exp1(tchar ***, bool); int exp2(tchar ***, bool); int exp2a(tchar ***, bool); int exp2b(tchar ***, bool); int exp2c(tchar ***, bool); tchar *exp3(tchar ***, bool); tchar *exp3a(tchar ***, bool); tchar *exp4(tchar ***, bool); tchar *exp5(tchar ***, bool); tchar *exp6(tchar ***, bool); void evalav(tchar **); /* * Determine if file given by name is accessible with permissions * given by mode. * * Borrowed from the Bourne sh, and modified a bit * * If the requested access is permitted, a value of 0 is * returned. Otherwise, a value of -1 is returned and errno is * set to indicate the error */ int chk_access(tchar *path, mode_t mode) { static int flag; static uid_t euid; struct stat statb; mode_t ftype; unsigned char name[MAXPATHLEN*MB_LEN_MAX]; /* General use buffer. */ /* convert tchar * to char * */ tstostr((char *)name, path); if (flag == 0) { euid = geteuid(); flag = 1; } if (stat((char *)name, &statb) == 0) { ftype = statb.st_mode & S_IFMT; if (access((char *)name, 010|(mode>>6)) == 0) { if (euid == 0) { if (ftype != S_IFREG || mode != S_IEXEC) return (0); /* root can execute file as long as it has execute permission for someone */ if (statb.st_mode & (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))) return (0); return (-1); } return (0); } } return (-1); } int exp(tchar ***vp) { #ifdef TRACE tprintf("TRACE- exp()\n"); #endif return (exp0(vp, 0)); } int exp0(tchar ***vp, bool ignore) { int p1 = exp1(vp, ignore); #ifdef TRACE tprintf("TRACE- exp0()\n"); #endif #ifdef EDEBUG etraci("exp0 p1", p1, vp); #endif if (**vp && eq(**vp, S_BARBAR /* "||" */)) { int p2; (*vp)++; p2 = exp0(vp, (ignore&IGNORE) || p1); #ifdef EDEBUG etraci("exp0 p2", p2, vp); #endif return (p1 || p2); } return (p1); } int exp1(tchar ***vp, bool ignore) { int p1 = exp2(vp, ignore); #ifdef TRACE tprintf("TRACE- exp1()\n"); #endif #ifdef EDEBUG etraci("exp1 p1", p1, vp); #endif if (**vp && eq(**vp, S_ANDAND /* "&&" */)) { int p2; (*vp)++; p2 = exp1(vp, (ignore&IGNORE) || !p1); #ifdef EDEBUG etraci("exp1 p2", p2, vp); #endif return (p1 && p2); } return (p1); } int exp2(tchar ***vp, bool ignore) { int p1 = exp2a(vp, ignore); #ifdef TRACE tprintf("TRACE- exp2()\n"); #endif #ifdef EDEBUG etraci("exp3 p1", p1, vp); #endif if (**vp && eq(**vp, S_BAR /* "|" */)) { int p2; (*vp)++; p2 = exp2(vp, ignore); #ifdef EDEBUG etraci("exp3 p2", p2, vp); #endif return (p1 | p2); } return (p1); } int exp2a(tchar ***vp, bool ignore) { int p1 = exp2b(vp, ignore); #ifdef TRACE tprintf("TRACE- exp2a()\n"); #endif #ifdef EDEBUG etraci("exp2a p1", p1, vp); #endif if (**vp && eq(**vp, S_HAT /* "^" */)) { int p2; (*vp)++; p2 = exp2a(vp, ignore); #ifdef EDEBUG etraci("exp2a p2", p2, vp); #endif return (p1 ^ p2); } return (p1); } int exp2b(tchar ***vp, bool ignore) { int p1 = exp2c(vp, ignore); #ifdef TRACE tprintf("TRACE- exp2b()\n"); #endif #ifdef EDEBUG etraci("exp2b p1", p1, vp); #endif if (**vp && eq(**vp, S_AND /* "&" */)) { int p2; (*vp)++; p2 = exp2b(vp, ignore); #ifdef EDEBUG etraci("exp2b p2", p2, vp); #endif return (p1 & p2); } return (p1); } int exp2c(tchar ***vp, bool ignore) { tchar *p1 = exp3(vp, ignore); tchar *p2; int i; #ifdef TRACE tprintf("TRACE- exp2c()\n"); #endif #ifdef EDEBUG etracc("exp2c p1", p1, vp); #endif if (i = isa(**vp, EQOP)) { (*vp)++; if (i == EQMATCH || i == NOTEQMATCH) ignore |= NOGLOB; p2 = exp3(vp, ignore); #ifdef EDEBUG etracc("exp2c p2", p2, vp); #endif if (!(ignore&IGNORE)) switch (i) { case EQEQ: i = eq(p1, p2); break; case NOTEQ: i = !eq(p1, p2); break; case EQMATCH: i = Gmatch(p1, p2); break; case NOTEQMATCH: i = !Gmatch(p1, p2); break; } xfree(p1), xfree(p2); return (i); } i = egetn(p1); xfree(p1); return (i); } tchar * exp3(tchar ***vp, bool ignore) { tchar *p1, *p2; int i; #ifdef TRACE tprintf("TRACE- exp3()\n"); #endif p1 = exp3a(vp, ignore); #ifdef EDEBUG etracc("exp3 p1", p1, vp); #endif if (i = isa(**vp, RELOP)) { (*vp)++; if (**vp && eq(**vp, S_EQ /* "=" */)) i |= 1, (*vp)++; p2 = exp3(vp, ignore); #ifdef EDEBUG etracc("exp3 p2", p2, vp); #endif if (!(ignore&IGNORE)) switch (i) { case GTR: i = egetn(p1) > egetn(p2); break; case GTR|1: i = egetn(p1) >= egetn(p2); break; case LSS: i = egetn(p1) < egetn(p2); break; case LSS|1: i = egetn(p1) <= egetn(p2); break; } xfree(p1), xfree(p2); return (putn(i)); } return (p1); } tchar * exp3a(tchar ***vp, bool ignore) { tchar *p1, *p2, *op; int i; #ifdef TRACE tprintf("TRACE- exp3a()\n"); #endif p1 = exp4(vp, ignore); #ifdef EDEBUG etracc("exp3a p1", p1, vp); #endif op = **vp; /* if (op && any(op[0], "<>") && op[0] == op[1]) { */ if (op && (op[0] == '<' || op[0] == '>') && op[0] == op[1]) { (*vp)++; p2 = exp3a(vp, ignore); #ifdef EDEBUG etracc("exp3a p2", p2, vp); #endif if (op[0] == '<') i = egetn(p1) << egetn(p2); else i = egetn(p1) >> egetn(p2); xfree(p1), xfree(p2); return (putn(i)); } return (p1); } tchar * exp4(tchar ***vp, bool ignore) { tchar *p1, *p2; int i = 0; #ifdef TRACE tprintf("TRACE- exp4()\n"); #endif p1 = exp5(vp, ignore); #ifdef EDEBUG etracc("exp4 p1", p1, vp); #endif if (isa(**vp, ADDOP)) { tchar *op = *(*vp)++; p2 = exp4(vp, ignore); #ifdef EDEBUG etracc("exp4 p2", p2, vp); #endif if (!(ignore&IGNORE)) switch (op[0]) { case '+': i = egetn(p1) + egetn(p2); break; case '-': i = egetn(p1) - egetn(p2); break; } xfree(p1), xfree(p2); return (putn(i)); } return (p1); } tchar * exp5(tchar ***vp, bool ignore) { tchar *p1, *p2; int i = 0; #ifdef TRACE tprintf("TRACE- exp5()\n"); #endif p1 = exp6(vp, ignore); #ifdef EDEBUG etracc("exp5 p1", p1, vp); #endif if (isa(**vp, MULOP)) { tchar *op = *(*vp)++; p2 = exp5(vp, ignore); #ifdef EDEBUG etracc("exp5 p2", p2, vp); #endif if (!(ignore&IGNORE)) switch (op[0]) { case '*': i = egetn(p1) * egetn(p2); break; case '/': i = egetn(p2); if (i == 0) error("Divide by 0"); i = egetn(p1) / i; break; case '%': i = egetn(p2); if (i == 0) error("Mod by 0"); i = egetn(p1) % i; break; } xfree(p1), xfree(p2); return (putn(i)); } return (p1); } tchar * exp6(tchar ***vp, bool ignore) { int ccode, i; tchar *cp, *dp, *ep; #ifdef TRACE tprintf("TRACE- exp6()\n"); #endif if (**vp == 0) bferr("Expression syntax"); if (eq(**vp, S_EXAS /* "!" */)) { (*vp)++; cp = exp6(vp, ignore); #ifdef EDEBUG etracc("exp6 ! cp", cp, vp); #endif i = egetn(cp); xfree(cp); return (putn(!i)); } if (eq(**vp, S_TIL /* "~" */)) { (*vp)++; cp = exp6(vp, ignore); #ifdef EDEBUG etracc("exp6 ~ cp", cp, vp); #endif i = egetn(cp); xfree(cp); return (putn(~i)); } if (eq(**vp, S_LPAR /* "(" */)) { (*vp)++; ccode = exp0(vp, ignore); #ifdef EDEBUG etraci("exp6 () ccode", ccode, vp); #endif if (*vp == 0 || **vp == 0 || ***vp != ')') bferr("Expression syntax"); (*vp)++; return (putn(ccode)); } if (eq(**vp, S_LBRA /* "{" */)) { tchar **v; struct command faket; tchar *fakecom[2]; faket.t_dtyp = TCOM; faket.t_dflg = 0; faket.t_dcar = faket.t_dcdr = faket.t_dspr = (struct command *)0; faket.t_dcom = fakecom; fakecom[0] = S_BRAPPPBRA /* "{ ... }" */; fakecom[1] = NOSTR; (*vp)++; v = *vp; for (;;) { if (!**vp) bferr("Missing }"); if (eq(*(*vp)++, S_RBRA /* "}" */)) break; } if (ignore&IGNORE) return (S_ /* "" */); psavejob(); if (pfork(&faket, -1) == 0) { *--(*vp) = 0; evalav(v); exitstat(); } pwait(); prestjob(); #ifdef EDEBUG etraci("exp6 {} status", egetn(value("status")), vp); #endif return (putn(egetn(value(S_status /* "status" */)) == 0)); } if (isa(**vp, ANYOP)) return (S_ /* "" */); cp = *(*vp)++; if (*cp == '-' && any(cp[1], S_erwxfdzo /* "erwxfdzo" */)) { struct stat stb; if (cp[2] != '\0') bferr("Malformed file inquiry"); /* * Detect missing file names by checking for operator * in the file name position. However, if an operator * name appears there, we must make sure that there's * no file by that name (e.g., "/") before announcing * an error. Even this check isn't quite right, since * it doesn't take globbing into account. */ if ((**vp == NULL) || isa(**vp, ANYOP) && stat_(**vp, &stb)) bferr("Missing file name"); dp = *(*vp)++; if (ignore&IGNORE) return (S_ /* "" */); ep = globone(dp); switch (cp[1]) { case 'r': i = !chk_access(ep, S_IREAD); break; case 'w': i = !chk_access(ep, S_IWRITE); break; case 'x': i = !chk_access(ep, S_IEXEC); break; default: if (stat_(ep, &stb)) { xfree(ep); return (S_0 /* "0" */); } switch (cp[1]) { case 'f': i = (stb.st_mode & S_IFMT) == S_IFREG; break; case 'd': i = (stb.st_mode & S_IFMT) == S_IFDIR; break; case 'z': i = stb.st_size == 0; break; case 'e': i = 1; break; case 'o': i = stb.st_uid == uid; break; } } #ifdef EDEBUG etraci("exp6 -? i", i, vp); #endif xfree(ep); return (putn(i)); } #ifdef EDEBUG etracc("exp6 default", cp, vp); #endif return (ignore&NOGLOB ? savestr(cp) : globone(cp)); } void evalav(tchar **v) { struct wordent paraml; struct wordent *hp = ¶ml; struct command *t; struct wordent *wdp = hp; #ifdef TRACE tprintf("TRACE- evalav()\n"); #endif set(S_status /* "status" */, S_0 /* "0" */); hp->prev = hp->next = hp; hp->word = S_ /* "" */; while (*v) { struct wordent *new = (struct wordent *)xcalloc(1, sizeof *wdp); new->prev = wdp; new->next = hp; wdp->next = new; wdp = new; wdp->word = savestr(*v++); } hp->prev = wdp; alias(¶ml); t = syntax(paraml.next, ¶ml, 0); if (err_msg) error("%s", gettext(err_msg)); execute(t, -1); freelex(¶ml), freesyn(t); } int isa(tchar *cp, int what) { #ifdef TRACE tprintf("TRACE- isa()\n"); #endif if (cp == 0) return ((what & RESTOP) != 0); if (cp[1] == 0) { if (what & ADDOP && (*cp == '+' || *cp == '-')) return (1); if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%')) return (1); if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' || *cp == '~' || *cp == '^' || *cp == '"')) return (1); } else if (cp[2] == 0) { if (what & RESTOP) { if (cp[0] == '|' && cp[1] == '&') return (1); if (cp[0] == '<' && cp[1] == '<') return (1); if (cp[0] == '>' && cp[1] == '>') return (1); } if (what & EQOP) { if (cp[0] == '=') { if (cp[1] == '=') return (EQEQ); if (cp[1] == '~') return (EQMATCH); } else if (cp[0] == '!') { if (cp[1] == '=') return (NOTEQ); if (cp[1] == '~') return (NOTEQMATCH); } } } if (what & RELOP) { if (*cp == '<') return (LSS); if (*cp == '>') return (GTR); } return (0); } int egetn(tchar *cp) { #ifdef TRACE tprintf("TRACE- egetn()\n"); #endif if (*cp && *cp != '-' && !digit(*cp)) bferr("Expression syntax"); return (getn(cp)); } /* Phew! */ #ifdef EDEBUG void etraci(tchar *str, int i, tchar ***vp) { printf("%s=%d\t", str, i); blkpr(*vp); printf("\n"); } void etracc(tchar *str, tchar *cp, tchar ***vp) { printf("%s=%s\t", str, cp); blkpr(*vp); printf("\n"); } #endif