1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980 Regents of the University of California. 11 * All rights reserved. The Berkeley Software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 #include "sh.h" 16 #include <locale.h> /* For LC_ALL */ 17 #include "sh.tconst.h" 18 #include <sys/types.h> 19 #include <stdlib.h> 20 21 /* 22 * N.B.: Some of the limits change from SunOS 4.x to SunOS 5.0. In 23 * particular, RLIMIT_RSS is gone and RLIMIT_VMEM is new. Beware of consusing 24 * the keywords that the command prints for these two. The old one was 25 * "memoryuse" and the new one is "memorysize". Note also that a given limit 26 * doesn't necessarily appear in the same position in the two releases. 27 */ 28 struct limits { 29 int limconst; 30 tchar *limname; 31 int limdiv; 32 tchar *limscale; 33 } limits[] = { 34 RLIMIT_CPU, S_cputime, /* "cputime" */ 35 1, S_seconds, /* "seconds" */ 36 RLIMIT_FSIZE, S_filesize, /* "filesize" */ 37 1024, S_kbytes, /* "kbytes" */ 38 RLIMIT_DATA, S_datasize, /* "datasize" */ 39 1024, S_kbytes, /* "kbytes" */ 40 RLIMIT_STACK, S_stacksize, /* "stacksize" */ 41 1024, S_kbytes, /* "kbytes" */ 42 RLIMIT_CORE, S_coredumpsize, /* "coredumpsize" */ 43 1024, S_kbytes, /* "kbytes" */ 44 RLIMIT_NOFILE, S_descriptors, /* "descriptors" */ 45 1, S_, /* "" */ 46 RLIMIT_VMEM, S_memorysize, /* "memorysize" */ 47 1024, S_kbytes, /* "kbytes" */ 48 -1, 0, 49 }; 50 51 struct Bin B; 52 struct whyle *whyles; 53 bool chkstop; 54 bool doneinp; 55 bool intty; 56 bool setintr; 57 int shpgrp; 58 int opgrp; 59 off_t lineloc; 60 tchar *evalp; 61 tchar **evalvec; 62 tchar *gointr; 63 64 65 static int getval(struct limits *lp, tchar **v, rlim_t *); 66 void islogin(void); 67 int dolabel(void); 68 void reexecute(struct command *kp); 69 void preread_(void); 70 void doagain(void); 71 void toend(void); 72 void wfree(void); 73 void echo(tchar sep, tchar **v); 74 void local_setenv(tchar *name, tchar *val); 75 void local_unsetenv(tchar *name); 76 void limtail(tchar *cp, tchar *str0); 77 void plim(struct limits *lp, tchar hard); 78 void search(); 79 80 #define BUFSZ 1028 81 82 /* 83 * C shell 84 */ 85 86 struct biltins * 87 isbfunc(struct command *t) 88 { 89 tchar *cp = t->t_dcom[0]; 90 struct biltins *bp, *bp1, *bp2; 91 int dofg1(), dobg1(); 92 93 static struct biltins label = { S_, dolabel, 0, 0 }; 94 static struct biltins foregnd = { S_Pjob, dofg1, 0, 0 }; 95 static struct biltins backgnd = { S_PjobAND, dobg1, 0, 0 }; 96 #ifdef TRACE 97 tprintf("TRACE- isbfunc()\n"); 98 #endif 99 if (lastchr(cp) == ':') { 100 label.bname = cp; 101 return (&label); 102 } 103 if (*cp == '%') { 104 if (t->t_dflg & FAND) { 105 t->t_dflg &= ~FAND; 106 backgnd.bname = cp; 107 return (&backgnd); 108 } 109 foregnd.bname = cp; 110 return (&foregnd); 111 } 112 /* 113 * Binary search 114 * Bp1 is the beginning of the current search range. 115 * Bp2 is one past the end. 116 */ 117 for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2; ) { 118 int i; 119 120 bp = bp1 + (bp2 - bp1 >> 1); 121 if ((i = *cp - *bp->bname) == 0 && 122 (i = strcmp_(cp, bp->bname)) == 0) { 123 return (bp); 124 } 125 if (i < 0) { 126 bp2 = bp; 127 } else { 128 bp1 = bp + 1; 129 } 130 } 131 return (0); 132 } 133 134 void 135 func(struct command *t, struct biltins *bp) 136 { 137 int i; 138 139 #ifdef TRACE 140 tprintf("TRACE- func()\n"); 141 #endif 142 xechoit(t->t_dcom); 143 setname(bp->bname); 144 i = blklen(t->t_dcom) - 1; 145 if (i < bp->minargs) { 146 bferr("Too few arguments"); 147 } 148 if (i > bp->maxargs) { 149 bferr("Too many arguments"); 150 } 151 (*bp->bfunct)(t->t_dcom, t); 152 } 153 154 int 155 dolabel(void) 156 { 157 #ifdef TRACE 158 tprintf("TRACE- dolabel()\n"); 159 #endif 160 return (0); 161 } 162 163 void 164 doonintr(tchar **v) 165 { 166 tchar *cp; 167 tchar *vv = v[1]; 168 169 #ifdef TRACE 170 tprintf("TRACE- doonintr()\n"); 171 #endif 172 if (parintr == SIG_IGN) { 173 return; 174 } 175 if (setintr && intty) { 176 bferr("Can't from terminal"); 177 } 178 cp = gointr, gointr = 0, xfree(cp); 179 if (vv == 0) { 180 if (setintr) { 181 (void) sigblock(sigmask(SIGINT)); 182 } else { 183 (void) signal(SIGINT, SIG_DFL); 184 } 185 gointr = 0; 186 } else if (eq((vv = strip(vv)), S_MINUS)) { 187 (void) signal(SIGINT, SIG_IGN); 188 gointr = S_MINUS; 189 } else { 190 gointr = savestr(vv); 191 (void) signal(SIGINT, pintr); 192 } 193 } 194 195 void 196 donohup(void) 197 { 198 199 #ifdef TRACE 200 tprintf("TRACE- donohup()\n"); 201 #endif 202 if (intty) { 203 bferr("Can't from terminal"); 204 } 205 if (setintr == 0) { 206 (void) signal(SIGHUP, SIG_IGN); 207 #ifdef CC 208 submit(getpid()); 209 #endif 210 } 211 } 212 213 void 214 dozip(void) 215 { 216 ; 217 } 218 219 void 220 prvars(void) 221 { 222 #ifdef TRACE 223 tprintf("TRACE- prvars()\n"); 224 #endif 225 226 plist(&shvhed); 227 } 228 229 void 230 doalias(tchar **v) 231 { 232 struct varent *vp; 233 tchar *p; 234 235 #ifdef TRACE 236 tprintf("TRACE- doalias()\n"); 237 #endif 238 v++; 239 p = *v++; 240 if (p == 0) { 241 plist(&aliases); 242 } else if (*v == 0) { 243 vp = adrof1(strip(p), &aliases); 244 if (vp) { 245 blkpr(vp->vec), printf("\n"); 246 } 247 } else { 248 if (eq(p, S_alias) || 249 eq(p, S_unalias)) { 250 setname(p); 251 bferr("Too dangerous to alias that"); 252 } 253 set1(strip(p), saveblk(v), &aliases); 254 } 255 } 256 257 void 258 unalias(tchar **v) 259 { 260 261 #ifdef TRACE 262 tprintf("TRACE- unalias()\n"); 263 #endif 264 unset1(v, &aliases); 265 } 266 267 void 268 dologout(void) 269 { 270 271 #ifdef TRACE 272 tprintf("TRACE- dologout()\n"); 273 #endif 274 islogin(); 275 goodbye(); 276 } 277 278 void 279 dologin(tchar **v) 280 { 281 282 char *v_; /* work */ 283 #ifdef TRACE 284 tprintf("TRACE- dologin()\n"); 285 #endif 286 islogin(); 287 rechist(); 288 (void) signal(SIGTERM, parterm); 289 if (v[1] != NULL) { 290 v_ = tstostr(NULL, v[1]); /* No need to free */ 291 } else { 292 v_ = 0; 293 } 294 execl("/bin/login", "login", v_, 0); 295 untty(); 296 exit(1); 297 } 298 299 #ifdef NEWGRP 300 void 301 donewgrp(tchar **v) 302 { 303 304 char *v_; /* work */ 305 #ifdef TRACE 306 tprintf("TRACE- donewgrp()\n"); 307 #endif 308 if (chkstop == 0 && setintr) { 309 panystop(0); 310 } 311 (void) signal(SIGTERM, parterm); 312 313 if (v[1] != NULL) { 314 v_ = tstostr(NOSTR, v[1]); /* No need to free */ 315 } else { 316 v_ = 0; 317 } 318 execl("/bin/newgrp", "newgrp", v_, 0); 319 execl("/usr/bin/newgrp", "newgrp", v_, 0); 320 untty(); 321 exit(1); 322 } 323 #endif 324 325 void 326 islogin(void) 327 { 328 329 #ifdef TRACE 330 tprintf("TRACE- islogin()\n"); 331 #endif 332 if (chkstop == 0 && setintr) { 333 panystop(0); 334 } 335 if (loginsh) { 336 return; 337 } 338 error("Not login shell"); 339 } 340 341 void 342 doif(tchar **v, struct command *kp) 343 { 344 int i; 345 tchar **vv; 346 347 #ifdef TRACE 348 tprintf("TRACE- doif()\n"); 349 #endif 350 v++; 351 i = exp(&v); 352 vv = v; 353 if (*vv == NOSTR) { 354 bferr("Empty if"); 355 } 356 if (eq(*vv, S_then)) { 357 if (*++vv) { 358 bferr("Improper then"); 359 } 360 setname(S_then); 361 /* 362 * If expression was zero, then scan to else, 363 * otherwise just fall into following code. 364 */ 365 if (!i) { 366 search(ZIF, 0); 367 } 368 return; 369 } 370 /* 371 * Simple command attached to this if. 372 * Left shift the node in this tree, munging it 373 * so we can reexecute it. 374 */ 375 if (i) { 376 lshift(kp->t_dcom, vv - kp->t_dcom); 377 reexecute(kp); 378 donefds(); 379 } 380 } 381 382 /* 383 * Reexecute a command, being careful not 384 * to redo i/o redirection, which is already set up. 385 */ 386 void 387 reexecute(struct command *kp) 388 { 389 390 #ifdef TRACE 391 tprintf("TRACE- reexecute()\n"); 392 #endif 393 kp->t_dflg &= FSAVE; 394 kp->t_dflg |= FREDO; 395 /* 396 * If tty is still ours to arbitrate, arbitrate it; 397 * otherwise dont even set pgrp's as the jobs would 398 * then have no way to get the tty (we can't give it 399 * to them, and our parent wouldn't know their pgrp, etc. 400 */ 401 execute(kp, tpgrp > 0 ? tpgrp : -1); 402 } 403 404 void 405 doelse(void) 406 { 407 408 #ifdef TRACE 409 tprintf("TRACE- doelse()\n"); 410 #endif 411 search(ZELSE, 0); 412 } 413 414 void 415 dogoto(tchar **v) 416 { 417 struct whyle *wp; 418 tchar *lp; 419 #ifdef TRACE 420 tprintf("TRACE- dogoto()\n"); 421 #endif 422 423 /* 424 * While we still can, locate any unknown ends of existing loops. 425 * This obscure code is the WORST result of the fact that we 426 * don't really parse. 427 */ 428 for (wp = whyles; wp; wp = wp->w_next) { 429 if (wp->w_end == 0) { 430 search(ZBREAK, 0); 431 wp->w_end = btell(); 432 } else { 433 bseek(wp->w_end); 434 } 435 } 436 search(ZGOTO, 0, lp = globone(v[1])); 437 xfree(lp); 438 /* 439 * Eliminate loops which were exited. 440 */ 441 wfree(); 442 } 443 444 void 445 doswitch(tchar **v) 446 { 447 tchar *cp, *lp; 448 449 #ifdef TRACE 450 tprintf("TRACE- doswitch()\n"); 451 #endif 452 v++; 453 if (!*v || *(*v++) != '(') { 454 goto syntax; 455 } 456 cp = **v == ')' ? S_ : *v++; 457 if (*(*v++) != ')') { 458 v--; 459 } 460 if (*v) { 461 syntax: 462 error("Syntax error"); 463 } 464 search(ZSWITCH, 0, lp = globone(cp)); 465 xfree(lp); 466 } 467 468 void 469 dobreak(void) 470 { 471 472 #ifdef TRACE 473 tprintf("TRACE- dobreak()\n"); 474 #endif 475 if (whyles) { 476 toend(); 477 } else { 478 bferr("Not in while/foreach"); 479 } 480 } 481 482 void 483 doexit(tchar **v) 484 { 485 486 #ifdef TRACE 487 tprintf("TRACE- doexit()\n"); 488 #endif 489 if (chkstop == 0) { 490 panystop(0); 491 } 492 /* 493 * Don't DEMAND parentheses here either. 494 */ 495 v++; 496 if (*v) { 497 set(S_status, putn(exp(&v))); 498 if (*v) { 499 bferr("Expression syntax"); 500 } 501 } 502 btoeof(); 503 if (intty) { 504 (void) close(SHIN); 505 unsetfd(SHIN); 506 } 507 } 508 509 void 510 doforeach(tchar **v) 511 { 512 tchar *cp; 513 struct whyle *nwp; 514 515 #ifdef TRACE 516 tprintf("TRACE- doforeach()\n"); 517 #endif 518 v++; 519 cp = strip(*v); 520 while (*cp && alnum(*cp)) { 521 cp++; 522 } 523 if (*cp || strlen_(*v) >= MAX_VAR_LEN || !letter(**v)) { 524 bferr("Invalid variable"); 525 } 526 cp = *v++; 527 if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') { 528 bferr("Words not ()'ed"); 529 } 530 v++; 531 gflag = 0, tglob(v); 532 v = glob(v); 533 if (v == 0) { 534 bferr("No match"); 535 } 536 nwp = (struct whyle *)xcalloc(1, sizeof (*nwp)); 537 nwp->w_fe = nwp->w_fe0 = v; gargv = 0; 538 nwp->w_start = btell(); 539 nwp->w_fename = savestr(cp); 540 nwp->w_next = whyles; 541 whyles = nwp; 542 /* 543 * Pre-read the loop so as to be more 544 * comprehensible to a terminal user. 545 */ 546 if (intty) { 547 preread_(); 548 } 549 doagain(); 550 } 551 552 void 553 dowhile(tchar **v) 554 { 555 int status; 556 bool again = whyles != 0 && whyles->w_start == lineloc && 557 whyles->w_fename == 0; 558 559 #ifdef TRACE 560 tprintf("TRACE- dowhile()\n"); 561 #endif 562 v++; 563 /* 564 * Implement prereading here also, taking care not to 565 * evaluate the expression before the loop has been read up 566 * from a terminal. 567 */ 568 if (intty && !again) { 569 status = !exp0(&v, 1); 570 } else { 571 status = !exp(&v); 572 } 573 if (*v) { 574 bferr("Expression syntax"); 575 } 576 if (!again) { 577 struct whyle *nwp = (struct whyle *)xcalloc(1, sizeof (*nwp)); 578 579 nwp->w_start = lineloc; 580 nwp->w_end = 0; 581 nwp->w_next = whyles; 582 whyles = nwp; 583 if (intty) { 584 /* 585 * The tty preread 586 */ 587 preread_(); 588 doagain(); 589 return; 590 } 591 } 592 if (status) { 593 /* We ain't gonna loop no more, no more! */ 594 toend(); 595 } 596 } 597 598 void 599 preread_(void) 600 { 601 #ifdef TRACE 602 tprintf("TRACE- preread()\n"); 603 #endif 604 605 whyles->w_end = -1; 606 if (setintr) { 607 (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT)); 608 } 609 search(ZBREAK, 0); 610 if (setintr) { 611 (void) sigblock(sigmask(SIGINT)); 612 } 613 whyles->w_end = btell(); 614 } 615 616 void 617 doend(void) 618 { 619 620 #ifdef TRACE 621 tprintf("TRACE- doend()\n"); 622 #endif 623 if (!whyles) { 624 bferr("Not in while/foreach"); 625 } 626 whyles->w_end = btell(); 627 doagain(); 628 } 629 630 void 631 docontin(void) 632 { 633 #ifdef TRACE 634 tprintf("TRACE- docontin()\n"); 635 #endif 636 637 if (!whyles) { 638 bferr("Not in while/foreach"); 639 } 640 doagain(); 641 } 642 643 void 644 doagain(void) 645 { 646 647 #ifdef TRACE 648 tprintf("TRACE- doagain()\n"); 649 #endif 650 /* Repeating a while is simple */ 651 if (whyles->w_fename == 0) { 652 bseek(whyles->w_start); 653 return; 654 } 655 /* 656 * The foreach variable list actually has a spurious word 657 * ")" at the end of the w_fe list. Thus we are at the 658 * of the list if one word beyond this is 0. 659 */ 660 if (!whyles->w_fe[1]) { 661 dobreak(); 662 return; 663 } 664 set(whyles->w_fename, savestr(*whyles->w_fe++)); 665 bseek(whyles->w_start); 666 } 667 668 void 669 dorepeat(tchar **v, struct command *kp) 670 { 671 int i, omask; 672 673 #ifdef TRACE 674 tprintf("TRACE- dorepeat()\n"); 675 #endif 676 i = getn(v[1]); 677 if (setintr) { 678 omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); 679 } 680 lshift(v, 2); 681 while (i > 0) { 682 if (setintr) { 683 (void) sigsetmask(omask); 684 } 685 reexecute(kp); 686 --i; 687 } 688 donefds(); 689 if (setintr) { 690 (void) sigsetmask(omask); 691 } 692 } 693 694 void 695 doswbrk(void) 696 { 697 698 #ifdef TRACE 699 tprintf("TRACE- doswbrk()\n"); 700 #endif 701 search(ZBRKSW, 0); 702 } 703 704 int 705 srchx(tchar *cp) 706 { 707 struct srch *sp, *sp1, *sp2; 708 int i; 709 710 #ifdef TRACE 711 tprintf("TRACE- srchx()\n"); 712 #endif 713 /* 714 * Binary search 715 * Sp1 is the beginning of the current search range. 716 * Sp2 is one past the end. 717 */ 718 for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2; ) { 719 sp = sp1 + (sp2 - sp1 >> 1); 720 if ((i = *cp - *sp->s_name) == 0 && 721 (i = strcmp_(cp, sp->s_name)) == 0) { 722 return (sp->s_value); 723 } 724 if (i < 0) { 725 sp2 = sp; 726 } else { 727 sp1 = sp + 1; 728 } 729 } 730 return (-1); 731 } 732 733 tchar Stype; 734 tchar *Sgoal; 735 736 /*VARARGS2*/ 737 void 738 search(type, level, goal) 739 int type; int level; tchar *goal; 740 { 741 tchar wordbuf[BUFSIZ]; 742 tchar *aword = wordbuf; 743 tchar *cp; 744 745 #ifdef TRACE 746 tprintf("TRACE- search()\n"); 747 #endif 748 Stype = type; Sgoal = goal; 749 if (type == ZGOTO) { 750 bseek((off_t)0); 751 } 752 do { 753 if (intty && fseekp == feobp) { 754 printf("? "), flush(); 755 } 756 aword[0] = 0; 757 (void) getword(aword); 758 759 switch (srchx(aword)) { 760 761 case ZELSE: 762 if (level == 0 && type == ZIF) { 763 return; 764 } 765 break; 766 767 case ZIF: 768 while (getword(aword)) { 769 continue; 770 } 771 if ((type == ZIF || type == ZELSE) && 772 eq(aword, S_then)) { 773 level++; 774 } 775 break; 776 777 case ZENDIF: 778 if (type == ZIF || type == ZELSE) { 779 level--; 780 } 781 break; 782 783 case ZFOREACH: 784 case ZWHILE: 785 if (type == ZBREAK) { 786 level++; 787 } 788 break; 789 790 case ZEND: 791 if (type == ZBREAK) { 792 level--; 793 } 794 break; 795 796 case ZSWITCH: 797 if (type == ZSWITCH || type == ZBRKSW) { 798 level++; 799 } 800 break; 801 802 case ZENDSW: 803 if (type == ZSWITCH || type == ZBRKSW) { 804 level--; 805 } 806 break; 807 808 case ZLABEL: 809 if (type == ZGOTO && getword(aword) && 810 eq(aword, goal)) { 811 level = -1; 812 } 813 break; 814 815 default: 816 if (type != ZGOTO && (type != ZSWITCH || level != 0)) { 817 break; 818 } 819 if (lastchr(aword) != ':') { 820 break; 821 } 822 aword[strlen_(aword) - 1] = 0; 823 if (type == ZGOTO && eq(aword, goal) || 824 type == ZSWITCH && eq(aword, S_default)) { 825 level = -1; 826 } 827 break; 828 829 case ZCASE: 830 if (type != ZSWITCH || level != 0) { 831 break; 832 } 833 (void) getword(aword); 834 if (lastchr(aword) == ':') { 835 aword[strlen_(aword) - 1] = 0; 836 } 837 cp = strip(Dfix1(aword)); 838 if (Gmatch(goal, cp)) { 839 level = -1; 840 } 841 xfree(cp); 842 break; 843 844 case ZDEFAULT: 845 if (type == ZSWITCH && level == 0) { 846 level = -1; 847 } 848 break; 849 } 850 (void) getword(NOSTR); 851 } while (level >= 0); 852 } 853 854 int 855 getword(tchar *wp) 856 { 857 int found = 0; 858 int c, d; 859 #ifdef TRACE 860 tprintf("TRACE- getword()\n"); 861 #endif 862 863 c = readc(1); 864 d = 0; 865 do { 866 while (issp(c)) { 867 c = readc(1); 868 } 869 if (c == '#') { 870 do { 871 c = readc(1); 872 } while (c >= 0 && c != '\n'); 873 } 874 if (c < 0) { 875 goto past; 876 } 877 if (c == '\n') { 878 if (wp) { 879 break; 880 } 881 return (0); 882 } 883 884 /* ( and ) form separate words */ 885 if (c == '(' || c == ')') { 886 return (1); 887 } 888 889 unreadc(c); 890 found = 1; 891 do { 892 c = readc(1); 893 if (c == '\\' && (c = readc(1)) == '\n') { 894 c = ' '; 895 } 896 if (c == '\'' || c == '"') { 897 if (d == 0) { 898 d = c; 899 } else if (d == c) { 900 d = 0; 901 } 902 } 903 if (c < 0) { 904 goto past; 905 } 906 if (wp) { 907 *wp++ = c; 908 } 909 } while ((d || !issp(c) && c != '(' && c != ')') && c != '\n'); 910 } while (wp == 0); 911 unreadc(c); 912 if (found) { 913 *--wp = 0; 914 } 915 return (found); 916 917 past: 918 switch (Stype) { 919 920 case ZIF: 921 bferr("then/endif not found"); 922 923 case ZELSE: 924 bferr("endif not found"); 925 926 case ZBRKSW: 927 case ZSWITCH: 928 bferr("endsw not found"); 929 930 case ZBREAK: 931 bferr("end not found"); 932 933 case ZGOTO: 934 setname(Sgoal); 935 bferr("label not found"); 936 } 937 /*NOTREACHED*/ 938 939 return (0); 940 } 941 942 void 943 toend(void) 944 { 945 946 #ifdef TRACE 947 tprintf("TRACE- toend()\n"); 948 #endif 949 if (whyles->w_end == 0) { 950 search(ZBREAK, 0); 951 whyles->w_end = btell() - 1; 952 } else { 953 bseek(whyles->w_end); 954 } 955 wfree(); 956 } 957 958 void 959 wfree(void) 960 { 961 long o = btell(); 962 963 #ifdef TRACE 964 tprintf("TRACE- wfree()\n"); 965 #endif 966 while (whyles) { 967 struct whyle *wp = whyles; 968 struct whyle *nwp = wp->w_next; 969 970 if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) { 971 break; 972 } 973 if (wp->w_fe0) { 974 blkfree(wp->w_fe0); 975 } 976 if (wp->w_fename) { 977 xfree(wp->w_fename); 978 } 979 xfree((char *)wp); 980 whyles = nwp; 981 } 982 } 983 984 void 985 doecho(tchar **v) 986 { 987 988 #ifdef TRACE 989 tprintf("TRACE- doecho()\n"); 990 #endif 991 echo(' ', v); 992 } 993 994 void 995 doglob(tchar **v) 996 { 997 998 #ifdef TRACE 999 tprintf("TRACE- doglob()\n"); 1000 #endif 1001 echo(0, v); 1002 flush(); 1003 } 1004 1005 void 1006 echo(tchar sep, tchar **v) 1007 { 1008 tchar *cp; 1009 int nonl = 0; 1010 1011 #ifdef TRACE 1012 tprintf("TRACE- echo()\n"); 1013 #endif 1014 if (setintr) { 1015 (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT)); 1016 } 1017 v++; 1018 if (*v == 0) { 1019 /* 1020 * echo command needs to have newline when there are no 1021 * flags or arguments. glob should have no newline. If 1022 * the separator is a blank, we are doing an echo. If the 1023 * separator is zero, we are globbing. 1024 */ 1025 if (sep == (tchar)' ') 1026 Putchar('\n'); 1027 return; 1028 } 1029 gflag = 0, tglob(v); 1030 if (gflag) { 1031 v = glob(v); 1032 if (v == 0) { 1033 bferr("No match"); 1034 } 1035 } 1036 /* check for -n arg, NOTE: it might be quoted */ 1037 if (sep == ' ' && *v && strlen_(*v) == 2 && 1038 ((**v&TRIM) == '-' && (*(*v + 1) & TRIM) == 'n' && 1039 (*(*v+2)&TRIM) == 0)) { 1040 nonl++, v++; 1041 } 1042 while (cp = *v++) { 1043 int c; 1044 1045 while (c = *cp++) { 1046 Putchar(c | QUOTE); 1047 } 1048 if (*v) { 1049 Putchar(sep | QUOTE); 1050 } 1051 } 1052 if (sep && nonl == 0) { 1053 Putchar('\n'); 1054 } else { 1055 flush(); 1056 } 1057 if (setintr) { 1058 (void) sigblock(sigmask(SIGINT)); 1059 } 1060 if (gargv) { 1061 blkfree(gargv), gargv = 0; 1062 } 1063 } 1064 1065 extern char **environ; 1066 1067 /* 1068 * Check if the environment variable vp affects this csh's behavior 1069 * and therefore we should call setlocale() or not. 1070 * This function has two side effects when it returns 1: 1071 * variable islocalevar_catnum is set to the LC_xxx value. 1072 * variable islocalevar_catname is set to the string "LC_xxx" 1073 */ 1074 static int islocalevar_catnum; 1075 static char *islocalevar_catname; 1076 1077 static 1078 bool 1079 islocalevar(tchar *vp) 1080 { 1081 static struct lcinfo { 1082 tchar * evname; /* The name of the env. var. */ 1083 } categories_we_care[] = { 1084 S_LANG, S_LC_ALL, S_LC_CTYPE, S_LC_MESSAGES, 1085 NOSTR /* assumption: LC_xxx >= 0 */ 1086 }; 1087 struct lcinfo *p = categories_we_care; 1088 1089 do { 1090 if (strcmp_(vp, p->evname) == 0) { 1091 return (1); 1092 } 1093 } while (((++p)->evname) != NOSTR); 1094 return (0); 1095 } 1096 1097 void 1098 dosetenv(tchar **v) 1099 { 1100 tchar *vp, *lp; 1101 1102 #ifdef TRACE 1103 tprintf("TRACE- dosetenv()\n"); 1104 #endif 1105 v++; 1106 if ((vp = *v++) == 0) { 1107 char **ep; 1108 1109 if (setintr) { 1110 (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT)); 1111 } 1112 for (ep = environ; *ep; ep++) { 1113 printf("%s\n", *ep); 1114 } 1115 return; 1116 } 1117 1118 if ((lp = *v++) == 0) { 1119 lp = S_; /* "" */ 1120 } 1121 local_setenv(vp, lp = globone(lp)); 1122 if (eq(vp, S_PATH)) { 1123 importpath(lp); 1124 dohash(xhash); 1125 } else if (islocalevar(vp)) { 1126 if (!setlocale(LC_ALL, "")) { 1127 error("Locale could not be set properly"); 1128 } 1129 } 1130 1131 xfree(lp); 1132 } 1133 1134 void 1135 dounsetenv(tchar **v) 1136 { 1137 #ifdef TRACE 1138 tprintf("TRACE- dounsetenv()\n"); 1139 #endif 1140 v++; 1141 do { 1142 local_unsetenv(*v); 1143 if (islocalevar(*v++)) { 1144 setlocale(LC_ALL, ""); /* Hope no error! */ 1145 } 1146 } while (*v); 1147 } 1148 1149 void 1150 local_setenv(tchar *name, tchar *val) 1151 { 1152 char **ep = environ; 1153 tchar *cp; 1154 char *dp; 1155 tchar *ep_; /* temporary */ 1156 char *blk[2], **oep = ep; 1157 1158 #ifdef TRACE 1159 /* tprintf("TRACE- local_setenv(%t, %t)\n", name, val); */ 1160 /* printf("IN local_setenv args = (%t)\n", val); */ 1161 #endif 1162 for (; *ep; ep++) { 1163 #ifdef MBCHAR 1164 for (cp = name, dp = *ep; *cp && *dp; cp++) { 1165 /* 1166 * This loop compares two chars in different 1167 * representations, EUC (as char *) and wchar_t 1168 * (in tchar), and ends when they are different. 1169 */ 1170 wchar_t dwc; 1171 int n; 1172 1173 n = mbtowc(&dwc, dp, MB_CUR_MAX); 1174 if (n <= 0) { 1175 break; /* Illegal multibyte. */ 1176 } 1177 dp += n; /* Advance to next multibyte char. */ 1178 if (dwc == (wchar_t)(*cp & TRIM)) { 1179 continue; 1180 } else { 1181 break; 1182 } 1183 } 1184 #else /* !MBCHAR */ 1185 for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) { 1186 continue; 1187 } 1188 #endif /* !MBCHAR */ 1189 if (*cp != 0 || *dp != '=') { 1190 continue; 1191 } 1192 cp = strspl(S_EQ, val); 1193 xfree(*ep); 1194 ep_ = strspl(name, cp); /* ep_ is xalloc'ed */ 1195 xfree(cp); 1196 /* 1197 * Trimming is not needed here. 1198 * trim(); 1199 */ 1200 *ep = tstostr(NULL, ep_); 1201 xfree(ep_); /* because temp. use */ 1202 return; 1203 } 1204 ep_ = strspl(name, S_EQ); /* ep_ is xalloc'ed */ 1205 blk[0] = tstostr(NULL, ep_); 1206 blk[1] = 0; 1207 xfree(ep_); 1208 environ = (char **)blkspl_((char **)environ, blk); 1209 xfree((void *)oep); 1210 local_setenv(name, val); 1211 } 1212 1213 void 1214 local_unsetenv(tchar *name) 1215 { 1216 char **ep = environ; 1217 tchar *cp; 1218 char *dp; 1219 char **oep = ep; 1220 char *cp_; /* tmp use */ 1221 static int cnt = 0; /* delete counter */ 1222 1223 #ifdef TRACE 1224 tprintf("TRACE- local_unsetenv()\n"); 1225 #endif 1226 for (; *ep; ep++) { 1227 #ifdef MBCHAR 1228 for (cp = name, dp = *ep; *cp && *dp; cp++) { 1229 /* 1230 * This loop compares two chars in different 1231 * representations, EUC (as char *) and wchar_t 1232 * (in tchar), and ends when they are different. 1233 */ 1234 wchar_t dwc; 1235 int n; 1236 1237 n = mbtowc(&dwc, dp, MB_CUR_MAX); 1238 if (n <= 0) { 1239 break; /* Illegal multibyte. */ 1240 } 1241 dp += n; /* Advance to next multibyte char. */ 1242 if (dwc == (wchar_t)(*cp & TRIM)) { 1243 continue; 1244 } else { 1245 break; 1246 } 1247 } 1248 #else /* !MBCHAR */ 1249 for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) { 1250 continue; 1251 } 1252 #endif /* !MBCHAR */ 1253 if (*cp != 0 || *dp != '=') { 1254 continue; 1255 } 1256 cp_ = *ep; 1257 *ep = 0; 1258 environ = (char **)blkspl_((char **)environ, ep+1); 1259 *ep = cp_; 1260 xfree(cp_); 1261 xfree((void *)oep); 1262 return; 1263 } 1264 } 1265 1266 void 1267 doumask(tchar **v) 1268 { 1269 tchar *cp = v[1]; 1270 int i; 1271 1272 #ifdef TRACE 1273 tprintf("TRACE- dounmask()\n"); 1274 #endif 1275 if (cp == 0) { 1276 i = umask(0); 1277 (void) umask(i); 1278 printf("%o\n", i); 1279 return; 1280 } 1281 i = 0; 1282 while (digit(*cp) && *cp != '8' && *cp != '9') { 1283 i = i * 8 + *cp++ - '0'; 1284 } 1285 if (*cp || i < 0 || i > 0777) { 1286 bferr("Improper mask"); 1287 } 1288 (void) umask(i); 1289 } 1290 1291 1292 struct limits * 1293 findlim(tchar *cp) 1294 { 1295 struct limits *lp, *res; 1296 1297 #ifdef TRACE 1298 tprintf("TRACE- findlim()\n"); 1299 #endif 1300 res = 0; 1301 for (lp = limits; lp->limconst >= 0; lp++) { 1302 if (prefix(cp, lp->limname)) { 1303 if (res) { 1304 bferr("Ambiguous"); 1305 } 1306 res = lp; 1307 } 1308 } 1309 if (res) { 1310 return (res); 1311 } 1312 bferr("No such limit"); 1313 /*NOTREACHED*/ 1314 } 1315 1316 void 1317 dolimit(tchar **v) 1318 { 1319 struct limits *lp; 1320 rlim_t limit; 1321 tchar hard = 0; 1322 1323 #ifdef TRACE 1324 tprintf("TRACE- dolimit()\n"); 1325 #endif 1326 v++; 1327 if (*v && eq(*v, S_h)) { 1328 hard = 1; 1329 v++; 1330 } 1331 if (*v == 0) { 1332 for (lp = limits; lp->limconst >= 0; lp++) { 1333 plim(lp, hard); 1334 } 1335 return; 1336 } 1337 lp = findlim(v[0]); 1338 if (v[1] == 0) { 1339 plim(lp, hard); 1340 return; 1341 } 1342 switch (getval(lp, v+1, &limit)) { 1343 case 0: 1344 error("Value specified for limit is too large"); 1345 return; 1346 case (-1): 1347 error("Numeric conversion failed"); 1348 return; 1349 default: 1350 if (setlim(lp, hard, limit) < 0) { 1351 error(NOSTR); 1352 } 1353 } 1354 } 1355 1356 static int 1357 getval(struct limits *lp, tchar **v, rlim_t *retval) 1358 { 1359 rlim_t value, tmp, tmp2; 1360 tchar *cp = *v++; 1361 char chbuf[BUFSIZ * MB_LEN_MAX]; 1362 1363 #ifdef TRACE 1364 tprintf("TRACE- getval()\n"); 1365 #endif 1366 1367 tstostr(chbuf, cp); 1368 errno = 0; 1369 value = strtoull(chbuf, NULL, 0); 1370 /* 1371 * we must accept zero, but the conversion can fail and give us 1372 * zero as well...try to deal with it as gracefully as possible 1373 * by checking for EINVAL 1374 */ 1375 if (value == 0 && errno == EINVAL) 1376 return (-1); 1377 1378 while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') { 1379 cp++; 1380 } 1381 if (*cp == 0) { 1382 if (*v == 0) { 1383 tmp = value * (rlim_t)lp->limdiv; 1384 /* Check for overflow */ 1385 if (tmp >= value) { 1386 *retval = tmp; 1387 return (1); 1388 } else { 1389 return (0); 1390 } 1391 } 1392 cp = *v; 1393 } 1394 switch (*cp) { 1395 1396 case ':': 1397 if (lp->limconst != RLIMIT_CPU) { 1398 goto badscal; 1399 } 1400 tstostr(chbuf, cp + 1); 1401 tmp = strtoull(chbuf, NULL, 0); 1402 tmp2 = value * 60 + tmp; 1403 if (tmp2 >= value) { 1404 *retval = tmp2; 1405 return (1); 1406 } else { 1407 return (0); 1408 } 1409 1410 case 'h': 1411 if (lp->limconst != RLIMIT_CPU) { 1412 goto badscal; 1413 } 1414 limtail(cp, S_hours); 1415 tmp = value * 3600; 1416 if (tmp < value) { 1417 return (0); 1418 } 1419 value = tmp; 1420 break; 1421 1422 case 'm': 1423 if (lp->limconst == RLIMIT_CPU) { 1424 limtail(cp, S_minutes); 1425 tmp = value * 60; 1426 if (tmp < value) { 1427 return (0); 1428 } 1429 value = tmp; 1430 break; 1431 } 1432 case 'M': 1433 if (lp->limconst == RLIMIT_CPU) { 1434 goto badscal; 1435 } 1436 *cp = 'm'; 1437 limtail(cp, S_megabytes); 1438 tmp = value * 1024 * 1024; 1439 if (tmp < value) { 1440 return (0); 1441 } 1442 value = tmp; 1443 break; 1444 1445 case 's': 1446 if (lp->limconst != RLIMIT_CPU) { 1447 goto badscal; 1448 } 1449 limtail(cp, S_seconds); 1450 break; 1451 1452 case 'k': 1453 if (lp->limconst == RLIMIT_CPU) { 1454 goto badscal; 1455 } 1456 limtail(cp, S_kbytes); 1457 tmp = value * 1024; 1458 if (tmp < value) { 1459 return (0); 1460 } 1461 value = tmp; 1462 break; 1463 1464 case 'u': 1465 limtail(cp, S_unlimited); 1466 *retval = RLIM_INFINITY; 1467 return (1); 1468 1469 default: 1470 badscal: 1471 bferr("Improper or unknown scale factor"); 1472 } 1473 *retval = value; 1474 return (1); 1475 } 1476 1477 void 1478 limtail(tchar *cp, tchar *str0) 1479 { 1480 tchar *str = str0; 1481 #ifdef TRACE 1482 tprintf("TRACE- limtail()\n"); 1483 #endif 1484 1485 while (*cp && *cp == *str) { 1486 cp++, str++; 1487 } 1488 if (*cp) { 1489 error("Bad scaling; did you mean ``%t''?", str0); 1490 } 1491 } 1492 1493 void 1494 plim(struct limits *lp, tchar hard) 1495 { 1496 struct rlimit rlim; 1497 char buf[BUFSZ]; 1498 char *pbuf; 1499 rlim_t limit; 1500 1501 #ifdef TRACE 1502 tprintf("TRACE- plim()\n"); 1503 #endif 1504 printf("%t \t", lp->limname); 1505 (void) getrlimit(lp->limconst, &rlim); 1506 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 1507 if (limit == RLIM_INFINITY) { 1508 printf("unlimited"); 1509 } else if (lp->limconst == RLIMIT_CPU) { 1510 psecs_ull(limit); 1511 } else { 1512 buf[BUFSZ - 1] = '\0'; 1513 pbuf = ulltostr((limit / lp->limdiv), &buf[BUFSZ - 1]); 1514 printf("%s %t", pbuf, lp->limscale); 1515 } 1516 printf("\n"); 1517 } 1518 1519 void 1520 dounlimit(tchar **v) 1521 { 1522 struct limits *lp; 1523 int err = 0; 1524 tchar hard = 0; 1525 #ifdef TRACE 1526 tprintf("TRACE- dounlimit()\n"); 1527 #endif 1528 1529 v++; 1530 if (*v && eq(*v, S_h)) { 1531 hard = 1; 1532 v++; 1533 } 1534 if (*v == 0) { 1535 for (lp = limits; lp->limconst >= 0; lp++) { 1536 if (setlim(lp, hard, RLIM_INFINITY) < 0) { 1537 err++; 1538 } 1539 } 1540 if (err) { 1541 error(NULL); 1542 } 1543 return; 1544 } 1545 while (*v) { 1546 lp = findlim(*v++); 1547 if (setlim(lp, hard, RLIM_INFINITY) < 0) { 1548 error(NULL); 1549 } 1550 } 1551 } 1552 1553 int 1554 setlim(struct limits *lp, tchar hard, rlim_t limit) 1555 { 1556 struct rlimit rlim; 1557 1558 #ifdef TRACE 1559 tprintf("TRACE- setlim()\n"); 1560 #endif 1561 (void) getrlimit(lp->limconst, &rlim); 1562 if (hard) { 1563 rlim.rlim_max = limit; 1564 } else if (limit == RLIM_INFINITY && geteuid() != 0) { 1565 rlim.rlim_cur = rlim.rlim_max; 1566 } else { 1567 rlim.rlim_cur = limit; 1568 } 1569 if (setrlimit(lp->limconst, &rlim) < 0) { 1570 printf("%t: %t: Can't %s%s limit\n", bname, lp->limname, 1571 limit == RLIM_INFINITY ? "remove" : "set", 1572 hard ? " hard" : ""); 1573 return (-1); 1574 } 1575 return (0); 1576 } 1577 1578 void 1579 dosuspend() 1580 { 1581 int ctpgrp; 1582 void (*old)(); 1583 1584 #ifdef TRACE 1585 tprintf("TRACE- dosuspend()\n"); 1586 #endif 1587 if (loginsh) { 1588 error("Can't suspend a login shell (yet)"); 1589 } 1590 if (getpid() == getsid(0)) { 1591 error("Can't suspend this shell"); 1592 } 1593 untty(); 1594 old = (void (*)())signal(SIGTSTP, SIG_DFL); 1595 (void) kill(0, SIGTSTP); 1596 /* the shell stops here */ 1597 (void) signal(SIGTSTP, old); 1598 if (tpgrp != -1) { 1599 retry: 1600 (void) ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp); 1601 if (ctpgrp != opgrp) { 1602 old = (void (*)())signal(SIGTTIN, SIG_DFL); 1603 (void) kill(0, SIGTTIN); 1604 (void) signal(SIGTTIN, old); 1605 goto retry; 1606 } 1607 (void) setpgid(0, shpgrp); 1608 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp); 1609 } 1610 } 1611 1612 void 1613 doeval(tchar **v) 1614 { 1615 tchar **oevalvec = evalvec; 1616 tchar *oevalp = evalp; 1617 jmp_buf osetexit; 1618 int reenter; 1619 tchar **gv = 0; 1620 1621 #ifdef TRACE 1622 tprintf("TRACE- doeval()\n"); 1623 #endif 1624 v++; 1625 if (*v == 0) { 1626 return; 1627 } 1628 gflag = 0, tglob(v); 1629 if (gflag) { 1630 gv = v = glob(v); 1631 gargv = 0; 1632 if (v == 0) { 1633 error("No match"); 1634 } 1635 v = copyblk(v); 1636 } else { 1637 trim(v); 1638 } 1639 getexit(osetexit); 1640 reenter = 0; 1641 setexit(); 1642 reenter++; 1643 if (reenter == 1) { 1644 evalvec = v; 1645 evalp = 0; 1646 process(0); 1647 } 1648 evalvec = oevalvec; 1649 evalp = oevalp; 1650 doneinp = 0; 1651 if (gv) { 1652 blkfree(gv); 1653 } 1654 resexit(osetexit); 1655 if (reenter >= 2) { 1656 error(NULL); 1657 } 1658 } 1659