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
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(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 = ¶ml;
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(¶ml);
613 t = syntax(paraml.next, ¶ml, 0);
614 if (err)
615 error("%s", gettext(err));
616 execute(t, -1);
617 freelex(¶ml), 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