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