|
|
1.1 ! root 1: /* ! 2: * built-in Bourne commands ! 3: */ ! 4: ! 5: static char *RCSid = "$Header: c_sh.c,v 3.1 88/11/03 09:14:31 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 <sys/times.h> ! 15: #include <unistd.h> /* getcwd */ ! 16: #include "sh.h" ! 17: #include "lex.h" ! 18: #include "tree.h" ! 19: #include "table.h" ! 20: ! 21: static void putvlist(); ! 22: static char *clocktos(); ! 23: ! 24: int ! 25: c_label(wp) ! 26: char **wp; ! 27: { ! 28: return 0; ! 29: } ! 30: ! 31: /* todo: add symlink hacks */ ! 32: int ! 33: c_cd(wp) ! 34: register char **wp; ! 35: { ! 36: static char path[PATH]; ! 37: register char *cp; ! 38: register struct tbl *vp; ! 39: ! 40: if ((cp = wp[1]) == NULL && (cp = strval(global("HOME"))) == NULL) ! 41: errorf("no home directory"); ! 42: if (strcmp(cp, "-") == 0) { ! 43: cp = strval(global("OLDPWD")); ! 44: shellf("%s\n", cp); ! 45: } ! 46: if (chdir(cp) < 0) ! 47: errorf("%s: bad directory\n", cp); ! 48: flushcom(0); ! 49: ! 50: /* maintain $PWD and $OLDPWD */ ! 51: vp = global("PWD"); ! 52: cp = strval(vp); ! 53: if (cp != null) ! 54: setstr(global("OLDPWD"), cp); ! 55: cp = getcwd(path, (size_t)PATH); ! 56: if (cp == NULL) ! 57: unset(vp); ! 58: else ! 59: setstr(vp, cp); ! 60: ! 61: return 0; ! 62: } ! 63: ! 64: int ! 65: c_shift(wp) ! 66: register char **wp; ! 67: { ! 68: register struct block *l = e.loc; ! 69: register int n; ! 70: ! 71: n = wp[1] ? evaluate(wp[1]) : 1; ! 72: if (l->argc < n) { ! 73: errorf("nothing to shift\n"); ! 74: return (1); ! 75: } ! 76: l->argv[n] = l->argv[0]; ! 77: l->argv += n; ! 78: l->argc -= n; ! 79: return 0; ! 80: } ! 81: ! 82: int ! 83: c_umask(wp) ! 84: register char **wp; ! 85: { ! 86: register int i; ! 87: register char *cp; ! 88: ! 89: if ((cp = wp[1]) == NULL) { ! 90: i = umask(0); ! 91: umask(i); ! 92: printf("%03o\n", i); /* should this be shell output? */ ! 93: } else { ! 94: for (i = 0; *cp>='0' && *cp<='7'; cp++) ! 95: i = i*8 + (*cp-'0'); ! 96: umask(i); ! 97: } ! 98: return 0; ! 99: } ! 100: ! 101: int ! 102: c_dot(wp) ! 103: char **wp; ! 104: { ! 105: char *file, *cp; ! 106: ! 107: if ((cp = wp[1]) == NULL) ! 108: return 0; ! 109: file = search(cp, path, 0); ! 110: if (file == NULL) ! 111: errorf("%s: not found\n", cp); ! 112: if (include(file)) ! 113: return exstat; ! 114: return -1; ! 115: } ! 116: ! 117: int ! 118: c_wait(wp) ! 119: char **wp; ! 120: { ! 121: register char *cp; ! 122: ! 123: wp++; ! 124: cp = *wp; ! 125: if (cp == NULL) ! 126: cp = "%"; ! 127: /* todo: print status ? */ ! 128: return waitfor(j_lookup(cp)); ! 129: } ! 130: ! 131: int ! 132: c_read(wp) ! 133: register char **wp; ! 134: { ! 135: register int c = 0; ! 136: FILE *f = stdin; ! 137: int expand = 1; ! 138: register char *cp; ! 139: ! 140: for (wp++; (cp = *wp) != NULL && *cp++ == '-'; wp++) { ! 141: while (*cp) switch (*cp++) { ! 142: case 'e': ! 143: expand = 1; ! 144: break; ! 145: case 'r': ! 146: expand = 0; ! 147: break; ! 148: case 'u': ! 149: if (!digit(*cp) || (f = shf[*cp++-'0']) == NULL) ! 150: errorf("bad -u argument\n"); ! 151: break; ! 152: } ! 153: } ! 154: ! 155: if (*wp == NULL) ! 156: errorf("missing name\n"); ! 157: if ((cp = strchr(*wp, '?')) != NULL) { ! 158: *cp = 0; ! 159: if (flag[FTALKING]) { ! 160: shellf("%s ", cp+1); ! 161: fflush(shlout); ! 162: } ! 163: } ! 164: ! 165: for (; *wp != NULL; wp++) { ! 166: for (cp = line; cp <= line+LINE; ) { ! 167: if (c == '\n') ! 168: break; ! 169: c = getc(f); ! 170: if (c == EOF) ! 171: return 1; ! 172: if (expand && c == '\\') { ! 173: c = getc(f); ! 174: if (c == '\n') ! 175: c = 0; ! 176: else ! 177: *cp++ = c; ! 178: continue; ! 179: } ! 180: if (c == '\n' || wp[1] && ctype(c, C_IFS)) ! 181: break; ! 182: *cp++ = c; ! 183: } ! 184: *cp = 0; ! 185: setstr(global(*wp), line); ! 186: } ! 187: return 0; ! 188: } ! 189: ! 190: int ! 191: c_eval(wp) ! 192: register char **wp; ! 193: { ! 194: register struct source *s; ! 195: ! 196: s = pushs(SWORDS); ! 197: s->u.strv = wp+1; ! 198: return shell(s); ! 199: } ! 200: ! 201: void setsig ARGS((struct trap *p, handler_t f)); ! 202: ! 203: int ! 204: c_trap(wp) ! 205: register char **wp; ! 206: { ! 207: int i; ! 208: char *s; ! 209: register struct trap *p; ! 210: ! 211: wp++; ! 212: if (*wp == NULL) { ! 213: for (p = sigtraps, i = SIGNALS; --i >= 0; p++) { ! 214: if (p->trap != NULL) ! 215: shellf("%s: %s\n", p->name, p->trap); ! 216: } ! 217: return 0; ! 218: } ! 219: ! 220: s = (gettrap(*wp) == NULL) ? *wp++ : NULL; /* get command */ ! 221: if (s != NULL && s[0] == '-' && s[1] == '\0') ! 222: s = NULL; ! 223: ! 224: /* set/clear traps */ ! 225: while (*wp != NULL) { ! 226: p = gettrap(*wp++); ! 227: if (p == NULL) ! 228: errorf("trap: bad signal %s\n", wp[-1]); ! 229: if (p->trap != NULL) ! 230: afree((Void*)p->trap, APERM); ! 231: p->trap = NULL; ! 232: if (s != NULL) { ! 233: if (strlen(s) != 0) { ! 234: p->trap = strsave(s, APERM); ! 235: setsig(p, trapsig); ! 236: } else ! 237: setsig(p, (handler_t)SIG_IGN); ! 238: } else ! 239: /* todo: restore to orginal value */ ! 240: setsig(p, ! 241: (p->signal==SIGINT || p->signal==SIGQUIT) && flag[FTALKING] ! 242: ? (handler_t)SIG_IGN : (handler_t)SIG_DFL); ! 243: } ! 244: return 0; ! 245: } ! 246: ! 247: void ! 248: setsig(p, f) ! 249: register struct trap *p; ! 250: void (*f)(); ! 251: { ! 252: if (p->signal == 0) ! 253: return; ! 254: if (signal(p->signal, SIG_IGN) != SIG_IGN || p->ourtrap) { ! 255: p->ourtrap = 1; ! 256: signal(p->signal, f); ! 257: } ! 258: } ! 259: ! 260: int ! 261: c_return(wp) ! 262: char **wp; ! 263: { ! 264: wp++; ! 265: if (*wp != NULL) ! 266: exstat = getn(*wp); ! 267: quitenv(); /* pop E_TCOM */ ! 268: while (e.type == E_LOOP || e.type == E_EXEC) ! 269: quitenv(); ! 270: if (e.type == E_FUNC) ! 271: longjmp(e.jbuf, 1); ! 272: leave(exstat); ! 273: } ! 274: ! 275: int ! 276: c_brkcont(wp) ! 277: register char **wp; ! 278: { ! 279: int quit; ! 280: ! 281: quit = wp[1] == NULL ? 1 : getn(wp[1]); ! 282: quitenv(); /* pop E_TCOM */ ! 283: while (e.type == E_LOOP || e.type == E_EXEC) { ! 284: if (e.type == E_LOOP && --quit <= 0) ! 285: longjmp(e.jbuf, (*wp[0] == 'b') ? LBREAK : LCONTIN); ! 286: quitenv(); ! 287: } ! 288: errorf("cannot %s\n", wp[0]); ! 289: } ! 290: ! 291: int ! 292: c_exit(wp) ! 293: char **wp; ! 294: { ! 295: register char *cp; ! 296: ! 297: e.oenv = NULL; ! 298: if ((cp = wp[1]) != NULL) ! 299: exstat = getn(cp); ! 300: #if JOBS ! 301: if (flag[FMONITOR] && j_stopped()) /* todo: only once */ ! 302: errorf("There are stopped jobs\n"); ! 303: #endif ! 304: leave(exstat); ! 305: } ! 306: ! 307: int ! 308: c_exro(wp) ! 309: register char **wp; ! 310: { ! 311: int flag = (**wp == 'e') ? EXPORT : RDONLY; ! 312: ! 313: if (*++wp != NULL) { ! 314: for (; *wp != NULL; wp++) ! 315: if (typeset(*wp, flag, 0) == NULL) ! 316: errorf("%s: bad identifier\n", *wp); ! 317: } else ! 318: putvlist(flag); ! 319: return 0; ! 320: } ! 321: ! 322: static void ! 323: putvlist(flag) ! 324: register int flag; ! 325: { ! 326: struct block *l = e.loc; ! 327: register struct tbl *vp, **p; ! 328: ! 329: flag |= ISSET; ! 330: for (l = e.loc; l != NULL; l = l->next) ! 331: for (p = tsort(&l->vars); (vp = *p++) != NULL; ) ! 332: if ((vp->flag&flag) == flag) { ! 333: if (vp->flag & EXPORT) ! 334: printf("export "); ! 335: if (vp->flag & RDONLY) ! 336: printf("readonly "); ! 337: printf("%s\n", vp->name); ! 338: } ! 339: } ! 340: ! 341: int ! 342: c_set(wp) ! 343: register char **wp; ! 344: { ! 345: struct block *l = e.loc; ! 346: register struct tbl *vp, **p; ! 347: register char **owp = wp; ! 348: register char *cp; ! 349: int old_fmonitor = flag[FMONITOR]; ! 350: ! 351: if ((cp = *++wp) == NULL) { ! 352: static char * Const args [] = {"set", "-", NULL}; ! 353: extern int c_typeset ARGS((char **args)); ! 354: return c_typeset(args); ! 355: } ! 356: ! 357: for (; (cp = *wp) != NULL && (*cp == '-' || *cp == '+');) { ! 358: int i, n = *cp++ == '-'; /* set or clear flag */ ! 359: wp++; ! 360: if (*cp == '\0') { ! 361: if (n) ! 362: flag[FXTRACE] = flag[FVERBOSE] = 0; ! 363: break; ! 364: } ! 365: if (*cp == '-') ! 366: goto setargs; ! 367: for (; *cp != '\0'; cp++) ! 368: if (*cp == 'o') { ! 369: if (*wp == NULL) { ! 370: printoptions(); ! 371: return 0; ! 372: } ! 373: i = option(*wp++); ! 374: if (i == 0) ! 375: shellf("%s: unknown option\n", *--wp); ! 376: flag[i] = n; ! 377: } else if (*cp>='a' && *cp<='z') ! 378: flag[FLAG(*cp)] = n; ! 379: else ! 380: errorf("%c: bad flag\n", *cp); ! 381: if (flag[FTALKING]) ! 382: flag[FERREXIT] = 0; ! 383: } ! 384: ! 385: #if JOBS ! 386: if (old_fmonitor != flag[FMONITOR]) ! 387: j_change(); ! 388: #endif ! 389: ! 390: /* set $# and $* */ ! 391: if (*wp != NULL) { ! 392: setargs: ! 393: owp = --wp; ! 394: wp[0] = l->argv[0]; /* save $0 */ ! 395: while (*++wp != NULL) ! 396: *wp = strsave(*wp, &l->area); ! 397: l->argc = wp - owp - 1; ! 398: l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area); ! 399: for (wp = l->argv; (*wp++ = *owp++) != NULL; ) ! 400: ; ! 401: resetopts(); ! 402: } ! 403: return 0; ! 404: } ! 405: ! 406: int ! 407: c_unset(wp) ! 408: register char **wp; ! 409: { ! 410: register char *id; ! 411: int flagf = 0; ! 412: ! 413: for (wp++; (id = *wp) != NULL && *id == '-'; wp++) ! 414: if (*++id == 'f') ! 415: flagf++; ! 416: for (; (id = *wp) != NULL; wp++) ! 417: if (!flagf) { /* unset variable */ ! 418: unset(local(id)); ! 419: } else { /* unset function */ ! 420: register struct tbl *tp; ! 421: tp = tsearch(&e.loc->funs, id, hash(id)); ! 422: if (tp != NULL) ! 423: define(tp, (struct op *)NULL); ! 424: } ! 425: return 0; ! 426: } ! 427: ! 428: int ! 429: c_ulimit(wp) ! 430: register char **wp; ! 431: { ! 432: extern int do_ulimit(); ! 433: ! 434: return do_ulimit(wp[1], wp[2]); ! 435: } ! 436: ! 437: int ! 438: c_times(wp) ! 439: char **wp; ! 440: { ! 441: struct tms all; ! 442: ! 443: (void) times(&all); ! 444: printf("Shell: "); ! 445: printf("%8s user ", clocktos(all.tms_utime)); ! 446: printf("%8s system\n", clocktos(all.tms_stime)); ! 447: printf("Kids: "); ! 448: printf("%8s user ", clocktos(all.tms_cutime)); ! 449: printf("%8s system\n", clocktos(all.tms_cstime)); ! 450: ! 451: return 0; ! 452: } ! 453: ! 454: /* ! 455: * time pipeline (really a statement, not a built-in comman) ! 456: */ ! 457: int ! 458: timex(t, f) ! 459: struct op *t; ! 460: int f; ! 461: { ! 462: int rv; ! 463: struct tms t0, t1; ! 464: clock_t t0t, t1t, time(); ! 465: extern clock_t j_utime, j_stime; /* computed by j_wait */ ! 466: ! 467: j_utime = j_stime = 0; ! 468: #if COHERENT ! 469: t0t = time((clock_t)NULL); ! 470: (void)times(&t0); ! 471: #else ! 472: t0t = times(&t0); ! 473: #endif ! 474: rv = execute(t->left, f); ! 475: #if COHERENT ! 476: t1t = time((clock_t)NULL); ! 477: (void)times(&t1); ! 478: #else ! 479: t1t = times(&t1); ! 480: #endif ! 481: shellf("%8s real ", clocktos((t1t - t0t) * 100)); ! 482: shellf("%8s user ", ! 483: clocktos(t1.tms_utime - t0.tms_utime + j_utime)); ! 484: shellf("%8s system ", ! 485: clocktos(t1.tms_stime - t0.tms_stime + j_stime)); ! 486: shellf("\n"); ! 487: ! 488: return rv; ! 489: } ! 490: ! 491: static char * ! 492: clocktos(t) ! 493: clock_t t; ! 494: { ! 495: static char temp[20]; ! 496: register int i; ! 497: register char *cp = temp + sizeof(temp); ! 498: ! 499: #if !COHERENT ! 500: #if CLK_TCK != 100 /* convert to 1/100'ths */ ! 501: t = (t < 1000000000/CLK_TCK) ? ! 502: (t * 100) / CLK_TCK : (t / CLK_TCK) * 100; ! 503: #endif ! 504: #endif ! 505: *--cp = '\0'; ! 506: *--cp = 's'; ! 507: for (i = -2; i <= 0 || t > 0; i++) { ! 508: if (i == 0) ! 509: *--cp = '.'; ! 510: *--cp = '0' + (char)(t%10); ! 511: t /= 10; ! 512: } ! 513: return cp; ! 514: } ! 515: ! 516: /* dummy function, special case in comexec() */ ! 517: int ! 518: c_exec(wp) ! 519: char ** wp; ! 520: { ! 521: return 0; ! 522: } ! 523: ! 524: /* dummy function, special case in comexec() */ ! 525: int ! 526: c_builtin(wp) ! 527: char ** wp; ! 528: { ! 529: return 0; ! 530: } ! 531: ! 532: extern int c_test(); /* in test.c */ ! 533: ! 534: Const struct builtin shbuiltins [] = { ! 535: {"=:", c_label}, ! 536: {"=.", c_dot}, ! 537: {"[", c_test}, ! 538: {"=cd", c_cd}, ! 539: {"builtin", c_builtin}, ! 540: {"=exec", c_exec}, ! 541: {"=shift", c_shift}, ! 542: {"wait", c_wait}, ! 543: {"read", c_read}, ! 544: {"=eval", c_eval}, ! 545: {"trap", c_trap}, ! 546: {"break", c_brkcont}, ! 547: {"continue", c_brkcont}, ! 548: {"exit", c_exit}, ! 549: {"=export", c_exro}, ! 550: {"=readonly", c_exro}, ! 551: {"=return", c_return}, ! 552: {"=set", c_set}, ! 553: {"=unset", c_unset}, ! 554: {"umask", c_umask}, ! 555: {"test", c_test}, ! 556: {"times", c_times}, ! 557: {"ulimit", c_ulimit}, ! 558: {NULL, NULL} ! 559: }; ! 560:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.