|
|
1.1 ! root 1: /* ! 2: * sh/exec3.c ! 3: * Bourne shell. ! 4: * Builtin commands. ! 5: */ ! 6: ! 7: #include "sh.h" ! 8: #include <sys/times.h> ! 9: #include <sys/const.h> /* HZ defined here */ ! 10: ! 11: #define HOUR (60L*60L*HZ) ! 12: #define MINUTE (60L*HZ) ! 13: #define SECOND HZ ! 14: ! 15: char *cd(); ! 16: ! 17: extern s_colon(); ! 18: extern s_dot(); ! 19: extern s_break(); ! 20: #define s_continue s_break ! 21: extern s_cd(); ! 22: extern s_dirs(); ! 23: extern s_eval(); ! 24: extern s_exec(); ! 25: extern s_exit(); ! 26: extern s_export(); ! 27: extern s_login(); ! 28: #define s_newgrp s_login ! 29: extern s_popd(); ! 30: extern s_pushd(); ! 31: extern s_read(); ! 32: #define s_readonly s_export ! 33: extern s_set(); ! 34: extern s_shift(); ! 35: extern s_times(); ! 36: extern s_trap(); ! 37: extern s_umask(); ! 38: extern s_wait(); ! 39: #define SNULL ((int (*)())0) ! 40: ! 41: typedef struct { ! 42: int i_hash; ! 43: char *i_name; ! 44: int (*i_func)(); ! 45: } INLINE; ! 46: ! 47: INLINE inls[] = { ! 48: 0, ":", s_colon, ! 49: 0, ".", s_dot, ! 50: 0, "break", s_break, ! 51: 0, "continue", s_continue, ! 52: 0, "cd", s_cd, ! 53: 0, "dirs", s_dirs, ! 54: 0, "eval", s_eval, ! 55: 0, "exec", s_exec, ! 56: 0, "exit", s_exit, ! 57: 0, "export", s_export, ! 58: 0, "login", s_login, ! 59: 0, "newgrp", s_newgrp, ! 60: 0, "popd", s_popd, ! 61: 0, "pushd", s_pushd, ! 62: 0, "read", s_read, ! 63: 0, "readonly", s_readonly, ! 64: 0, "set", s_set, ! 65: 0, "shift", s_shift, ! 66: 0, "times", s_times, ! 67: 0, "trap", s_trap, ! 68: 0, "umask", s_umask, ! 69: 0, "wait", s_wait, ! 70: 0, NULL, SNULL ! 71: }; ! 72: ! 73: inline() ! 74: { ! 75: register int (*s_func)(); ! 76: register INLINE *ip; ! 77: register int ahash; ! 78: int pid, status; ! 79: ! 80: if (inls[0].i_hash==0) ! 81: for (ip=inls; ip->i_name!=NULL; ip++) ! 82: ip->i_hash = ihash(ip->i_name); ! 83: if (nargv[0] == NULL) ! 84: return 0; ! 85: ahash = ihash(nargv[0]); ! 86: for (ip=inls; ip->i_name!=NULL; ip++) ! 87: if (ip->i_hash==ahash && strcmp(nargv[0], ip->i_name)==0) ! 88: break; ! 89: if ((s_func=ip->i_func) == SNULL) ! 90: return 0; ! 91: if (*niovp != NULL && s_func != s_exec) { ! 92: /* Redirection with built-in command. */ ! 93: /* Allowed only with eval, export, readonly, set, times. */ ! 94: if (s_func != s_eval ! 95: && s_func != s_export ! 96: && s_func != s_set ! 97: && s_func != s_times) { ! 98: eredir(); ! 99: slret = 1; ! 100: return 1; ! 101: } ! 102: if ((pid = clone()) == 0) { ! 103: /* Perform redirection in child process. */ ! 104: if (redirect(niovp) < 0) ! 105: slret = 1; ! 106: else if (s_func == s_eval) ! 107: slret = (*s_func)(); ! 108: else { ! 109: /* Kludge stderr output to stdout. */ ! 110: dup2(1, 2); ! 111: close(1); ! 112: slret = (*s_func)(); ! 113: } ! 114: exit(slret); ! 115: /* NOTREACHED */ ! 116: } else { ! 117: /* Parent waits for child and takes its exit status. */ ! 118: while (wait(&status) != pid) ! 119: ; ! 120: slret = status >> 8; ! 121: } ! 122: } else ! 123: slret = (*s_func)(); ! 124: return 1; ! 125: } ! 126: ! 127: ihash(cp) ! 128: register char *cp; ! 129: { ! 130: register int i; ! 131: for (i=0; *cp; i+=*cp++); ! 132: return i; ! 133: } ! 134: ! 135: /* ! 136: * Actual builtin functions. ! 137: */ ! 138: s_colon() ! 139: { ! 140: return 0; ! 141: } ! 142: ! 143: s_dot() ! 144: { ! 145: if (nargc==2) { ! 146: ffind(NULL); ! 147: if (ffind(vpath, nargv[1], 4)) ! 148: return session(SFILE, duplstr(strt, 0)); ! 149: else { ! 150: ecantfind(nargv[1]); ! 151: return 1; ! 152: } ! 153: } else if (nargc==1) ! 154: return 0; ! 155: syntax(); ! 156: return 1; ! 157: } ! 158: ! 159: s_break() ! 160: { ! 161: register CON *cp; ! 162: register int t; ! 163: register int n; ! 164: int ret; ! 165: ! 166: ret = nargv[0][0]=='b' ? 2 : 1; ! 167: n = nargc>1 ? atoi(nargv[1]) : 1; ! 168: for (cp = sesp->s_con; cp; cp = cp->c_next) { ! 169: t = cp->c_node->n_type; ! 170: if ((t==NWHILE || t==NFOR || t==NUNTIL) && --n == 0) { ! 171: sesp->s_con = cp; ! 172: longjmp(cp->c_envl, ret); ! 173: break; ! 174: } ! 175: freebuf(cp->c_bpp); ! 176: } ! 177: printe("%s out of bounds", ret==1 ? "Continue" : "Break"); ! 178: } ! 179: ! 180: /* s_continue is overlaid with s_break */ ! 181: ! 182: s_cd() ! 183: { ! 184: register char *dir; ! 185: ! 186: if ((dir = cd((nargc<2) ? vhome : nargv[1])) == NULL) ! 187: return -1; /* cd failed */ ! 188: if (dstack[dstkp] != NULL) ! 189: sfree(dstack[dstkp]); ! 190: dstack[dstkp] = duplstr(dir, 1); /* update dir stack */ ! 191: return 0; ! 192: } ! 193: ! 194: s_dirs() ! 195: { ! 196: register int i; ! 197: ! 198: for (i = dstkp; i >= 0; i--) ! 199: fprintf(stderr, "%s ", dstack[i]); ! 200: fputc('\n', stderr); ! 201: } ! 202: ! 203: s_eval() ! 204: { ! 205: if (nargc>1) ! 206: return session(SARGV, ++nargv); ! 207: else ! 208: return 0; ! 209: } ! 210: ! 211: s_exec() ! 212: { ! 213: if (redirect(niovp) < 0) { ! 214: if (nargc>1) { ! 215: exit(1); ! 216: NOTREACHED; ! 217: } ! 218: return 1; ! 219: } ! 220: if (nargc==1) ! 221: return 0; ! 222: if (no1flag) ! 223: cleanup(2, NULL); ! 224: dflttrp(ICMD); ! 225: ++nargv; ! 226: --nargc; ! 227: nenvp = envlvar(nenvp); ! 228: flexec(); ! 229: exit(1); ! 230: NOTREACHED; ! 231: } ! 232: ! 233: s_exit() ! 234: { ! 235: if (nargc > 1) ! 236: slret = atoi(nargv[1]); ! 237: reset(RUEXITS); ! 238: NOTREACHED; ! 239: } ! 240: ! 241: s_export() ! 242: { ! 243: register int flag; ! 244: register char **varv; ! 245: ! 246: flag = nargv[0][0]=='e' ? VEXP : VRDO; ! 247: if (nargc < 2) ! 248: tellvar(flag); ! 249: else ! 250: for (varv=++nargv; *varv; ) ! 251: if (namevar(*varv)) ! 252: flagvar(*varv++, flag); ! 253: else ! 254: eillvar(*varv++); ! 255: return 0; ! 256: } ! 257: ! 258: s_login() ! 259: { ! 260: register char *cmd; ! 261: ! 262: cmd = nargv[0][0]=='l' ? "/bin/login" : "/bin/newgrp"; ! 263: execve(cmd, nargv, envlvar(nenvp)); ! 264: ecantfind(cmd); ! 265: return 1; ! 266: } ! 267: ! 268: /* s_newgrp is overlaid with s_login */ ! 269: ! 270: s_popd() ! 271: { ! 272: register int i, j, n, ret; ! 273: ! 274: if (nargc == 1) ! 275: return popd(); ! 276: /* ! 277: * Kludge to pop one or more specific dir stack elements. ! 278: * Do args backwards so e.g. "popd 2 3 4" works as expected. ! 279: * Internal indices [0, dstkp] are user indices [dstkp, 0]. ! 280: */ ! 281: for (ret = 0, i = nargc-1; i > 0; i--) { ! 282: if ((n = atoi(nargv[i])) == 0) ! 283: ret |= popd(); ! 284: else if (n < 0 || n > dstkp) { ! 285: printe("Illegal arg: %d", n); ! 286: ret = -1; ! 287: continue; ! 288: } else { ! 289: j = dstkp - n; ! 290: if (dstack[j] != NULL) ! 291: sfree(dstack[j]); ! 292: for ( ; j < dstkp; j++) ! 293: dstack[j] = dstack[j+1]; ! 294: --dstkp; ! 295: } ! 296: } ! 297: return ret; ! 298: } ! 299: ! 300: s_pushd() ! 301: { ! 302: register char *dir; ! 303: register int i, ret; ! 304: ! 305: if (nargc == 1) { ! 306: /* Exchange top two stack elements. */ ! 307: if (dstkp == 0) ! 308: return 1; /* only one element on stack */ ! 309: dir = dstack[dstkp-1]; ! 310: dstack[dstkp-1] = dstack[dstkp]; ! 311: dstack[dstkp] = dir; /* exchange top two */ ! 312: return ((cd(dir) == NULL) ? -1 : 0); /* and cd accordingly */ ! 313: } ! 314: /* Push one or more directories to stack. */ ! 315: for (ret = 0, i = 1; i < nargc; i++) ! 316: ret |= pushd(nargv[i]); ! 317: return ret; ! 318: } ! 319: ! 320: s_read() ! 321: { ! 322: SES s; ! 323: register int n, c; ! 324: register char **vp; ! 325: int eol; ! 326: ! 327: s.s_type = SSTR; ! 328: s.s_flag = 0; ! 329: s.s_ifp = stdin; ! 330: s.s_next = sesp; ! 331: sesp = &s; ! 332: for (eol=0, vp=++nargv, n=--nargc; n; n-=1, vp+=1) { ! 333: if (n==1 && ! eol) { ! 334: strp = strt; ! 335: c = collect('\n', 2); ! 336: if (c == '\n') ! 337: --strp; ! 338: *strp = '\0'; ! 339: } else if (! eol) { ! 340: readflag = 1; ! 341: c = yylex(); ! 342: readflag = 0; ! 343: } else ! 344: *strt = '\0'; ! 345: if (namevar(*vp)) ! 346: assnvar(*vp, duplstr(strt, 0)); ! 347: else ! 348: eillvar(*vp); ! 349: eol = c=='\n' || c==EOF; ! 350: } ! 351: sesp = s.s_next; ! 352: return c==EOF; ! 353: } ! 354: ! 355: /* s_readonly overlaid with s_export */ ! 356: ! 357: s_set() ! 358: { ! 359: if (nargc < 2) { ! 360: tellvar(0); ! 361: return 0; ! 362: } ! 363: return set(nargc, nargv, 0); ! 364: } ! 365: ! 366: s_shift() ! 367: { ! 368: register int n; ! 369: ! 370: n = nargc > 1 ? atoi(nargv[1]) : 1; ! 371: while (n > 0 && sargc > 0) { ! 372: n -= 1; ! 373: sargc -= 1; ! 374: sargp += 1; ! 375: } ! 376: return n!=0; ! 377: } ! 378: ! 379: s_times() ! 380: { ! 381: #if _I386 ! 382: #define tb_cutime tms_cutime ! 383: #define tb_cstime tms_cstime ! 384: struct tms tb; ! 385: #else ! 386: struct tbuffer tb; ! 387: ! 388: #endif ! 389: ! 390: times(&tb); ! 391: ptime(tb.tb_cutime); ! 392: ptime(tb.tb_cstime); ! 393: prints("\n"); ! 394: return 0; ! 395: } ! 396: ! 397: s_trap() ! 398: { ! 399: register char **vp; ! 400: register char *cp; ! 401: register int err; ! 402: ! 403: err = 0; ! 404: if (nargc==1) ! 405: return telltrp(); ! 406: vp = ++nargv; ! 407: cp = *vp; ! 408: if (class(cp[0], MDIGI) ! 409: && (cp[1]=='\0' || (class(cp[1], MDIGI) && cp[2]=='\0'))) ! 410: cp = NULL; ! 411: else ! 412: ++vp; ! 413: while (*vp) { ! 414: if (class(vp[0][0], MDIGI)) ! 415: err |= setstrp(atoi(*vp++), cp); ! 416: else { ! 417: printe("Bad trap: %s", *vp++); ! 418: err |= 1; ! 419: } ! 420: } ! 421: return err; ! 422: } ! 423: ! 424: s_umask() ! 425: { ! 426: if (nargc < 2) ! 427: prints("%03o\n", ufmask); ! 428: else ! 429: umask(ufmask = atoi(nargv[1])); ! 430: return 0; ! 431: } ! 432: ! 433: s_wait() ! 434: { ! 435: register int f; ! 436: ! 437: f = (nargc > 1) ? atoi(nargv[1]) : 0; ! 438: if (f > 0) ! 439: f = -f; ! 440: waitc(f); ! 441: return slret; ! 442: } ! 443: ! 444: /* ! 445: * Change to given directory. ! 446: * Update global variable CWD accordingly. ! 447: * Return NULL if bad, otherwise full pathname of the directory. ! 448: */ ! 449: char * ! 450: cd(dir) register char *dir; ! 451: { ! 452: if (chdir(dir) < 0) { ! 453: printe("%s: bad directory", dir); ! 454: return NULL; ! 455: } ! 456: if (*dir != '/') { ! 457: /* ! 458: * Find an absolute pathname for the dstack and $CWD. ! 459: * The directory now in dstack[dstkp] is "." if _getwd() failed ! 460: * for any reason (e.g., the user lacks search permission ! 461: * down the path to "/", or "." was rm'ed by another process). ! 462: * Avoid _getwd() in this case, it can undo the chdir() above. ! 463: */ ! 464: if ((strcmp(dstack[dstkp], ".") == 0) ! 465: || ((dir = _getwd()) == NULL)) ! 466: return NULL; ! 467: } ! 468: assnvar("CWD", dir); ! 469: return dir; ! 470: } ! 471: ! 472: /* ! 473: * Pop the directory stack and change to the previous stacked directory. ! 474: */ ! 475: popd() ! 476: { ! 477: if (dstkp == 0) { ! 478: printe("Directory stack underflow"); ! 479: return -1; ! 480: } ! 481: if (dstack[dstkp] != NULL) ! 482: sfree(dstack[dstkp]); ! 483: return (cd(dstack[--dstkp]) == NULL ? -1 : 0); ! 484: } ! 485: ! 486: /* ! 487: * Change to given directory and add it to the directory stack. ! 488: */ ! 489: pushd(dir) register char *dir; ! 490: { ! 491: if ((dir = cd(dir)) == NULL) ! 492: return -1; /* cd failed */ ! 493: if (++dstkp >= DSTACKN) { ! 494: --dstkp; ! 495: printe("Directory stack overflow"); ! 496: return -1; ! 497: } ! 498: dstack[dstkp] = duplstr(dir, 1); ! 499: return 0; ! 500: } ! 501: ! 502: /* ! 503: * The set command. This is also called from `main' to set ! 504: * options from the command line. In this case `flag' is ! 505: * set. ! 506: */ ! 507: set(argc, argv, flag) ! 508: register char *argv[]; ! 509: { ! 510: int n; ! 511: register char *cp; ! 512: ! 513: if (flag) { ! 514: cflag = 0; ! 515: iflag = 0; ! 516: sflag = 0; ! 517: } ! 518: n = 0; ! 519: if (argc > 0) ! 520: n = 1; ! 521: if (argc>1 && argv[1][0]=='-') { ! 522: register char *fp; ! 523: ! 524: n++; ! 525: for (cp = &argv[1][1]; *cp; cp++) { ! 526: if ((fp=index(shfnams, *cp)) == NULL ! 527: || (fp+=shflags-shfnams) == NULL ! 528: || (fp != &lgnflag && fp > &xflag && flag == 0)) ! 529: printe("-%c: Bad option", *cp); ! 530: else if (fp != &lgnflag) ! 531: *fp = *cp; ! 532: } ! 533: if (cp == &argv[1][1]) { ! 534: vflag = 0; ! 535: xflag = 0; ! 536: } ! 537: if (flag == 0 && argc == 2) ! 538: return errflag; ! 539: } ! 540: if (errflag) ! 541: return 1; ! 542: if (sargv != NULL) ! 543: vfree(sargv); ! 544: sargv = vdupl(argv); ! 545: sargc = argc - n; ! 546: sargp = sargv + n; ! 547: return 0; ! 548: } ! 549: ! 550: /* ! 551: * print the time as XmX.Xs ! 552: * as fixed by Randall. ! 553: */ ! 554: ptime(t) ! 555: long t; ! 556: { ! 557: register int ticks, tenths, seconds; ! 558: ! 559: prints("%Dm", t/MINUTE); ! 560: ticks = t%MINUTE; ! 561: seconds = ticks/SECOND; ! 562: tenths = (ticks%SECOND + SECOND/20)/(SECOND/10); ! 563: if (tenths == 10) { ! 564: tenths = 0; ! 565: seconds++; ! 566: } ! 567: prints("%d.%ds ", seconds, tenths); ! 568: } ! 569: ! 570: /* end of sh/exec3.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.