|
|
1.1 root 1: /*
2: * execute command tree
3: */
4:
5: static char *RCSid = "$Header: exec.c,v 3.1 88/11/03 09:15:46 egisin Exp $";
6:
7: #include <stddef.h>
8: #include <stdlib.h>
9: #include <stdio.h>
10: #include <string.h>
11: #include <errno.h>
12: #include <signal.h>
13: #include <setjmp.h>
14: #include <unistd.h>
15: #include <fcntl.h>
16: #include "sh.h"
17: #include "lex.h"
18: #include "tree.h"
19: #include "table.h"
20:
21: static int comexec ARGS((struct op *t, char **vp, char **ap, int flags));
22: static void iosetup ARGS((struct ioword *iop));
23: static void echo ARGS((char **, char **));
24: static int herein ARGS((char *name, int sub));
25:
26: /*
27: * execute command tree
28: */
29: int
30: execute(t, flags)
31: register struct op *t;
32: Volatile int flags; /* if XEXEC don't fork */
33: {
34: int i;
35: int Volatile rv = 0;
36: int pv[2];
37: register char **ap;
38: char *s, *cp;
39: struct ioword **iowp;
40:
41: if (t == NULL)
42: return 0;
43:
44: if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
45: return exchild(t, flags); /* run in sub-process */
46:
47: newenv(E_EXEC);
48: if (trap)
49: runtraps();
50:
51: if (t->ioact != NULL || t->type == TPIPE) {
52: e.savefd = alloc(sizeofN(short, NUFILE), ATEMP);
53: for (i = 0; i < NUFILE; i++)
54: e.savefd[i] = 0; /* not redirected */
55: }
56:
57: /* do redirection, to be restored in quitenv() */
58: if (t->ioact != NULL)
59: for (iowp = t->ioact; *iowp != NULL; iowp++) {
60: if ((flags&XPIPEI) && (*iowp)->unit == 0 ||
61: (flags&XPIPEO) && (*iowp)->unit == 1)
62: errorf("attempt to redirect fd 0/1 in pipe\n");
63: iosetup(*iowp);
64: }
65:
66: switch(t->type) {
67: case TCOM:
68: e.type = E_TCOM;
69: rv = comexec(t, eval(t->vars, DOTILDE),
70: eval(t->args, DOBLANK|DOGLOB|DOTILDE), flags);
71: break;
72:
73: case TPAREN:
74: rv = execute(t->left, flags|XFORK);
75: break;
76:
77: case TPIPE:
78: flags |= XFORK;
79: e.savefd[0] = savefd(0);
80: e.savefd[1] = savefd(1);
81: flags |= XPIPEO;
82: (void) dup2(e.savefd[0], 0); /* stdin of first */
83: while (t->type == TPIPE) {
84: openpipe(pv);
85: (void) dup2(pv[1], 1); /* stdout of curr */
86: exchild(t->left, flags);
87: (void) dup2(pv[0], 0); /* stdin of next */
88: closepipe(pv);
89: flags |= XPIPEI;
90: t = t->right;
91: }
92: flags &= ~ XPIPEO;
93: (void) dup2(e.savefd[1], 1); /* stdout of last */
94: exchild(t, flags);
95: (void) dup2(e.savefd[0], 0); /* close pipe in */
96: /*
97: * added background check to avoid waiting on unwanted pipelines
98: */
99: if (!(flags & XBGND))
100: rv = waitlast();
101: break;
102:
103: case TLIST:
104: while (t->type == TLIST) {
105: execute(t->left, 0);
106: t = t->right;
107: }
108: rv = execute(t, 0);
109: break;
110:
111: case TASYNC:
112: rv = execute(t->left, flags|XBGND|XFORK);
113: break;
114:
115: case TOR:
116: case TAND:
117: rv = execute(t->left, 0);
118: if (t->right != NULL && (rv == 0) == (t->type == TAND))
119: rv = execute(t->right, 0);
120: break;
121:
122: case TFOR:
123: e.type = E_LOOP;
124: ap = (t->vars != NULL) ?
125: eval(t->vars, DOBLANK|DOGLOB|DOTILDE) : e.loc->argv + 1;
126: while ((i = setjmp(e.jbuf)))
127: if (i == LBREAK)
128: goto Break1;
129: while (*ap != NULL) {
130: setstr(global(t->str), *ap++);
131: rv = execute(t->left, 0);
132: }
133: Break1:
134: break;
135:
136: case TWHILE:
137: case TUNTIL:
138: e.type = E_LOOP;
139: while ((i = setjmp(e.jbuf)))
140: if (i == LBREAK)
141: goto Break2;
142: while ((execute(t->left, 0) == 0) == (t->type == TWHILE))
143: rv = execute(t->right, 0);
144: Break2:
145: break;
146:
147: case TIF:
148: case TELIF:
149: if (t->right == NULL)
150: break; /* should be error */
151: rv = execute(t->left, 0) == 0 ?
152: execute(t->right->left, 0) :
153: execute(t->right->right, 0);
154: break;
155:
156: case TCASE:
157: cp = evalstr(t->str, 0);
158: for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
159: for (ap = t->vars; *ap; ap++)
160: if ((s = evalstr(*ap, DOPAT)) && gmatch(cp, s))
161: goto Found;
162: break;
163: Found:
164: rv = execute(t->left, 0);
165: break;
166:
167: case TBRACE:
168: rv = execute(t->left, 0);
169: break;
170:
171: case TFUNCT:
172: rv = define(t->str, t->left);
173: break;
174:
175: case TTIME:
176: rv = timex(t, flags);
177: break;
178:
179: case TEXEC: /* an eval'd TCOM */
180: s = t->args[0];
181: ap = makenv();
182: #if _MINIX || COHERENT /* no F_SETFD close-on-exec */
183: for (i = 10; i < 20; i++)
184: close(i);
185: #endif
186: execve(t->str, t->args, ap);
187: #if 0
188: if (errno == ENOEXEC) {
189: #else
190: if (errno == -1 || errno == ENOEXEC) {
191: #endif
192: *t->args-- = t->str;
193: *t->args = s;
194: execve(SHELL, t->args, ap);
195: errorf("No shell\n");
196: }
197: errorf("%s: %s\n", s, strerror(errno));
198: }
199:
200: quitenv(); /* restores IO */
201: if (e.interactive) { /* flush stdout, shlout */
202: fflush(shf[1]);
203: fflush(shf[2]);
204: }
205: if ((flags&XEXEC))
206: exit(rv); /* exit child */
207: return rv;
208: }
209:
210: /*
211: * execute simple command
212: */
213:
214: static int
215: comexec(t, vp, ap, flags)
216: struct op *t;
217: register char **ap, **vp;
218: int flags;
219: {
220: int i;
221: int rv = 0;
222: register char *cp;
223: register struct tbl *tp = NULL;
224: register struct block *l;
225: static struct op texec = {TEXEC};
226: extern int c_exec(), c_builtin();
227:
228: if (flag[FXTRACE])
229: echo(vp, ap);
230:
231: /* create new variable/function block */
232: l = alloc(sizeof(struct block), ATEMP);
233: l->next = e.loc; e.loc = l;
234: newblock();
235:
236: Doexec:
237: if ((cp = *ap) == NULL)
238: cp = ":";
239: tp = findcom(cp, 1);
240:
241: switch (tp->type) {
242: case CSHELL: /* shell built-in */
243: while (tp->val.f == c_builtin) {
244: if ((cp = *++ap) == NULL)
245: break;
246: tp = tsearch(&builtins, cp, hash(cp));
247: if (tp == NULL)
248: errorf("%s: not builtin\n", cp);
249: }
250: if (tp->val.f == c_exec) {
251: if (*++ap == NULL) {
252: e.savefd = NULL; /* don't restore redirection */
253: break;
254: }
255: flags |= XEXEC;
256: goto Doexec;
257: }
258: if ((tp->flag&TRACE))
259: e.loc = l->next; /* no local block */
260: i = (tp->flag&TRACE) ? 0 : LOCAL;
261: while (*vp != NULL)
262: (void) typeset(*vp++, i, 0);
263: rv = (*tp->val.f)(ap);
264: break;
265:
266: case CFUNC: /* function call */
267: if (!(tp->flag&ISSET))
268: errorf("%s: undefined function", cp);
269: l->argv = ap;
270: for (i = 0; *ap++ != NULL; i++)
271: ;
272: l->argc = i - 1;
273: resetopts();
274: while (*vp != NULL)
275: (void) typeset(*vp++, LOCAL, 0);
276: e.type = E_FUNC;
277: if (setjmp(e.jbuf))
278: rv = exstat; /* return # */
279: else
280: rv = execute(tp->val.t, 0);
281: break;
282:
283: case CEXEC: /* executable command */
284: if (!(tp->flag&ISSET)) {
285: shellf("%s: not found\n", cp);
286: rv = 1;
287: break;
288: }
289:
290: /* set $_ to program's full path */
291: setstr(typeset("_", LOCAL|EXPORT, 0), tp->val.s);
292: while (*vp != NULL)
293: (void) typeset(*vp++, LOCAL|EXPORT, 0);
294:
295: if ((flags&XEXEC)) {
296: j_exit();
297: #if !COHERENT
298: signal(SIGINT, SIG_DFL);
299: signal(SIGQUIT, SIG_DFL);
300: #endif
301: }
302:
303: /* to fork we set up a TEXEC node and call execute */
304: texec.left = t; /* for tprint */
305: texec.str = tp->val.s;
306: texec.args = ap;
307: rv = exchild(&texec, flags);
308: break;
309: }
310: if (rv != 0 && flag[FERREXIT])
311: leave(rv);
312: return (exstat = rv);
313: }
314:
315: int
316: shcomexec(wp)
317: register char **wp;
318: {
319: register struct tbl *tp;
320:
321: tp = tsearch(&builtins, *wp, hash(*wp));
322: if (tp == NULL)
323: errorf("%s: shcomexec botch\n", *wp);
324: return (*tp->val.f)(wp);
325: }
326:
327: /*
328: * define function
329: */
330: int
331: define(name, t)
332: char *name;
333: struct op *t;
334: {
335: register struct block *l;
336: register struct tbl *tp;
337:
338: for (l = e.loc; l != NULL; l = l->next) {
339: lastarea = &l->area;
340: tp = tsearch(&l->funs, name, hash(name));
341: if (tp != NULL && (tp->flag&DEFINED))
342: break;
343: if (l->next == NULL) {
344: tp = tenter(&l->funs, name, hash(name));
345: tp->flag = DEFINED|FUNCT;
346: tp->type = CFUNC;
347: }
348: }
349:
350: if ((tp->flag&ALLOC))
351: tfree(tp->val.t, lastarea);
352: tp->flag &= ~(ISSET|ALLOC);
353:
354: if (t == NULL) /* undefine */
355: return 0;
356:
357: tp->val.t = tcopy(t, lastarea);
358: tp->flag |= (ISSET|ALLOC);
359:
360: return 0;
361: }
362:
363: /*
364: * add builtin
365: */
366: builtin(name, func)
367: char *name;
368: int (*func)();
369: {
370: register struct tbl *tp;
371: int flag = DEFINED;
372:
373: if (*name == '=') { /* sets keyword variables */
374: name++;
375: flag |= TRACE; /* command does variable assignment */
376: }
377:
378: tp = tenter(&builtins, name, hash(name));
379: tp->flag |= flag;
380: tp->type = CSHELL;
381: tp->val.f = func;
382: }
383:
384: /*
385: * find command
386: * either function, hashed command, or built-in (in that order)
387: */
388: struct tbl *
389: findcom(name, insert)
390: char *name;
391: int insert; /* insert if not found */
392: {
393: register struct block *l = e.loc;
394: unsigned int h = hash(name);
395: register struct tbl *tp = NULL;
396: static struct tbl temp;
397:
398: if (strchr(name, '/') != NULL) {
399: tp = &temp;
400: tp->type = CEXEC;
401: tp->flag = 0; /* make ~ISSET */
402: goto Search;
403: }
404: for (l = e.loc; l != NULL; l = l->next) {
405: tp = tsearch(&l->funs, name, h);
406: if (tp != NULL && (tp->flag&DEFINED))
407: break;
408: }
409: if (tp == NULL)
410: tp = tsearch(&commands, name, h);
411: if (tp == NULL)
412: tp = tsearch(&builtins, name, h);
413: if (tp == NULL && insert) {
414: tp = tenter(&commands, name, h);
415: tp->type = CEXEC;
416: tp->flag = DEFINED;
417: }
418: Search:
419: if (tp->type == CEXEC && !(tp->flag&ISSET)) {
420: if (!flag[FHASHALL]) {
421: tp = &temp;
422: tp->type = CEXEC;
423: tp->flag = 0; /* make ~ISSET */
424: }
425: name = search(name, path, 1);
426: if (name != NULL) {
427: tp->val.s = strsave(name,
428: (tp == &temp) ? ATEMP : APERM);
429: tp->flag |= ISSET|ALLOC;
430: }
431: }
432: return tp;
433: }
434:
435: /*
436: * flush executable commands with relative paths
437: */
438: flushcom(all)
439: int all; /* just relative or all */
440: {
441: register struct tbl *tp;
442:
443: for (twalk(&commands); (tp = tnext()) != NULL; )
444: if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
445: if ((tp->flag&ALLOC))
446: afree(tp->val.s, commands.areap);
447: tp->flag = DEFINED; /* make ~ISSET */
448: }
449: }
450:
451: /*
452: * search for command with PATH
453: */
454: char *
455: search(name, path, mode)
456: char *name, *path;
457: int mode; /* 0: readable; 1: executable */
458: {
459: register int i;
460: register char *sp, *tp;
461: int colon = FALSE;
462:
463: if (strchr(name, '/'))
464: return (eaccess(name, mode) == 0) ? name : NULL;
465:
466: sp = path;
467: do {
468: tp = line;
469: colon = FALSE;
470: for (; *sp != '\0'; tp++) {
471: if ((*tp = *sp++) == ':') {
472: colon = TRUE;
473: break;
474: }
475: }
476: if (tp != line)
477: *tp++ = '/';
478: for (i = 0; (*tp++ = name[i++]) != '\0';)
479: ;
480: i = eaccess(line, mode);
481: if (i == 0)
482: return line;
483: /* what should we do about EACCES? */
484: } while (*sp != '\0' || colon);
485: return NULL;
486: }
487:
488: /*
489: * set up redirection, saving old fd's in e.savefd
490: */
491: static void
492: iosetup(iop)
493: register struct ioword *iop;
494: {
495: register int u = -1;
496: char *cp, *msg;
497: extern long lseek();
498:
499: if (iop->unit == 0 || iop->unit == 1 || iop->unit == 2)
500: e.interactive = 0;
501: e.savefd[iop->unit] = savefd(iop->unit);
502:
503: msg = iop->flag&(IOREAD|IOHERE)? "open": "create";
504: cp = iop->name;
505: if (!(iop->flag & IOHERE))
506: cp = evalstr(cp, DOTILDE);
507: if (iop->flag&IODUP)
508: iop->flag &= ~(IOREAD|IOWRITE); /* todo: lex.c */
509:
510: switch (iop->flag) {
511: case IOREAD:
512: u = open(cp, 0);
513: break;
514:
515: case IOHERE:
516: case IOHERE|IOXHERE:
517: u = herein(cp, iop->flag&IOXHERE);
518: /* cp may have wrong name */
519: break;
520:
521: case IOWRITE|IOCAT:
522: if ((u = open(cp, 1)) >= 0) {
523: (void) lseek(u, (long)0, 2);
524: break;
525: }
526: /* FALLTHROUGH */
527: case IOWRITE:
528: u = creat(cp, 0666);
529: break;
530:
531: case IODUP:
532: if (*cp == '-')
533: close(iop->unit);
534: else
535: if (digit(*cp))
536: u = *cp - '0';
537: else
538: errorf("%s: illegal >& argument\n", cp);
539: break;
540: }
541: if (u < 0)
542: errorf("%s: cannot %s\n", cp, msg);
543: if (u != iop->unit) {
544: (void) dup2(u, iop->unit);
545: if (iop->flag != IODUP)
546: close(u);
547: }
548:
549: fopenshf(iop->unit);
550: }
551:
552: /*
553: * open here document temp file.
554: * if unquoted here, expand here temp file into second temp file.
555: */
556: static int
557: herein(hname, sub)
558: char *hname;
559: int sub;
560: {
561: int fd;
562: FILE * Volatile f = NULL;
563:
564: f = fopen(hname, "r");
565: if (f == NULL)
566: return -1;
567: setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
568:
569: if (sub) {
570: char *cp;
571: struct source *s;
572: struct temp *h;
573:
574: newenv(E_ERRH);
575: if (setjmp(e.jbuf)) {
576: if (f != NULL)
577: fclose(f);
578: quitenv();
579: return -1; /* todo: error()? */
580: }
581:
582: /* set up yylex input from here file */
583: s = pushs(SFILE);
584: s->u.file = f;
585: source = s;
586: if (yylex(ONEWORD) != LWORD)
587: errorf("exec:herein error\n");
588: cp = evalstr(yylval.cp, 0);
589:
590: /* write expanded input to another temp file */
591: h = maketemp(ATEMP);
592: h->next = e.temps; e.temps = h;
593: if (h == NULL)
594: error();
595: f = fopen(h->name, "w+");
596: if (f == NULL)
597: error();
598: setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
599: fputs(cp, f);
600: rewind(f);
601:
602: quitenv();
603: }
604: fd = dup(fileno(f));
605: fclose(f);
606: return fd;
607: }
608:
609: static void
610: echo(vp, ap)
611: register char **vp, **ap;
612: {
613: shellf("+");
614: while (*vp != NULL)
615: shellf(" %s", *vp++);
616: while (*ap != NULL)
617: shellf(" %s", *ap++);
618: shellf("\n");
619: }
620:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.