|
|
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.