1 /* 2 * built-in Bourne commands 3 */ 4 5 #include "sh.h" 6 #include "ksh_stat.h" /* umask() */ 7 #include "ksh_time.h" 8 #include "ksh_times.h" 9 10 static char *clocktos ARGS((clock_t t)); 11 12 13 /* :, false and true */ 14 int 15 c_label(wp) 16 char **wp; 17 { 18 return wp[0][0] == 'f' ? 1 : 0; 19 } 20 21 int 22 c_shift(wp) 23 char **wp; 24 { 25 register struct block *l = e->loc; 26 register int n; 27 long val; 28 char *arg; 29 30 if (ksh_getopt(wp, &builtin_opt, null) == '?') 31 return 1; 32 arg = wp[builtin_opt.optind]; 33 34 if (arg) { 35 evaluate(arg, &val, KSH_UNWIND_ERROR); 36 n = val; 37 } else 38 n = 1; 39 if (n < 0) { 40 bi_errorf("%s: bad number", arg); 41 return (1); 42 } 43 if (l->argc < n) { 44 bi_errorf("nothing to shift"); 45 return (1); 46 } 47 l->argv[n] = l->argv[0]; 48 l->argv += n; 49 l->argc -= n; 50 return 0; 51 } 52 53 int 54 c_umask(wp) 55 char **wp; 56 { 57 register int i; 58 register char *cp; 59 int symbolic = 0; 60 int old_umask; 61 int optc; 62 63 while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF) 64 switch (optc) { 65 case 'S': 66 symbolic = 1; 67 break; 68 case '?': 69 return 1; 70 } 71 cp = wp[builtin_opt.optind]; 72 if (cp == NULL) { 73 old_umask = umask(0); 74 umask(old_umask); 75 if (symbolic) { 76 char buf[18]; 77 int j; 78 79 old_umask = ~old_umask; 80 cp = buf; 81 for (i = 0; i < 3; i++) { 82 *cp++ = "ugo"[i]; 83 *cp++ = '='; 84 for (j = 0; j < 3; j++) 85 if (old_umask & (1 << (8 - (3*i + j)))) 86 *cp++ = "rwx"[j]; 87 *cp++ = ','; 88 } 89 cp[-1] = '\0'; 90 shprintf("%s\n", buf); 91 } else 92 shprintf("%#3.3o\n", old_umask); 93 } else { 94 int new_umask; 95 96 if (digit(*cp)) { 97 for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++) 98 new_umask = new_umask * 8 + (*cp - '0'); 99 if (*cp) { 100 bi_errorf("bad number"); 101 return 1; 102 } 103 } else { 104 /* symbolic format */ 105 int positions, new_val; 106 char op; 107 108 old_umask = umask(0); 109 umask(old_umask); /* in case of error */ 110 old_umask = ~old_umask; 111 new_umask = old_umask; 112 positions = 0; 113 while (*cp) { 114 while (*cp && strchr("augo", *cp)) 115 switch (*cp++) { 116 case 'a': positions |= 0111; break; 117 case 'u': positions |= 0100; break; 118 case 'g': positions |= 0010; break; 119 case 'o': positions |= 0001; break; 120 } 121 if (!positions) 122 positions = 0111; /* default is a */ 123 if (!strchr("=+-", op = *cp)) 124 break; 125 cp++; 126 new_val = 0; 127 while (*cp && strchr("rwxugoXs", *cp)) 128 switch (*cp++) { 129 case 'r': new_val |= 04; break; 130 case 'w': new_val |= 02; break; 131 case 'x': new_val |= 01; break; 132 case 'u': new_val |= old_umask >> 6; 133 break; 134 case 'g': new_val |= old_umask >> 3; 135 break; 136 case 'o': new_val |= old_umask >> 0; 137 break; 138 case 'X': if (old_umask & 0111) 139 new_val |= 01; 140 break; 141 case 's': /* ignored */ 142 break; 143 } 144 new_val = (new_val & 07) * positions; 145 switch (op) { 146 case '-': 147 new_umask &= ~new_val; 148 break; 149 case '=': 150 new_umask = new_val 151 | (new_umask & ~(positions * 07)); 152 break; 153 case '+': 154 new_umask |= new_val; 155 } 156 if (*cp == ',') { 157 positions = 0; 158 cp++; 159 } else if (!strchr("=+-", *cp)) 160 break; 161 } 162 if (*cp) { 163 bi_errorf("bad mask"); 164 return 1; 165 } 166 new_umask = ~new_umask; 167 } 168 umask(new_umask); 169 } 170 return 0; 171 } 172 173 int 174 c_dot(wp) 175 char **wp; 176 { 177 char *file, *cp; 178 char **argv; 179 int argc; 180 int i; 181 int err; 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, &err); 189 if (file == NULL) { 190 bi_errorf("%s: %s", cp, err ? strerror(err) : "not found"); 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_I) && 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 /* Must be done before setting export. */ 389 if (vp->flag & RDONLY) { 390 shf_flush(shf); 391 bi_errorf("%s is read only", *wp); 392 return 1; 393 } 394 if (Flag(FEXPORT)) 395 typeset(*wp, EXPORT, 0, 0, 0); 396 if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) { 397 shf_flush(shf); 398 return 1; 399 } 400 } 401 402 shf_flush(shf); 403 if (history) { 404 Xput(xs, xp, '\0'); 405 source->line++; 406 histsave(source->line, Xstring(xs, xp), 1); 407 Xfree(xs, xp); 408 } 409 #ifdef KSH 410 /* if this is the co-process fd, close the file descriptor 411 * (can get eof if and only if all processes are have died, ie, 412 * coproc.njobs is 0 and the pipe is closed). 413 */ 414 if (c == EOF && !ecode) 415 coproc_read_close(fd); 416 #endif /* KSH */ 417 418 return ecode ? ecode : c == EOF; 419 } 420 421 int 422 c_eval(wp) 423 char **wp; 424 { 425 register struct source *s; 426 427 if (ksh_getopt(wp, &builtin_opt, null) == '?') 428 return 1; 429 s = pushs(SWORDS, ATEMP); 430 s->u.strv = wp + builtin_opt.optind; 431 if (!Flag(FPOSIX)) { 432 /* 433 * Handle case where the command is empty due to failed 434 * command substitution, eg, eval "$(false)". 435 * In this case, shell() will not set/change exstat (because 436 * compiled tree is empty), so will use this value. 437 * subst_exstat is cleared in execute(), so should be 0 if 438 * there were no substitutions. 439 * 440 * A strict reading of POSIX says we don't do this (though 441 * it is traditionally done). [from 1003.2-1992] 442 * 3.9.1: Simple Commands 443 * ... If there is a command name, execution shall 444 * continue as described in 3.9.1.1. If there 445 * is no command name, but the command contained a command 446 * substitution, the command shall complete with the exit 447 * status of the last command substitution 448 * 3.9.1.1: Command Search and Execution 449 * ...(1)...(a) If the command name matches the name of 450 * a special built-in utility, that special built-in 451 * utility shall be invoked. 452 * 3.14.5: Eval 453 * ... If there are no arguments, or only null arguments, 454 * eval shall return an exit status of zero. 455 */ 456 exstat = subst_exstat; 457 } 458 459 return shell(s, FALSE); 460 } 461 462 int 463 c_trap(wp) 464 char **wp; 465 { 466 int i; 467 char *s; 468 register Trap *p; 469 470 if (ksh_getopt(wp, &builtin_opt, null) == '?') 471 return 1; 472 wp += builtin_opt.optind; 473 474 if (*wp == NULL) { 475 int anydfl = 0; 476 477 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) { 478 if (p->trap == NULL) 479 anydfl = 1; 480 else { 481 shprintf("trap -- "); 482 print_value_quoted(p->trap); 483 shprintf(" %s\n", p->name); 484 } 485 } 486 #if 0 /* this is ugly and not clear POSIX needs it */ 487 /* POSIX may need this so output of trap can be saved and 488 * used to restore trap conditions 489 */ 490 if (anydfl) { 491 shprintf("trap -- -"); 492 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) 493 if (p->trap == NULL && p->name) 494 shprintf(" %s", p->name); 495 shprintf(newline); 496 } 497 #endif 498 return 0; 499 } 500 501 /* 502 * Use case sensitive lookup for first arg so the 503 * command 'exit' isn't confused with the pseudo-signal 504 * 'EXIT'. 505 */ 506 s = (gettrap(*wp, FALSE) == NULL) ? *wp++ : NULL; /* get command */ 507 if (s != NULL && s[0] == '-' && s[1] == '\0') 508 s = NULL; 509 510 /* set/clear traps */ 511 while (*wp != NULL) { 512 p = gettrap(*wp++, TRUE); 513 if (p == NULL) { 514 bi_errorf("bad signal %s", wp[-1]); 515 return 1; 516 } 517 settrap(p, s); 518 } 519 return 0; 520 } 521 522 int 523 c_exitreturn(wp) 524 char **wp; 525 { 526 int how = LEXIT; 527 int n; 528 char *arg; 529 530 if (ksh_getopt(wp, &builtin_opt, null) == '?') 531 return 1; 532 arg = wp[builtin_opt.optind]; 533 534 if (arg) { 535 if (!getn(arg, &n)) { 536 exstat = 1; 537 warningf(TRUE, "%s: bad number", arg); 538 } else 539 exstat = n; 540 } 541 if (wp[0][0] == 'r') { /* return */ 542 struct env *ep; 543 544 /* need to tell if this is exit or return so trap exit will 545 * work right (POSIX) 546 */ 547 for (ep = e; ep; ep = ep->oenv) 548 if (STOP_RETURN(ep->type)) { 549 how = LRETURN; 550 break; 551 } 552 } 553 554 if (how == LEXIT && !really_exit && j_stopped_running()) { 555 really_exit = 1; 556 how = LSHELL; 557 } 558 559 quitenv(); /* get rid of any i/o redirections */ 560 unwind(how); 561 /*NOTREACHED*/ 562 return 0; 563 } 564 565 int 566 c_brkcont(wp) 567 char **wp; 568 { 569 int n, quit; 570 struct env *ep, *last_ep = (struct env *) 0; 571 char *arg; 572 573 if (ksh_getopt(wp, &builtin_opt, null) == '?') 574 return 1; 575 arg = wp[builtin_opt.optind]; 576 577 if (!arg) 578 n = 1; 579 else if (!bi_getn(arg, &n)) 580 return 1; 581 quit = n; 582 if (quit <= 0) { 583 /* at&t ksh does this for non-interactive shells only - weird */ 584 bi_errorf("%s: bad value", arg); 585 return 1; 586 } 587 588 /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */ 589 for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv) 590 if (ep->type == E_LOOP) { 591 if (--quit == 0) 592 break; 593 ep->flags |= EF_BRKCONT_PASS; 594 last_ep = ep; 595 } 596 597 if (quit) { 598 /* at&t ksh doesn't print a message - just does what it 599 * can. We print a message 'cause it helps in debugging 600 * scripts, but don't generate an error (ie, keep going). 601 */ 602 if (n == quit) { 603 warningf(TRUE, "%s: cannot %s", wp[0], wp[0]); 604 return 0; 605 } 606 /* POSIX says if n is too big, the last enclosing loop 607 * shall be used. Doesn't say to print an error but we 608 * do anyway 'cause the user messed up. 609 */ 610 last_ep->flags &= ~EF_BRKCONT_PASS; 611 warningf(TRUE, "%s: can only %s %d level(s)", 612 wp[0], wp[0], n - quit); 613 } 614 615 unwind(*wp[0] == 'b' ? LBREAK : LCONTIN); 616 /*NOTREACHED*/ 617 } 618 619 int 620 c_set(wp) 621 char **wp; 622 { 623 int argi, setargs; 624 struct block *l = e->loc; 625 register char **owp = wp; 626 627 if (wp[1] == NULL) { 628 static const char *const args [] = { "set", "-", NULL }; 629 return c_typeset((char **) args); 630 } 631 632 argi = parse_args(wp, OF_SET, &setargs); 633 if (argi < 0) 634 return 1; 635 /* set $# and $* */ 636 if (setargs) { 637 owp = wp += argi - 1; 638 wp[0] = l->argv[0]; /* save $0 */ 639 while (*++wp != NULL) 640 *wp = str_save(*wp, &l->area); 641 l->argc = wp - owp - 1; 642 l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area); 643 for (wp = l->argv; (*wp++ = *owp++) != NULL; ) 644 ; 645 } 646 /* POSIX says set exit status is 0, but old scripts that use 647 * getopt(1), use the construct: set -- `getopt ab:c "$@"` 648 * which assumes the exit value set will be that of the `` 649 * (subst_exstat is cleared in execute() so that it will be 0 650 * if there are no command substitutions). 651 */ 652 return Flag(FPOSIX) ? 0 : subst_exstat; 653 } 654 655 int 656 c_unset(wp) 657 char **wp; 658 { 659 register char *id; 660 int optc, unset_var = 1; 661 int ret = 0; 662 663 while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF) 664 switch (optc) { 665 case 'f': 666 unset_var = 0; 667 break; 668 case 'v': 669 unset_var = 1; 670 break; 671 case '?': 672 return 1; 673 } 674 wp += builtin_opt.optind; 675 for (; (id = *wp) != NULL; wp++) 676 if (unset_var) { /* unset variable */ 677 struct tbl *vp = global(id); 678 679 if (!(vp->flag & ISSET)) 680 ret = 1; 681 if ((vp->flag&RDONLY)) { 682 bi_errorf("%s is read only", vp->name); 683 return 1; 684 } 685 unset(vp, strchr(id, '[') ? 1 : 0); 686 } else { /* unset function */ 687 if (define(id, (struct op *) NULL)) 688 ret = 1; 689 } 690 return ret; 691 } 692 693 int 694 c_times(wp) 695 char **wp; 696 { 697 struct tms all; 698 699 (void) ksh_times(&all); 700 shprintf("Shell: %8ss user ", clocktos(all.tms_utime)); 701 shprintf("%8ss system\n", clocktos(all.tms_stime)); 702 shprintf("Kids: %8ss user ", clocktos(all.tms_cutime)); 703 shprintf("%8ss system\n", clocktos(all.tms_cstime)); 704 705 return 0; 706 } 707 708 /* 709 * time pipeline (really a statement, not a built-in command) 710 */ 711 int 712 timex(t, f) 713 struct op *t; 714 int f; 715 { 716 #define TF_NOARGS BIT(0) 717 #define TF_NOREAL BIT(1) /* don't report real time */ 718 #define TF_POSIX BIT(2) /* report in posix format */ 719 int rv = 0; 720 struct tms t0, t1, tms; 721 clock_t t0t, t1t = 0; 722 int tf = 0; 723 extern clock_t j_usrtime, j_systime; /* computed by j_wait */ 724 char opts[1]; 725 726 t0t = ksh_times(&t0); 727 if (t->left) { 728 /* 729 * Two ways of getting cpu usage of a command: just use t0 730 * and t1 (which will get cpu usage from other jobs that 731 * finish while we are executing t->left), or get the 732 * cpu usage of t->left. at&t ksh does the former, while 733 * pdksh tries to do the later (the j_usrtime hack doesn't 734 * really work as it only counts the last job). 735 */ 736 j_usrtime = j_systime = 0; 737 if (t->left->type == TCOM) 738 t->left->str = opts; 739 opts[0] = 0; 740 rv = execute(t->left, f | XTIME); 741 tf |= opts[0]; 742 t1t = ksh_times(&t1); 743 } else 744 tf = TF_NOARGS; 745 746 if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */ 747 tf |= TF_NOREAL; 748 tms.tms_utime = t0.tms_utime + t0.tms_cutime; 749 tms.tms_stime = t0.tms_stime + t0.tms_cstime; 750 } else { 751 tms.tms_utime = t1.tms_utime - t0.tms_utime + j_usrtime; 752 tms.tms_stime = t1.tms_stime - t0.tms_stime + j_systime; 753 } 754 755 if (!(tf & TF_NOREAL)) 756 shf_fprintf(shl_out, 757 tf & TF_POSIX ? "real %8s\n" : "%8ss real ", 758 clocktos(t1t - t0t)); 759 shf_fprintf(shl_out, tf & TF_POSIX ? "user %8s\n" : "%8ss user ", 760 clocktos(tms.tms_utime)); 761 shf_fprintf(shl_out, tf & TF_POSIX ? "sys %8s\n" : "%8ss system\n", 762 clocktos(tms.tms_stime)); 763 shf_flush(shl_out); 764 765 return rv; 766 } 767 768 void 769 timex_hook(t, app) 770 struct op *t; 771 char ** volatile *app; 772 { 773 char **wp = *app; 774 int optc; 775 int i, j; 776 Getopt opt; 777 778 ksh_getopt_reset(&opt, 0); 779 opt.optind = 0; /* start at the start */ 780 while ((optc = ksh_getopt(wp, &opt, ":p")) != EOF) 781 switch (optc) { 782 case 'p': 783 t->str[0] |= TF_POSIX; 784 break; 785 case '?': 786 errorf("time: -%s unknown option", opt.optarg); 787 case ':': 788 errorf("time: -%s requires an argument", 789 opt.optarg); 790 } 791 /* Copy command words down over options. */ 792 if (opt.optind != 0) { 793 for (i = 0; i < opt.optind; i++) 794 afree(wp[i], ATEMP); 795 for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++) 796 ; 797 } 798 if (!wp[0]) 799 t->str[0] |= TF_NOARGS; 800 *app = wp; 801 } 802 803 static char * 804 clocktos(t) 805 clock_t t; 806 { 807 static char temp[22]; /* enough for 64 bit clock_t */ 808 register int i; 809 register char *cp = temp + sizeof(temp); 810 811 /* note: posix says must use max precision, ie, if clk_tck is 812 * 1000, must print 3 places after decimal (if non-zero, else 1). 813 */ 814 if (CLK_TCK != 100) /* convert to 1/100'ths */ 815 t = (t < 1000000000/CLK_TCK) ? 816 (t * 100) / CLK_TCK : (t / CLK_TCK) * 100; 817 818 *--cp = '\0'; 819 for (i = -2; i <= 0 || t > 0; i++) { 820 if (i == 0) 821 *--cp = '.'; 822 *--cp = '0' + (char)(t%10); 823 t /= 10; 824 } 825 return cp; 826 } 827 828 /* exec with no args - args case is taken care of in comexec() */ 829 int 830 c_exec(wp) 831 char ** wp; 832 { 833 int i; 834 835 /* make sure redirects stay in place */ 836 if (e->savefd != NULL) { 837 for (i = 0; i < NUFILE; i++) { 838 if (e->savefd[i] > 0) 839 close(e->savefd[i]); 840 /* 841 * For ksh keep anything > 2 private, 842 * for sh, let them be (POSIX says what 843 * happens is unspecified and the bourne shell 844 * keeps them open). 845 */ 846 #ifdef KSH 847 if (i > 2 && e->savefd[i]) 848 fd_clexec(i); 849 #endif /* KSH */ 850 } 851 e->savefd = NULL; 852 } 853 return 0; 854 } 855 856 /* dummy function, special case in comexec() */ 857 int 858 c_builtin(wp) 859 char ** wp; 860 { 861 return 0; 862 } 863 864 extern int c_test ARGS((char **wp)); /* in c_test.c */ 865 extern int c_ulimit ARGS((char **wp)); /* in c_ulimit.c */ 866 867 /* A leading = means assignments before command are kept; 868 * a leading * means a POSIX special builtin; 869 * a leading + means a POSIX regular builtin 870 * (* and + should not be combined). 871 */ 872 const struct builtin shbuiltins [] = { 873 {"*=.", c_dot}, 874 {"*=:", c_label}, 875 {"[", c_test}, 876 {"*=break", c_brkcont}, 877 {"=builtin", c_builtin}, 878 {"*=continue", c_brkcont}, 879 {"*=eval", c_eval}, 880 {"*=exec", c_exec}, 881 {"*=exit", c_exitreturn}, 882 {"+false", c_label}, 883 {"*=return", c_exitreturn}, 884 {"*=set", c_set}, 885 {"*=shift", c_shift}, 886 {"=times", c_times}, 887 {"*=trap", c_trap}, 888 {"+=wait", c_wait}, 889 {"+read", c_read}, 890 {"test", c_test}, 891 {"+true", c_label}, 892 {"ulimit", c_ulimit}, 893 {"+umask", c_umask}, 894 {"*=unset", c_unset}, 895 #ifdef OS2 896 /* In OS2, the first line of a file can be "extproc name", which 897 * tells the command interpreter (cmd.exe) to use name to execute 898 * the file. For this to be useful, ksh must ignore commands 899 * starting with extproc and this does the trick... 900 */ 901 {"extproc", c_label}, 902 #endif /* OS2 */ 903 {NULL, NULL} 904 }; 905