|
|
1.1 root 1: /*
2: * execute command tree
3: */
4:
5: static char *RCSid = "$Header: /newbits/usr/bin/korn/RCS/exec.c,v 1.2 91/08/01 12:40:11 bin Exp Locker: bin $";
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 <sys/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 (errno == ENOEXEC) {
188: *t->args-- = t->str;
189: *t->args = s;
190: execve(SHELL, t->args, ap);
191: errorf("No shell\n");
192: }
193: errorf("%s: %s\n", s, strerror(errno));
194: }
195:
196: quitenv(); /* restores IO */
197: if (e.interactive) { /* flush stdout, shlout */
198: fflush(shf[1]);
199: fflush(shf[2]);
200: }
201: if ((flags&XEXEC))
202: exit(rv); /* exit child */
203: return rv;
204: }
205:
206: /*
207: * execute simple command
208: */
209:
210: static int
211: comexec(t, vp, ap, flags)
212: struct op *t;
213: register char **ap, **vp;
214: int flags;
215: {
216: int i;
217: int rv = 0;
218: register char *cp;
219: register struct tbl *tp = NULL;
220: register struct block *l;
221: static struct op texec = {TEXEC};
222: extern int c_exec(), c_builtin();
223:
224: if (flag[FXTRACE])
225: echo(vp, ap);
226:
227: /* create new variable/function block */
228: l = alloc(sizeof(struct block), ATEMP);
229: l->next = e.loc; e.loc = l;
230: newblock();
231:
232: Doexec:
233: if ((cp = *ap) == NULL)
234: cp = ":";
235: tp = findcom(cp, 1);
236:
237: switch (tp->type) {
238: case CSHELL: /* shell built-in */
239: while (tp->val.f == c_builtin) {
240: if ((cp = *++ap) == NULL)
241: break;
242: tp = tsearch(&builtins, cp, hash(cp));
243: if (tp == NULL)
244: errorf("%s: not builtin\n", cp);
245: }
246: if (tp->val.f == c_exec) {
247: if (*++ap == NULL) {
248: e.savefd = NULL; /* don't restore redirection */
249: break;
250: }
251: flags |= XEXEC;
252: goto Doexec;
253: }
254: if ((tp->flag&TRACE))
255: e.loc = l->next; /* no local block */
256: i = (tp->flag&TRACE) ? 0 : LOCAL;
257: while (*vp != NULL)
258: (void) typeset(*vp++, i, 0);
259: rv = (*tp->val.f)(ap);
260: break;
261:
262: case CFUNC: /* function call */
263: if (!(tp->flag&ISSET))
264: errorf("%s: undefined function", cp);
265: l->argv = ap;
266: for (i = 0; *ap++ != NULL; i++)
267: ;
268: l->argc = i - 1;
269: resetopts();
270: while (*vp != NULL)
271: (void) typeset(*vp++, LOCAL, 0);
272: e.type = E_FUNC;
273: if (setjmp(e.jbuf))
274: rv = exstat; /* return # */
275: else
276: rv = execute(tp->val.t, 0);
277: break;
278:
279: case CEXEC: /* executable command */
280: if (!(tp->flag&ISSET)) {
281: shellf("%s: not found\n", cp);
282: rv = 1;
283: break;
284: }
285:
286: /* set $_ to program's full path */
287: setstr(typeset("_", LOCAL|EXPORT, 0), tp->val.s);
288: while (*vp != NULL)
289: (void) typeset(*vp++, LOCAL|EXPORT, 0);
290:
291: if ((flags&XEXEC)) {
292: j_exit();
293: #if !COHERENT
294: signal(SIGINT, SIG_DFL);
295: signal(SIGQUIT, SIG_DFL);
296: #endif
297: }
298:
299: /* to fork we set up a TEXEC node and call execute */
300: texec.left = t; /* for tprint */
301: texec.str = tp->val.s;
302: texec.args = ap;
303: rv = exchild(&texec, flags);
304: break;
305: }
306: if (rv != 0 && flag[FERREXIT])
307: leave(rv);
308: return (exstat = rv);
309: }
310:
311: int
312: shcomexec(wp)
313: register char **wp;
314: {
315: register struct tbl *tp;
316:
317: tp = tsearch(&builtins, *wp, hash(*wp));
318: if (tp == NULL)
319: errorf("%s: shcomexec botch\n", *wp);
320: return (*tp->val.f)(wp);
321: }
322:
323: /*
324: * define function
325: */
326: int
327: define(name, t)
328: char *name;
329: struct op *t;
330: {
331: register struct block *l;
332: register struct tbl *tp;
333:
334: for (l = e.loc; l != NULL; l = l->next) {
335: lastarea = &l->area;
336: tp = tsearch(&l->funs, name, hash(name));
337: if (tp != NULL && (tp->flag&DEFINED))
338: break;
339: if (l->next == NULL) {
340: tp = tenter(&l->funs, name, hash(name));
341: tp->flag = DEFINED|FUNCT;
342: tp->type = CFUNC;
343: }
344: }
345:
346: if ((tp->flag&ALLOC))
347: tfree(tp->val.t, lastarea);
348: tp->flag &= ~(ISSET|ALLOC);
349:
350: if (t == NULL) /* undefine */
351: return 0;
352:
353: tp->val.t = tcopy(t, lastarea);
354: tp->flag |= (ISSET|ALLOC);
355:
356: return 0;
357: }
358:
359: /*
360: * add builtin
361: */
362: builtin(name, func)
363: char *name;
364: int (*func)();
365: {
366: register struct tbl *tp;
367: int flag = DEFINED;
368:
369: if (*name == '=') { /* sets keyword variables */
370: name++;
371: flag |= TRACE; /* command does variable assignment */
372: }
373:
374: tp = tenter(&builtins, name, hash(name));
375: tp->flag |= flag;
376: tp->type = CSHELL;
377: tp->val.f = func;
378: }
379:
380: /*
381: * find command
382: * either function, hashed command, or built-in (in that order)
383: */
384: struct tbl *
385: findcom(name, insert)
386: char *name;
387: int insert; /* insert if not found */
388: {
389: register struct block *l = e.loc;
390: unsigned int h = hash(name);
391: register struct tbl *tp = NULL;
392: static struct tbl temp;
393:
394: if (strchr(name, '/') != NULL) {
395: tp = &temp;
396: tp->type = CEXEC;
397: tp->flag = 0; /* make ~ISSET */
398: goto Search;
399: }
400: for (l = e.loc; l != NULL; l = l->next) {
401: tp = tsearch(&l->funs, name, h);
402: if (tp != NULL && (tp->flag&DEFINED))
403: break;
404: }
405: if (tp == NULL)
406: tp = tsearch(&commands, name, h);
407: if (tp == NULL)
408: tp = tsearch(&builtins, name, h);
409: if (tp == NULL && insert) {
410: tp = tenter(&commands, name, h);
411: tp->type = CEXEC;
412: tp->flag = DEFINED;
413: }
414: Search:
415: if (tp->type == CEXEC && !(tp->flag&ISSET)) {
416: if (!flag[FHASHALL]) {
417: tp = &temp;
418: tp->type = CEXEC;
419: tp->flag = 0; /* make ~ISSET */
420: }
421: name = search(name, path, 1);
422: if (name != NULL) {
423: tp->val.s = strsave(name,
424: (tp == &temp) ? ATEMP : APERM);
425: tp->flag |= ISSET|ALLOC;
426: }
427: }
428: return tp;
429: }
430:
431: /*
432: * flush executable commands with relative paths
433: */
434: flushcom(all)
435: int all; /* just relative or all */
436: {
437: register struct tbl *tp;
438:
439: for (twalk(&commands); (tp = tnext()) != NULL; )
440: if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
441: if ((tp->flag&ALLOC))
442: afree(tp->val.s, commands.areap);
443: tp->flag = DEFINED; /* make ~ISSET */
444: }
445: }
446:
447: /*
448: * search for command with PATH
449: */
450: char *
451: search(name, path, mode)
452: char *name, *path;
453: int mode; /* 0: readable; 1: executable */
454: {
455: register int i;
456: register char *sp, *tp;
457: int colon = FALSE;
458:
459: if (strchr(name, '/'))
460: return (eaccess(name, mode) == 0) ? name : NULL;
461:
462: sp = path;
463: do {
464: tp = line;
465: colon = FALSE;
466: for (; *sp != '\0'; tp++) {
467: if ((*tp = *sp++) == ':') {
468: colon = TRUE;
469: break;
470: }
471: }
472: if (tp != line)
473: *tp++ = '/';
474: for (i = 0; (*tp++ = name[i++]) != '\0';)
475: ;
476: i = eaccess(line, mode);
477: if (i == 0)
478: return line;
479: /* what should we do about EACCES? */
480: } while (*sp != '\0' || colon);
481: return NULL;
482: }
483:
484: /*
485: * set up redirection, saving old fd's in e.savefd
486: */
487: static void
488: iosetup(iop)
489: register struct ioword *iop;
490: {
491: register int u = -1;
492: char *cp, *msg;
493: extern long lseek();
494:
495: if (iop->unit == 0 || iop->unit == 1 || iop->unit == 2)
496: e.interactive = 0;
497: e.savefd[iop->unit] = savefd(iop->unit);
498:
499: msg = iop->flag&(IOREAD|IOHERE)? "open": "create";
500: cp = iop->name;
501: if (!(iop->flag & IOHERE))
502: cp = evalstr(cp, DOTILDE);
503: if (iop->flag&IODUP)
504: iop->flag &= ~(IOREAD|IOWRITE); /* todo: lex.c */
505:
506: switch (iop->flag) {
507: case IOREAD:
508: u = open(cp, 0);
509: break;
510:
511: case IOHERE:
512: case IOHERE|IOXHERE:
513: u = herein(cp, iop->flag&IOXHERE);
514: /* cp may have wrong name */
515: break;
516:
517: case IOWRITE|IOCAT:
518: if ((u = open(cp, 1)) >= 0) {
519: (void) lseek(u, (long)0, 2);
520: break;
521: }
522: /* FALLTHROUGH */
523: case IOWRITE:
524: u = creat(cp, 0666);
525: break;
526:
527: case IODUP:
528: if (*cp == '-')
529: close(iop->unit);
530: else
531: if (digit(*cp))
532: u = *cp - '0';
533: else
534: errorf("%s: illegal >& argument\n", cp);
535: break;
536: }
537: if (u < 0)
538: errorf("%s: cannot %s\n", cp, msg);
539: if (u != iop->unit) {
540: (void) dup2(u, iop->unit);
541: if (iop->flag != IODUP)
542: close(u);
543: }
544:
545: fopenshf(iop->unit);
546: }
547:
548: /*
549: * open here document temp file.
550: * if unquoted here, expand here temp file into second temp file.
551: */
552: static int
553: herein(hname, sub)
554: char *hname;
555: int sub;
556: {
557: int fd;
558: FILE * Volatile f = NULL;
559:
560: f = fopen(hname, "r");
561: if (f == NULL)
562: return -1;
563: setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
564:
565: if (sub) {
566: char *cp;
567: struct source *s;
568: struct temp *h;
569:
570: newenv(E_ERRH);
571: if (setjmp(e.jbuf)) {
572: if (f != NULL)
573: fclose(f);
574: quitenv();
575: return -1; /* todo: error()? */
576: }
577:
578: /* set up yylex input from here file */
579: s = pushs(SFILE);
580: s->u.file = f;
581: source = s;
582: if (yylex(ONEWORD) != LWORD)
583: errorf("exec:herein error\n");
584: cp = evalstr(yylval.cp, 0);
585:
586: /* write expanded input to another temp file */
587: h = maketemp(ATEMP);
588: h->next = e.temps; e.temps = h;
589: if (h == NULL)
590: error();
591: f = fopen(h->name, "w+");
592: if (f == NULL)
593: error();
594: setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
595: fputs(cp, f);
596: rewind(f);
597:
598: quitenv();
599: }
600: fd = dup(fileno(f));
601: fclose(f);
602: return fd;
603: }
604:
605: static void
606: echo(vp, ap)
607: register char **vp, **ap;
608: {
609: shellf("+");
610: while (*vp != NULL)
611: shellf(" %s", *vp++);
612: while (*ap != NULL)
613: shellf(" %s", *ap++);
614: shellf("\n");
615: }
616:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.