xref: /illumos-gate/usr/src/cmd/csh/sh.exp.c (revision 258f91c6)
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 #include "sh.h"
16 #include "sh.tconst.h"
17 
18 /*
19  * C shell
20  */
21 
22 #define	IGNORE	1	/* in ignore, it means to ignore value, just parse */
23 #define	NOGLOB	2	/* in ignore, it means not to globone */
24 
25 #define	ADDOP	1
26 #define	MULOP	2
27 #define	EQOP	4
28 #define	RELOP	8
29 #define	RESTOP	16
30 #define	ANYOP	31
31 
32 #define	EQEQ	1
33 #define	GTR	2
34 #define	LSS	4
35 #define	NOTEQ	6
36 #define	EQMATCH 7
37 #define	NOTEQMATCH 8
38 
39 int	uid;
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
chk_access(tchar * path,mode_t mode)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((char *)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
exp(tchar *** vp)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
exp0(tchar *** vp,bool ignore)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
exp1(tchar *** vp,bool ignore)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
exp2(tchar *** vp,bool ignore)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
exp2a(tchar *** vp,bool ignore)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
exp2b(tchar *** vp,bool ignore)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
exp2c(tchar *** vp,bool ignore)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 *
exp3(tchar *** vp,bool ignore)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 *
exp3a(tchar *** vp,bool ignore)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 *
exp4(tchar *** vp,bool ignore)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 *
exp5(tchar *** vp,bool ignore)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 *
exp6(tchar *** vp,bool ignore)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
evalav(tchar ** v)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_msg)
615 		error("%s", gettext(err_msg));
616 	execute(t, -1);
617 	freelex(&paraml), freesyn(t);
618 }
619 
620 int
isa(tchar * cp,int what)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
egetn(tchar * cp)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
etraci(tchar * str,int i,tchar *** vp)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
etracc(tchar * str,tchar * cp,tchar *** vp)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