Home | History | Annotate | Download | only in csh
      1 /*
      2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
      7 /*	  All Rights Reserved  	*/
      8 
      9 /*
     10  * Copyright (c) 1980 Regents of the University of California.
     11  * All rights reserved.  The Berkeley Software License Agreement
     12  * specifies the terms and conditions for redistribution.
     13  */
     14 
     15 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     16 
     17 #include "sh.h"
     18 #include "sh.tconst.h"
     19 
     20 /*
     21  * C shell
     22  */
     23 
     24 #define	IGNORE	1	/* in ignore, it means to ignore value, just parse */
     25 #define	NOGLOB	2	/* in ignore, it means not to globone */
     26 
     27 #define	ADDOP	1
     28 #define	MULOP	2
     29 #define	EQOP	4
     30 #define	RELOP	8
     31 #define	RESTOP	16
     32 #define	ANYOP	31
     33 
     34 #define	EQEQ	1
     35 #define	GTR	2
     36 #define	LSS	4
     37 #define	NOTEQ	6
     38 #define	EQMATCH 7
     39 #define	NOTEQMATCH 8
     40 
     41 int	exp0(tchar ***, bool);
     42 int	exp1(tchar ***, bool);
     43 int	exp2(tchar ***, bool);
     44 int	exp2a(tchar ***, bool);
     45 int	exp2b(tchar ***, bool);
     46 int	exp2c(tchar ***, bool);
     47 tchar	*exp3(tchar ***, bool);
     48 tchar	*exp3a(tchar ***, bool);
     49 tchar	*exp4(tchar ***, bool);
     50 tchar	*exp5(tchar ***, bool);
     51 tchar	*exp6(tchar ***, bool);
     52 void	evalav(tchar **);
     53 
     54 /*
     55  * Determine if file given by name is accessible with permissions
     56  * given by mode.
     57  *
     58  * Borrowed from the Bourne sh, and modified a bit
     59  *
     60  * If the requested access  is  permitted,  a  value  of  0  is
     61  * returned.  Otherwise, a value of -1 is returned and errno is
     62  * set to indicate the error
     63  */
     64 
     65 int
     66 chk_access(tchar *path, mode_t mode)
     67 {
     68 	static int flag;
     69 	static uid_t euid;
     70 	struct stat statb;
     71 	mode_t ftype;
     72 	unsigned char name[MAXPATHLEN*MB_LEN_MAX]; /* General use buffer. */
     73 
     74 	/* convert tchar * to char * */
     75 	tstostr(name, path);
     76 
     77 	if (flag == 0) {
     78 		euid = geteuid();
     79 		flag = 1;
     80 	}
     81 	if (stat((char *)name, &statb) == 0) {
     82 		ftype = statb.st_mode & S_IFMT;
     83 		if (access((char *)name, 010|(mode>>6)) == 0) {
     84 			if (euid == 0) {
     85 				if (ftype != S_IFREG || mode != S_IEXEC)
     86 					return (0);
     87 				/* root can execute file as long as it has execute
     88 				permission for someone */
     89 				if (statb.st_mode & (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
     90 					return (0);
     91 				return (-1);
     92 			}
     93 			return (0);
     94 		}
     95 	}
     96 	return (-1);
     97 }
     98 
     99 int
    100 exp(tchar ***vp)
    101 {
    102 #ifdef TRACE
    103 	tprintf("TRACE- exp()\n");
    104 #endif
    105 
    106 	return (exp0(vp, 0));
    107 }
    108 
    109 int
    110 exp0(tchar ***vp, bool ignore)
    111 {
    112 	int p1 = exp1(vp, ignore);
    113 #ifdef TRACE
    114 	tprintf("TRACE- exp0()\n");
    115 #endif
    116 
    117 #ifdef EDEBUG
    118 	etraci("exp0 p1", p1, vp);
    119 #endif
    120 	if (**vp && eq(**vp, S_BARBAR /* "||" */)) {
    121 		int p2;
    122 
    123 		(*vp)++;
    124 		p2 = exp0(vp, (ignore&IGNORE) || p1);
    125 #ifdef EDEBUG
    126 		etraci("exp0 p2", p2, vp);
    127 #endif
    128 		return (p1 || p2);
    129 	}
    130 	return (p1);
    131 }
    132 
    133 int
    134 exp1(tchar ***vp, bool ignore)
    135 {
    136 	int p1 = exp2(vp, ignore);
    137 
    138 #ifdef TRACE
    139 	tprintf("TRACE- exp1()\n");
    140 #endif
    141 #ifdef EDEBUG
    142 	etraci("exp1 p1", p1, vp);
    143 #endif
    144 	if (**vp && eq(**vp, S_ANDAND /* "&&" */)) {
    145 		int p2;
    146 
    147 		(*vp)++;
    148 		p2 = exp1(vp, (ignore&IGNORE) || !p1);
    149 #ifdef EDEBUG
    150 		etraci("exp1 p2", p2, vp);
    151 #endif
    152 		return (p1 && p2);
    153 	}
    154 	return (p1);
    155 }
    156 
    157 int
    158 exp2(tchar ***vp, bool ignore)
    159 {
    160 	int p1 = exp2a(vp, ignore);
    161 
    162 #ifdef TRACE
    163 	tprintf("TRACE- exp2()\n");
    164 #endif
    165 #ifdef EDEBUG
    166 	etraci("exp3 p1", p1, vp);
    167 #endif
    168 	if (**vp && eq(**vp, S_BAR /* "|" */)) {
    169 		int p2;
    170 
    171 		(*vp)++;
    172 		p2 = exp2(vp, ignore);
    173 #ifdef EDEBUG
    174 		etraci("exp3 p2", p2, vp);
    175 #endif
    176 		return (p1 | p2);
    177 	}
    178 	return (p1);
    179 }
    180 
    181 int
    182 exp2a(tchar ***vp, bool ignore)
    183 {
    184 	int p1 = exp2b(vp, ignore);
    185 
    186 #ifdef TRACE
    187 	tprintf("TRACE- exp2a()\n");
    188 #endif
    189 #ifdef EDEBUG
    190 	etraci("exp2a p1", p1, vp);
    191 #endif
    192 	if (**vp && eq(**vp, S_HAT /* "^" */)) {
    193 		int p2;
    194 
    195 		(*vp)++;
    196 		p2 = exp2a(vp, ignore);
    197 #ifdef EDEBUG
    198 		etraci("exp2a p2", p2, vp);
    199 #endif
    200 		return (p1 ^ p2);
    201 	}
    202 	return (p1);
    203 }
    204 
    205 int
    206 exp2b(tchar ***vp, bool ignore)
    207 {
    208 	int p1 = exp2c(vp, ignore);
    209 
    210 #ifdef TRACE
    211 	tprintf("TRACE- exp2b()\n");
    212 #endif
    213 #ifdef EDEBUG
    214 	etraci("exp2b p1", p1, vp);
    215 #endif
    216 	if (**vp && eq(**vp, S_AND /* "&" */)) {
    217 		int p2;
    218 
    219 		(*vp)++;
    220 		p2 = exp2b(vp, ignore);
    221 #ifdef EDEBUG
    222 		etraci("exp2b p2", p2, vp);
    223 #endif
    224 		return (p1 & p2);
    225 	}
    226 	return (p1);
    227 }
    228 
    229 int
    230 exp2c(tchar ***vp, bool ignore)
    231 {
    232 	tchar *p1 = exp3(vp, ignore);
    233 	tchar *p2;
    234 	int i;
    235 
    236 #ifdef TRACE
    237 	tprintf("TRACE- exp2c()\n");
    238 #endif
    239 #ifdef EDEBUG
    240 	etracc("exp2c p1", p1, vp);
    241 #endif
    242 	if (i = isa(**vp, EQOP)) {
    243 		(*vp)++;
    244 		if (i == EQMATCH || i == NOTEQMATCH)
    245 			ignore |= NOGLOB;
    246 		p2 = exp3(vp, ignore);
    247 #ifdef EDEBUG
    248 		etracc("exp2c p2", p2, vp);
    249 #endif
    250 		if (!(ignore&IGNORE)) switch (i) {
    251 
    252 		case EQEQ:
    253 			i = eq(p1, p2);
    254 			break;
    255 
    256 		case NOTEQ:
    257 			i = !eq(p1, p2);
    258 			break;
    259 
    260 		case EQMATCH:
    261 			i = Gmatch(p1, p2);
    262 			break;
    263 
    264 		case NOTEQMATCH:
    265 			i = !Gmatch(p1, p2);
    266 			break;
    267 		}
    268 		xfree(p1), xfree(p2);
    269 		return (i);
    270 	}
    271 	i = egetn(p1);
    272 	xfree(p1);
    273 	return (i);
    274 }
    275 
    276 tchar *
    277 exp3(tchar ***vp, bool ignore)
    278 {
    279 	tchar *p1, *p2;
    280 	int i;
    281 
    282 #ifdef TRACE
    283 	tprintf("TRACE- exp3()\n");
    284 #endif
    285 	p1 = exp3a(vp, ignore);
    286 #ifdef EDEBUG
    287 	etracc("exp3 p1", p1, vp);
    288 #endif
    289 	if (i = isa(**vp, RELOP)) {
    290 		(*vp)++;
    291 		if (**vp && eq(**vp, S_EQ /* "=" */))
    292 			i |= 1, (*vp)++;
    293 		p2 = exp3(vp, ignore);
    294 #ifdef EDEBUG
    295 		etracc("exp3 p2", p2, vp);
    296 #endif
    297 		if (!(ignore&IGNORE)) switch (i) {
    298 
    299 		case GTR:
    300 			i = egetn(p1) > egetn(p2);
    301 			break;
    302 
    303 		case GTR|1:
    304 			i = egetn(p1) >= egetn(p2);
    305 			break;
    306 
    307 		case LSS:
    308 			i = egetn(p1) < egetn(p2);
    309 			break;
    310 
    311 		case LSS|1:
    312 			i = egetn(p1) <= egetn(p2);
    313 			break;
    314 		}
    315 		xfree(p1), xfree(p2);
    316 		return (putn(i));
    317 	}
    318 	return (p1);
    319 }
    320 
    321 tchar *
    322 exp3a(tchar ***vp, bool ignore)
    323 {
    324 	tchar *p1, *p2, *op;
    325 	int i;
    326 
    327 #ifdef TRACE
    328 	tprintf("TRACE- exp3a()\n");
    329 #endif
    330 	p1 = exp4(vp, ignore);
    331 #ifdef EDEBUG
    332 	etracc("exp3a p1", p1, vp);
    333 #endif
    334 	op = **vp;
    335 	/* if (op && any(op[0], "<>") && op[0] == op[1]) { */
    336 	if (op && (op[0] == '<' || op[0] == '>') && op[0] == op[1]) {
    337 		(*vp)++;
    338 		p2 = exp3a(vp, ignore);
    339 #ifdef EDEBUG
    340 		etracc("exp3a p2", p2, vp);
    341 #endif
    342 		if (op[0] == '<')
    343 			i = egetn(p1) << egetn(p2);
    344 		else
    345 			i = egetn(p1) >> egetn(p2);
    346 		xfree(p1), xfree(p2);
    347 		return (putn(i));
    348 	}
    349 	return (p1);
    350 }
    351 
    352 tchar *
    353 exp4(tchar ***vp, bool ignore)
    354 {
    355 	tchar *p1, *p2;
    356 	int i = 0;
    357 
    358 #ifdef TRACE
    359 	tprintf("TRACE- exp4()\n");
    360 #endif
    361 	p1 = exp5(vp, ignore);
    362 #ifdef EDEBUG
    363 	etracc("exp4 p1", p1, vp);
    364 #endif
    365 	if (isa(**vp, ADDOP)) {
    366 		tchar *op = *(*vp)++;
    367 
    368 		p2 = exp4(vp, ignore);
    369 #ifdef EDEBUG
    370 		etracc("exp4 p2", p2, vp);
    371 #endif
    372 		if (!(ignore&IGNORE)) switch (op[0]) {
    373 
    374 		case '+':
    375 			i = egetn(p1) + egetn(p2);
    376 			break;
    377 
    378 		case '-':
    379 			i = egetn(p1) - egetn(p2);
    380 			break;
    381 		}
    382 		xfree(p1), xfree(p2);
    383 		return (putn(i));
    384 	}
    385 	return (p1);
    386 }
    387 
    388 tchar *
    389 exp5(tchar ***vp, bool ignore)
    390 {
    391 	tchar *p1, *p2;
    392 	int i = 0;
    393 
    394 #ifdef TRACE
    395 	tprintf("TRACE- exp5()\n");
    396 #endif
    397 	p1 = exp6(vp, ignore);
    398 #ifdef EDEBUG
    399 	etracc("exp5 p1", p1, vp);
    400 #endif
    401 	if (isa(**vp, MULOP)) {
    402 		tchar *op = *(*vp)++;
    403 
    404 		p2 = exp5(vp, ignore);
    405 #ifdef EDEBUG
    406 		etracc("exp5 p2", p2, vp);
    407 #endif
    408 		if (!(ignore&IGNORE)) switch (op[0]) {
    409 
    410 		case '*':
    411 			i = egetn(p1) * egetn(p2);
    412 			break;
    413 
    414 		case '/':
    415 			i = egetn(p2);
    416 			if (i == 0)
    417 				error("Divide by 0");
    418 			i = egetn(p1) / i;
    419 			break;
    420 
    421 		case '%':
    422 			i = egetn(p2);
    423 			if (i == 0)
    424 				error("Mod by 0");
    425 			i = egetn(p1) % i;
    426 			break;
    427 		}
    428 		xfree(p1), xfree(p2);
    429 		return (putn(i));
    430 	}
    431 	return (p1);
    432 }
    433 
    434 tchar *
    435 exp6(tchar ***vp, bool ignore)
    436 {
    437 	int ccode, i;
    438 	tchar *cp, *dp, *ep;
    439 
    440 #ifdef TRACE
    441 	tprintf("TRACE- exp6()\n");
    442 #endif
    443 	if (**vp == 0)
    444 		bferr("Expression syntax");
    445 	if (eq(**vp, S_EXAS /* "!" */)) {
    446 		(*vp)++;
    447 		cp = exp6(vp, ignore);
    448 #ifdef EDEBUG
    449 		etracc("exp6 ! cp", cp, vp);
    450 #endif
    451 		i = egetn(cp);
    452 		xfree(cp);
    453 		return (putn(!i));
    454 	}
    455 	if (eq(**vp, S_TIL /* "~" */)) {
    456 		(*vp)++;
    457 		cp = exp6(vp, ignore);
    458 #ifdef EDEBUG
    459 		etracc("exp6 ~ cp", cp, vp);
    460 #endif
    461 		i = egetn(cp);
    462 		xfree(cp);
    463 		return (putn(~i));
    464 	}
    465 	if (eq(**vp, S_LPAR /* "(" */)) {
    466 		(*vp)++;
    467 		ccode = exp0(vp, ignore);
    468 #ifdef EDEBUG
    469 		etraci("exp6 () ccode", ccode, vp);
    470 #endif
    471 		if (*vp == 0 || **vp == 0 || ***vp != ')')
    472 			bferr("Expression syntax");
    473 		(*vp)++;
    474 		return (putn(ccode));
    475 	}
    476 	if (eq(**vp, S_LBRA /* "{" */)) {
    477 		tchar **v;
    478 		struct command faket;
    479 		tchar *fakecom[2];
    480 
    481 		faket.t_dtyp = TCOM;
    482 		faket.t_dflg = 0;
    483 		faket.t_dcar = faket.t_dcdr = faket.t_dspr = (struct command *)0;
    484 		faket.t_dcom = fakecom;
    485 		fakecom[0] = S_BRAPPPBRA /* "{ ... }" */;
    486 		fakecom[1] = NOSTR;
    487 		(*vp)++;
    488 		v = *vp;
    489 		for (;;) {
    490 			if (!**vp)
    491 				bferr("Missing }");
    492 			if (eq(*(*vp)++, S_RBRA /* "}" */))
    493 				break;
    494 		}
    495 		if (ignore&IGNORE)
    496 			return (S_ /* "" */);
    497 		psavejob();
    498 		if (pfork(&faket, -1) == 0) {
    499 			*--(*vp) = 0;
    500 			evalav(v);
    501 			exitstat();
    502 		}
    503 		pwait();
    504 		prestjob();
    505 #ifdef EDEBUG
    506 		etraci("exp6 {} status", egetn(value("status")), vp);
    507 #endif
    508 		return (putn(egetn(value(S_status /* "status" */)) == 0));
    509 	}
    510 	if (isa(**vp, ANYOP))
    511 		return (S_ /* "" */);
    512 	cp = *(*vp)++;
    513 	if (*cp == '-' && any(cp[1], S_erwxfdzo /* "erwxfdzo" */)) {
    514 		struct stat stb;
    515 
    516 		if (cp[2] != '\0')
    517 			bferr("Malformed file inquiry");
    518 
    519 		/*
    520 		 * Detect missing file names by checking for operator
    521 		 * in the file name position.  However, if an operator
    522 		 * name appears there, we must make sure that there's
    523 		 * no file by that name (e.g., "/") before announcing
    524 		 * an error.  Even this check isn't quite right, since
    525 		 * it doesn't take globbing into account.
    526 		 */
    527 		if ((**vp == NULL) || isa(**vp, ANYOP) && stat_(**vp, &stb))
    528 			bferr("Missing file name");
    529 		dp = *(*vp)++;
    530 
    531 		if (ignore&IGNORE)
    532 			return (S_ /* "" */);
    533 		ep = globone(dp);
    534 		switch (cp[1]) {
    535 
    536 		case 'r':
    537 			i = !chk_access(ep, S_IREAD);
    538 			break;
    539 
    540 		case 'w':
    541 			i = !chk_access(ep, S_IWRITE);
    542 			break;
    543 
    544 		case 'x':
    545 			i = !chk_access(ep, S_IEXEC);
    546 			break;
    547 
    548 		default:
    549 			if (stat_(ep, &stb)) {
    550 				xfree(ep);
    551 				return (S_0 /* "0" */);
    552 			}
    553 			switch (cp[1]) {
    554 
    555 			case 'f':
    556 				i = (stb.st_mode & S_IFMT) == S_IFREG;
    557 				break;
    558 
    559 			case 'd':
    560 				i = (stb.st_mode & S_IFMT) == S_IFDIR;
    561 				break;
    562 
    563 			case 'z':
    564 				i = stb.st_size == 0;
    565 				break;
    566 
    567 			case 'e':
    568 				i = 1;
    569 				break;
    570 
    571 			case 'o':
    572 				i = stb.st_uid == uid;
    573 				break;
    574 			}
    575 		}
    576 #ifdef EDEBUG
    577 		etraci("exp6 -? i", i, vp);
    578 #endif
    579 		xfree(ep);
    580 		return (putn(i));
    581 	}
    582 #ifdef EDEBUG
    583 	etracc("exp6 default", cp, vp);
    584 #endif
    585 	return (ignore&NOGLOB ? savestr(cp) : globone(cp));
    586 }
    587 
    588 void
    589 evalav(tchar **v)
    590 {
    591 	struct wordent paraml;
    592 	struct wordent *hp = &paraml;
    593 	struct command *t;
    594 	struct wordent *wdp = hp;
    595 
    596 #ifdef TRACE
    597 	tprintf("TRACE- evalav()\n");
    598 #endif
    599 	set(S_status /* "status" */, S_0 /* "0" */);
    600 	hp->prev = hp->next = hp;
    601 	hp->word = S_ /* "" */;
    602 	while (*v) {
    603 		struct wordent *new = (struct wordent *)xcalloc(1, sizeof *wdp);
    604 
    605 		new->prev = wdp;
    606 		new->next = hp;
    607 		wdp->next = new;
    608 		wdp = new;
    609 		wdp->word = savestr(*v++);
    610 	}
    611 	hp->prev = wdp;
    612 	alias(&paraml);
    613 	t = syntax(paraml.next, &paraml, 0);
    614 	if (err)
    615 		error("%s", gettext(err));
    616 	execute(t, -1);
    617 	freelex(&paraml), freesyn(t);
    618 }
    619 
    620 int
    621 isa(tchar *cp, int what)
    622 {
    623 
    624 #ifdef TRACE
    625 	tprintf("TRACE- isa()\n");
    626 #endif
    627 	if (cp == 0)
    628 		return ((what & RESTOP) != 0);
    629 	if (cp[1] == 0) {
    630 		if (what & ADDOP && (*cp == '+' || *cp == '-'))
    631 			return (1);
    632 		if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
    633 			return (1);
    634 		if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
    635 					*cp == '~' || *cp == '^' || *cp == '"'))
    636 			return (1);
    637 	} else if (cp[2] == 0) {
    638 		if (what & RESTOP) {
    639 			if (cp[0] == '|' && cp[1] == '&')
    640 				return (1);
    641 			if (cp[0] == '<' && cp[1] == '<')
    642 				return (1);
    643 			if (cp[0] == '>' && cp[1] == '>')
    644 				return (1);
    645 		}
    646 		if (what & EQOP) {
    647 			if (cp[0] == '=') {
    648 				if (cp[1] == '=')
    649 					return (EQEQ);
    650 				if (cp[1] == '~')
    651 					return (EQMATCH);
    652 			} else if (cp[0] == '!') {
    653 				if (cp[1] == '=')
    654 					return (NOTEQ);
    655 				if (cp[1] == '~')
    656 					return (NOTEQMATCH);
    657 			}
    658 		}
    659 	}
    660 	if (what & RELOP) {
    661 		if (*cp == '<')
    662 			return (LSS);
    663 		if (*cp == '>')
    664 			return (GTR);
    665 	}
    666 	return (0);
    667 }
    668 
    669 int
    670 egetn(tchar *cp)
    671 {
    672 
    673 #ifdef TRACE
    674 	tprintf("TRACE- egetn()\n");
    675 #endif
    676 	if (*cp && *cp != '-' && !digit(*cp))
    677 		bferr("Expression syntax");
    678 	return (getn(cp));
    679 }
    680 
    681 /* Phew! */
    682 
    683 #ifdef EDEBUG
    684 void
    685 etraci(tchar *str, int i, tchar ***vp)
    686 {
    687 
    688 	printf("%s=%d\t", str, i);
    689 	blkpr(*vp);
    690 	printf("\n");
    691 }
    692 
    693 void
    694 etracc(tchar *str, tchar *cp, tchar ***vp)
    695 {
    696 
    697 	printf("%s=%s\t", str, cp);
    698 	blkpr(*vp);
    699 	printf("\n");
    700 }
    701 #endif
    702