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