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