1 /* $OpenBSD: c_sh.c,v 1.3 1996/10/13 21:32:18 downsj Exp $ */ 2 3 /* 4 * built-in Bourne commands 5 */ 6 7 #include "sh.h" 8 #include "ksh_stat.h" /* umask() */ 9 #include "ksh_time.h" 10 #include "ksh_times.h" 11 12 static char *clocktos ARGS((clock_t t)); 13 14 /* :, false and true */ 15 int 16 c_label(wp) 17 char **wp; 18 { 19 return wp[0][0] == 'f' ? 1 : 0; 20 } 21 22 int 23 c_shift(wp) 24 char **wp; 25 { 26 register struct block *l = e->loc; 27 register int n; 28 long val; 29 char *arg; 30 31 if (ksh_getopt(wp, &builtin_opt, null) == '?') 32 return 1; 33 arg = wp[builtin_opt.optind]; 34 35 if (arg) { 36 evaluate(arg, &val, FALSE); 37 n = val; 38 } else 39 n = 1; 40 if (n < 0) { 41 bi_errorf("%s: bad number", arg); 42 return (1); 43 } 44 if (l->argc < n) { 45 bi_errorf("nothing to shift"); 46 return (1); 47 } 48 l->argv[n] = l->argv[0]; 49 l->argv += n; 50 l->argc -= n; 51 return 0; 52 } 53 54 int 55 c_umask(wp) 56 char **wp; 57 { 58 register int i; 59 register char *cp; 60 int symbolic = 0; 61 int old_umask; 62 int optc; 63 64 while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF) 65 switch (optc) { 66 case 'S': 67 symbolic = 1; 68 break; 69 case '?': 70 return 1; 71 } 72 cp = wp[builtin_opt.optind]; 73 if (cp == NULL) { 74 old_umask = umask(0); 75 umask(old_umask); 76 if (symbolic) { 77 char buf[18]; 78 int j; 79 80 old_umask = ~old_umask; 81 cp = buf; 82 for (i = 0; i < 3; i++) { 83 *cp++ = "ugo"[i]; 84 *cp++ = '='; 85 for (j = 0; j < 3; j++) 86 if (old_umask & (1 << (8 - (3*i + j)))) 87 *cp++ = "rwx"[j]; 88 *cp++ = ','; 89 } 90 cp[-1] = '\0'; 91 shprintf("%s\n", buf); 92 } else 93 shprintf("%#3.3o\n", old_umask); 94 } else { 95 int new_umask; 96 97 if (digit(*cp)) { 98 for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++) 99 new_umask = new_umask * 8 + (*cp - '0'); 100 if (*cp) { 101 bi_errorf("bad number"); 102 return 1; 103 } 104 } else { 105 /* symbolic format */ 106 int positions, new_val; 107 char op; 108 109 old_umask = umask(0); 110 umask(old_umask); /* in case of error */ 111 old_umask = ~old_umask; 112 new_umask = old_umask; 113 positions = 0; 114 while (*cp) { 115 while (*cp && strchr("augo", *cp)) 116 switch (*cp++) { 117 case 'a': positions |= 0111; break; 118 case 'u': positions |= 0100; break; 119 case 'g': positions |= 0010; break; 120 case 'o': positions |= 0001; break; 121 } 122 if (!positions) 123 positions = 0111; /* default is a */ 124 if (!strchr("=+-", op = *cp)) 125 break; 126 cp++; 127 new_val = 0; 128 while (*cp && strchr("rwxugoXs", *cp)) 129 switch (*cp++) { 130 case 'r': new_val |= 04; break; 131 case 'w': new_val |= 02; break; 132 case 'x': new_val |= 01; break; 133 case 'u': new_val |= old_umask >> 6; 134 break; 135 case 'g': new_val |= old_umask >> 3; 136 break; 137 case 'o': new_val |= old_umask >> 0; 138 break; 139 case 'X': if (old_umask & 0111) 140 new_val |= 01; 141 break; 142 case 's': /* ignored */ 143 break; 144 } 145 new_val = (new_val & 07) * positions; 146 switch (op) { 147 case '-': 148 new_umask &= ~new_val; 149 break; 150 case '=': 151 new_umask = new_val 152 | (new_umask & ~(positions * 07)); 153 break; 154 case '+': 155 new_umask |= new_val; 156 } 157 if (*cp == ',') { 158 positions = 0; 159 cp++; 160 } else if (!strchr("=+-", *cp)) 161 break; 162 } 163 if (*cp) { 164 bi_errorf("bad mask"); 165 return 1; 166 } 167 new_umask = ~new_umask; 168 } 169 umask(new_umask); 170 } 171 return 0; 172 } 173 174 int 175 c_dot(wp) 176 char **wp; 177 { 178 char *file, *cp; 179 char **argv; 180 int argc; 181 int i; 182 183 if (ksh_getopt(wp, &builtin_opt, null) == '?') 184 return 1; 185 186 if ((cp = wp[builtin_opt.optind]) == NULL) 187 return 0; 188 file = search(cp, path, R_OK, (int *) 0); 189 if (file == NULL) { 190 bi_errorf("%s: not found", cp); 191 return 1; 192 } 193 194 /* Set positional parameters? */ 195 if (wp[builtin_opt.optind + 1]) { 196 argv = wp + builtin_opt.optind; 197 argv[0] = e->loc->argv[0]; /* preserve $0 */ 198 for (argc = 0; argv[argc + 1]; argc++) 199 ; 200 } else { 201 argc = 0; 202 argv = (char **) 0; 203 } 204 i = include(file, argc, argv, 0); 205 if (i < 0) { /* should not happen */ 206 bi_errorf("%s: %s", cp, strerror(errno)); 207 return 1; 208 } 209 return i; 210 } 211 212 int 213 c_wait(wp) 214 char **wp; 215 { 216 int UNINITIALIZED(rv); 217 int sig; 218 219 if (ksh_getopt(wp, &builtin_opt, null) == '?') 220 return 1; 221 wp += builtin_opt.optind; 222 if (*wp == (char *) 0) { 223 while (waitfor((char *) 0, &sig) >= 0) 224 ; 225 rv = sig; 226 } else { 227 for (; *wp; wp++) 228 rv = waitfor(*wp, &sig); 229 if (rv < 0) 230 rv = sig ? sig : 127; /* magic exit code: bad job-id */ 231 } 232 return rv; 233 } 234 235 int 236 c_read(wp) 237 char **wp; 238 { 239 register int c = 0; 240 int expand = 1, history = 0; 241 int expanding; 242 int ecode = 0; 243 register char *cp; 244 int fd = 0; 245 struct shf *shf; 246 int optc; 247 const char *emsg; 248 XString cs, xs; 249 struct tbl *vp; 250 char UNINITIALIZED(*xp); 251 252 while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != EOF) 253 switch (optc) { 254 #ifdef KSH 255 case 'p': 256 if ((fd = coproc_getfd(R_OK, &emsg)) < 0) { 257 bi_errorf("-p: %s", emsg); 258 return 1; 259 } 260 break; 261 #endif /* KSH */ 262 case 'r': 263 expand = 0; 264 break; 265 case 's': 266 history = 1; 267 break; 268 case 'u': 269 if (!*(cp = builtin_opt.optarg)) 270 fd = 0; 271 else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) { 272 bi_errorf("-u: %s: %s", cp, emsg); 273 return 1; 274 } 275 break; 276 case '?': 277 return 1; 278 } 279 wp += builtin_opt.optind; 280 281 if (*wp == NULL) 282 *--wp = "REPLY"; 283 284 /* Since we can't necessarily seek backwards on non-regular files, 285 * don't buffer them so we can't read too much. 286 */ 287 shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare); 288 289 if ((cp = strchr(*wp, '?')) != NULL) { 290 *cp = 0; 291 if (isatty(fd)) { 292 /* at&t ksh says it prints prompt on fd if it's open 293 * for writing and is a tty, but it doesn't do it 294 * (it also doesn't check the interactive flag, 295 * as is indicated in the Kornshell book). 296 */ 297 shellf("%s", cp+1); 298 } 299 } 300 301 #ifdef KSH 302 /* If we are reading from the co-process for the first time, 303 * make sure the other side of the pipe is closed first. This allows 304 * the detection of eof. 305 * 306 * This is not compatiable with at&t ksh... the fd is kept so another 307 * coproc can be started with same ouput, however, this means eof 308 * can't be detected... This is why it is closed here. 309 * If this call is removed, remove the eof check below, too. 310 * coproc_readw_close(fd); 311 */ 312 #endif /* KSH */ 313 314 if (history) 315 Xinit(xs, xp, 128, ATEMP); 316 expanding = 0; 317 Xinit(cs, cp, 128, ATEMP); 318 for (; *wp != NULL; wp++) { 319 for (cp = Xstring(cs, cp); ; ) { 320 if (c == '\n' || c == EOF) 321 break; 322 while (1) { 323 c = shf_getc(shf); 324 if (c == '\0' 325 #ifdef OS2 326 || c == '\r' 327 #endif /* OS2 */ 328 ) 329 continue; 330 if (c == EOF && shf_error(shf) 331 && shf_errno(shf) == EINTR) 332 { 333 /* Was the offending signal one that 334 * would normally kill a process? 335 * If so, pretend the read was killed. 336 */ 337 ecode = fatal_trap_check(); 338 339 /* non fatal (eg, CHLD), carry on */ 340 if (!ecode) { 341 shf_clearerr(shf); 342 continue; 343 } 344 } 345 break; 346 } 347 if (history) { 348 Xcheck(xs, xp); 349 Xput(xs, xp, c); 350 } 351 Xcheck(cs, cp); 352 if (expanding) { 353 expanding = 0; 354 if (c == '\n') { 355 c = 0; 356 if (Flag(FTALKING) && isatty(fd)) { 357 /* set prompt in case this is 358 * called from .profile or $ENV 359 */ 360 set_prompt(PS2, (Source *) 0); 361 pprompt(prompt, 0); 362 } 363 } else if (c != EOF) 364 Xput(cs, cp, c); 365 continue; 366 } 367 if (expand && c == '\\') { 368 expanding = 1; 369 continue; 370 } 371 if (c == '\n' || c == EOF) 372 break; 373 if (ctype(c, C_IFS)) { 374 if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS)) 375 continue; 376 if (wp[1]) 377 break; 378 } 379 Xput(cs, cp, c); 380 } 381 /* strip trailing IFS white space from last variable */ 382 if (!wp[1]) 383 while (Xlength(cs, cp) && ctype(cp[-1], C_IFS) 384 && ctype(cp[-1], C_IFSWS)) 385 cp--; 386 Xput(cs, cp, '\0'); 387 vp = global(*wp); 388 if (vp->flag & RDONLY) { 389 shf_flush(shf); 390 bi_errorf("%s is read only", *wp); 391 return 1; 392 } 393 if (Flag(FEXPORT)) 394 typeset(*wp, EXPORT, 0, 0, 0); 395 setstr(vp, Xstring(cs, cp)); 396 } 397 398 shf_flush(shf); 399 if (history) { 400 Xput(xs, xp, '\0'); 401 source->line++; 402 histsave(source->line, Xstring(xs, xp), 1); 403 Xfree(xs, xp); 404 } 405 #ifdef KSH 406 /* if this is the co-process fd, close the file descriptor 407 * (can get eof if and only if all processes are have died, ie, 408 * coproc.njobs is 0 and the pipe is closed). 409 */ 410 if (c == EOF && !ecode) 411 coproc_read_close(fd); 412 #endif /* KSH */ 413 414 return ecode ? ecode : c == EOF; 415 } 416 417 int 418 c_eval(wp) 419 char **wp; 420 { 421 register struct source *s; 422 423 if (ksh_getopt(wp, &builtin_opt, null) == '?') 424 return 1; 425 s = pushs(SWORDS, ATEMP); 426 s->u.strv = wp + builtin_opt.optind; 427 return shell(s, FALSE); 428 } 429 430 int 431 c_trap(wp) 432 char **wp; 433 { 434 int i; 435 char *s; 436 register Trap *p; 437 438 if (ksh_getopt(wp, &builtin_opt, null) == '?') 439 return 1; 440 wp += builtin_opt.optind; 441 442 if (*wp == NULL) { 443 int anydfl = 0; 444 445 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) { 446 if (p->trap == NULL) 447 anydfl = 1; 448 else { 449 shprintf("trap -- "); 450 print_value_quoted(p->trap); 451 shprintf(" %s\n", p->name); 452 } 453 } 454 #if 0 /* this is ugly and not clear POSIX needs it */ 455 /* POSIX may need this so output of trap can be saved and 456 * used to restore trap conditions 457 */ 458 if (anydfl) { 459 shprintf("trap -- -"); 460 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) 461 if (p->trap == NULL && p->name) 462 shprintf(" %s", p->name); 463 shprintf(newline); 464 } 465 #endif 466 return 0; 467 } 468 469 s = (gettrap(*wp) == NULL) ? *wp++ : NULL; /* get command */ 470 if (s != NULL && s[0] == '-' && s[1] == '\0') 471 s = NULL; 472 473 /* set/clear traps */ 474 while (*wp != NULL) { 475 p = gettrap(*wp++); 476 if (p == NULL) { 477 bi_errorf("bad signal %s", wp[-1]); 478 return 1; 479 } 480 settrap(p, s); 481 } 482 return 0; 483 } 484 485 int 486 c_exitreturn(wp) 487 char **wp; 488 { 489 int how = LEXIT; 490 char *arg; 491 492 if (ksh_getopt(wp, &builtin_opt, null) == '?') 493 return 1; 494 arg = wp[builtin_opt.optind]; 495 496 if (arg != NULL && !getn(arg, &exstat)) { 497 exstat = 1; 498 warningf(TRUE, "%s: bad number", arg); 499 } 500 if (wp[0][0] == 'r') { /* return */ 501 struct env *ep; 502 503 /* need to tell if this is exit or return so trap exit will 504 * work right (POSIX) 505 */ 506 for (ep = e; ep; ep = ep->oenv) 507 if (STOP_RETURN(ep->type)) { 508 how = LRETURN; 509 break; 510 } 511 } 512 513 if (how == LEXIT && !really_exit && j_stopped_running()) { 514 really_exit = 1; 515 how = LSHELL; 516 } 517 518 quitenv(); /* get rid of any i/o redirections */ 519 unwind(how); 520 /*NOTREACHED*/ 521 return 0; 522 } 523 524 int 525 c_brkcont(wp) 526 char **wp; 527 { 528 int n, quit; 529 struct env *ep, *last_ep = (struct env *) 0; 530 char *arg; 531 532 if (ksh_getopt(wp, &builtin_opt, null) == '?') 533 return 1; 534 arg = wp[builtin_opt.optind]; 535 536 if (!arg) 537 n = 1; 538 else if (!bi_getn(arg, &n)) 539 return 1; 540 quit = n; 541 if (quit <= 0) { 542 /* at&t ksh does this for non-interactive shells only - weird */ 543 bi_errorf("%s: bad value", arg); 544 return 1; 545 } 546 547 /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */ 548 for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv) 549 if (ep->type == E_LOOP) { 550 if (--quit == 0) 551 break; 552 ep->flags |= EF_BRKCONT_PASS; 553 last_ep = ep; 554 } 555 556 if (quit) { 557 /* at&t ksh doesn't print a message - just does what it 558 * can. We print a message 'cause it helps in debugging 559 * scripts, but don't generate an error (ie, keep going). 560 */ 561 if (n == quit) { 562 warningf(TRUE, "%s: cannot %s", wp[0], wp[0]); 563 return 0; 564 } 565 /* POSIX says if n is too big, the last enclosing loop 566 * shall be used. Doesn't say to print an error but we 567 * do anyway 'cause the user messed up. 568 */ 569 last_ep->flags &= ~EF_BRKCONT_PASS; 570 warningf(TRUE, "%s: can only %s %d level(s)", 571 wp[0], wp[0], n - quit); 572 } 573 574 unwind(*wp[0] == 'b' ? LBREAK : LCONTIN); 575 /*NOTREACHED*/ 576 } 577 578 int 579 c_set(wp) 580 char **wp; 581 { 582 int argi, setargs; 583 struct block *l = e->loc; 584 register char **owp = wp; 585 586 if (wp[1] == NULL) { 587 static const char *const args [] = { "set", "-", NULL }; 588 return c_typeset((char **) args); 589 } 590 591 argi = parse_args(wp, OF_SET, &setargs); 592 if (argi < 0) 593 return 1; 594 /* set $# and $* */ 595 if (setargs) { 596 owp = wp += argi - 1; 597 wp[0] = l->argv[0]; /* save $0 */ 598 while (*++wp != NULL) 599 *wp = str_save(*wp, &l->area); 600 l->argc = wp - owp - 1; 601 l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area); 602 for (wp = l->argv; (*wp++ = *owp++) != NULL; ) 603 ; 604 } 605 /* POSIX says set exit status is 0, but old scripts that use 606 * getopt(1), use the construct: set -- `getopt ab:c "$@"` 607 * which assumes the exit value set will be that of the `` 608 * (subst_exstat is cleared in execute() so that it will be 0 609 * if there are no command substitutions). 610 */ 611 return Flag(FPOSIX) ? 0 : subst_exstat; 612 } 613 614 int 615 c_unset(wp) 616 char **wp; 617 { 618 register char *id; 619 int optc, unset_var = 1; 620 int ret = 0; 621 622 while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF) 623 switch (optc) { 624 case 'f': 625 unset_var = 0; 626 break; 627 case 'v': 628 unset_var = 1; 629 break; 630 case '?': 631 return 1; 632 } 633 wp += builtin_opt.optind; 634 for (; (id = *wp) != NULL; wp++) 635 if (unset_var) { /* unset variable */ 636 struct tbl *vp = global(id); 637 638 if (!(vp->flag & ISSET)) 639 ret = 1; 640 if ((vp->flag&RDONLY)) { 641 bi_errorf("%s is read only", vp->name); 642 return 1; 643 } 644 unset(vp, strchr(id, '[') ? 1 : 0); 645 } else { /* unset function */ 646 if (define(id, (struct op *) NULL)) 647 ret = 1; 648 } 649 return ret; 650 } 651 652 int 653 c_times(wp) 654 char **wp; 655 { 656 struct tms all; 657 658 (void) ksh_times(&all); 659 shprintf("Shell: %8s user ", clocktos(all.tms_utime)); 660 shprintf("%8s system\n", clocktos(all.tms_stime)); 661 shprintf("Kids: %8s user ", clocktos(all.tms_cutime)); 662 shprintf("%8s system\n", clocktos(all.tms_cstime)); 663 664 return 0; 665 } 666 667 /* 668 * time pipeline (really a statement, not a built-in command) 669 */ 670 int 671 timex(t, f) 672 struct op *t; 673 int f; 674 { 675 int rv; 676 struct tms t0, t1; 677 clock_t t0t, t1t; 678 extern clock_t j_usrtime, j_systime; /* computed by j_wait */ 679 680 j_usrtime = j_systime = 0; 681 t0t = ksh_times(&t0); 682 rv = execute(t->left, f); 683 t1t = ksh_times(&t1); 684 685 shf_fprintf(shl_out, "%8s real ", clocktos(t1t - t0t)); 686 shf_fprintf(shl_out, "%8s user ", 687 clocktos(t1.tms_utime - t0.tms_utime + j_usrtime)); 688 shf_fprintf(shl_out, "%8s system ", 689 clocktos(t1.tms_stime - t0.tms_stime + j_systime)); 690 shf_fprintf(shl_out, newline); 691 692 return rv; 693 } 694 695 static char * 696 clocktos(t) 697 clock_t t; 698 { 699 static char temp[20]; 700 register int i; 701 register char *cp = temp + sizeof(temp); 702 703 if (CLK_TCK != 100) /* convert to 1/100'ths */ 704 t = (t < 1000000000/CLK_TCK) ? 705 (t * 100) / CLK_TCK : (t / CLK_TCK) * 100; 706 707 *--cp = '\0'; 708 *--cp = 's'; 709 for (i = -2; i <= 0 || t > 0; i++) { 710 if (i == 0) 711 *--cp = '.'; 712 *--cp = '0' + (char)(t%10); 713 t /= 10; 714 } 715 return cp; 716 } 717 718 /* exec with no args - args case is taken care of in comexec() */ 719 int 720 c_exec(wp) 721 char ** wp; 722 { 723 int i; 724 725 /* make sure redirects stay in place */ 726 if (e->savefd != NULL) { 727 for (i = 0; i < NUFILE; i++) { 728 if (e->savefd[i] > 0) 729 close(e->savefd[i]); 730 /* keep anything > 2 private */ 731 if (i > 2 && e->savefd[i]) 732 fd_clexec(i); 733 } 734 e->savefd = NULL; 735 } 736 return 0; 737 } 738 739 /* dummy function, special case in comexec() */ 740 int 741 c_builtin(wp) 742 char ** wp; 743 { 744 return 0; 745 } 746 747 extern int c_test ARGS((char **wp)); /* in c_test.c */ 748 extern int c_ulimit ARGS((char **wp)); /* in c_ulimit.c */ 749 750 /* A leading = means assignments before command are kept; 751 * a leading * means a POSIX special builtin; 752 * a leading + means a POSIX regular builtin 753 * (* and + should not be combined). 754 */ 755 const struct builtin shbuiltins [] = { 756 {"*=.", c_dot}, 757 {"*=:", c_label}, 758 {"[", c_test}, 759 {"*=break", c_brkcont}, 760 {"=builtin", c_builtin}, 761 {"*=continue", c_brkcont}, 762 {"*=eval", c_eval}, 763 {"*=exec", c_exec}, 764 {"*=exit", c_exitreturn}, 765 {"+false", c_label}, 766 {"*=return", c_exitreturn}, 767 {"*=set", c_set}, 768 {"*=shift", c_shift}, 769 {"=times", c_times}, 770 {"*=trap", c_trap}, 771 {"+=wait", c_wait}, 772 {"+read", c_read}, 773 {"test", c_test}, 774 {"+true", c_label}, 775 {"ulimit", c_ulimit}, 776 {"+umask", c_umask}, 777 {"*=unset", c_unset}, 778 #ifdef OS2 779 /* In OS2, the first line of a file can be "extproc name", which 780 * tells the command interpreter (cmd.exe) to use name to execute 781 * the file. For this to be useful, ksh must ignore commands 782 * starting with extproc and this does the trick... 783 */ 784 {"extproc", c_label}, 785 #endif /* OS2 */ 786 {NULL, NULL} 787 }; 788