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
41int	exp0(tchar ***, bool);
42int	exp1(tchar ***, bool);
43int	exp2(tchar ***, bool);
44int	exp2a(tchar ***, bool);
45int	exp2b(tchar ***, bool);
46int	exp2c(tchar ***, bool);
47tchar	*exp3(tchar ***, bool);
48tchar	*exp3a(tchar ***, bool);
49tchar	*exp4(tchar ***, bool);
50tchar	*exp5(tchar ***, bool);
51tchar	*exp6(tchar ***, bool);
52void	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
65int
66chk_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
99int
100exp(tchar ***vp)
101{
102#ifdef TRACE
103	tprintf("TRACE- exp()\n");
104#endif
105
106	return (exp0(vp, 0));
107}
108
109int
110exp0(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
133int
134exp1(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
157int
158exp2(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
181int
182exp2a(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
205int
206exp2b(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
229int
230exp2c(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
276tchar *
277exp3(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
321tchar *
322exp3a(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
352tchar *
353exp4(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
388tchar *
389exp5(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
434tchar *
435exp6(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
588void
589evalav(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
620int
621isa(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
669int
670egetn(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
684void
685etraci(tchar *str, int i, tchar ***vp)
686{
687
688	printf("%s=%d\t", str, i);
689	blkpr(*vp);
690	printf("\n");
691}
692
693void
694etracc(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