1 /* $OpenBSD: func.c,v 1.24 2004/08/08 12:55:28 millert Exp $ */ 2 /* $NetBSD: func.c,v 1.11 1996/02/09 02:28:29 christos Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)func.c 8.1 (Berkeley) 5/31/93"; 36 #else 37 static char rcsid[] = "$OpenBSD: func.c,v 1.24 2004/08/08 12:55:28 millert Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <signal.h> 44 #include <locale.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <stdarg.h> 49 50 #include "csh.h" 51 #include "extern.h" 52 #include "pathnames.h" 53 54 extern char **environ; 55 56 static int zlast = -1; 57 static void islogin(void); 58 static void reexecute(struct command *); 59 static void preread(void); 60 static void doagain(void); 61 static void search(int, int, Char *); 62 static int getword(Char *); 63 static int keyword(Char *); 64 static void toend(void); 65 static void xecho(int, Char **); 66 static void Unsetenv(Char *); 67 68 struct biltins * 69 isbfunc(struct command *t) 70 { 71 Char *cp = t->t_dcom[0]; 72 struct biltins *bp, *bp1, *bp2; 73 static struct biltins label = {"", dozip, 0, 0}; 74 static struct biltins foregnd = {"%job", dofg1, 0, 0}; 75 static struct biltins backgnd = {"%job &", dobg1, 0, 0}; 76 77 if (lastchr(cp) == ':') { 78 label.bname = short2str(cp); 79 return (&label); 80 } 81 if (*cp == '%') { 82 if (t->t_dflg & F_AMPERSAND) { 83 t->t_dflg &= ~F_AMPERSAND; 84 backgnd.bname = short2str(cp); 85 return (&backgnd); 86 } 87 foregnd.bname = short2str(cp); 88 return (&foregnd); 89 } 90 /* 91 * Binary search Bp1 is the beginning of the current search range. Bp2 is 92 * one past the end. 93 */ 94 for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 95 int i; 96 97 bp = bp1 + ((bp2 - bp1) >> 1); 98 if ((i = *cp - *bp->bname) == 0 && 99 (i = Strcmp(cp, str2short(bp->bname))) == 0) 100 return bp; 101 if (i < 0) 102 bp2 = bp; 103 else 104 bp1 = bp + 1; 105 } 106 return (0); 107 } 108 109 void 110 func(struct command *t, struct biltins *bp) 111 { 112 int i; 113 114 xechoit(t->t_dcom); 115 setname(bp->bname); 116 i = blklen(t->t_dcom) - 1; 117 if (i < bp->minargs) 118 stderror(ERR_NAME | ERR_TOOFEW); 119 if (i > bp->maxargs) 120 stderror(ERR_NAME | ERR_TOOMANY); 121 (*bp->bfunct) (t->t_dcom, t); 122 } 123 124 void 125 /*ARGSUSED*/ 126 doonintr(Char **v, struct command *t) 127 { 128 Char *cp; 129 Char *vv = v[1]; 130 sigset_t sigset; 131 132 if (parintr == SIG_IGN) 133 return; 134 if (setintr && intty) 135 stderror(ERR_NAME | ERR_TERMINAL); 136 cp = gointr; 137 gointr = 0; 138 xfree((ptr_t) cp); 139 if (vv == 0) { 140 if (setintr) { 141 sigemptyset(&sigset); 142 sigaddset(&sigset, SIGINT); 143 sigprocmask(SIG_BLOCK, &sigset, NULL); 144 } else 145 (void) signal(SIGINT, SIG_DFL); 146 gointr = 0; 147 } 148 else if (eq((vv = strip(vv)), STRminus)) { 149 (void) signal(SIGINT, SIG_IGN); 150 gointr = Strsave(STRminus); 151 } 152 else { 153 gointr = Strsave(vv); 154 (void) signal(SIGINT, pintr); 155 } 156 } 157 158 void 159 /*ARGSUSED*/ 160 donohup(Char **v, struct command *t) 161 { 162 if (intty) 163 stderror(ERR_NAME | ERR_TERMINAL); 164 if (setintr == 0) { 165 (void) signal(SIGHUP, SIG_IGN); 166 } 167 } 168 169 void 170 /*ARGSUSED*/ 171 dozip(Char **v, struct command *t) 172 { 173 ; 174 } 175 176 void 177 prvars(void) 178 { 179 plist(&shvhed); 180 } 181 182 void 183 /*ARGSUSED*/ 184 doalias(Char **v, struct command *t) 185 { 186 struct varent *vp; 187 Char *p; 188 189 v++; 190 p = *v++; 191 if (p == 0) 192 plist(&aliases); 193 else if (*v == 0) { 194 vp = adrof1(strip(p), &aliases); 195 if (vp) { 196 blkpr(cshout, vp->vec); 197 fputc('\n', cshout); 198 } 199 } 200 else { 201 if (eq(p, STRalias) || eq(p, STRunalias)) { 202 setname(vis_str(p)); 203 stderror(ERR_NAME | ERR_DANGER); 204 } 205 set1(strip(p), saveblk(v), &aliases); 206 } 207 } 208 209 void 210 /*ARGSUSED*/ 211 unalias(Char **v, struct command *t) 212 { 213 unset1(v, &aliases); 214 } 215 216 void 217 /*ARGSUSED*/ 218 dologout(Char **v, struct command *t) 219 { 220 islogin(); 221 goodbye(); 222 } 223 224 void 225 /*ARGSUSED*/ 226 dologin(Char **v, struct command *t) 227 { 228 islogin(); 229 rechist(); 230 (void) signal(SIGTERM, parterm); 231 (void) execl(_PATH_LOGIN, "login", short2str(v[1]), (char *)NULL); 232 untty(); 233 xexit(1); 234 } 235 236 static void 237 islogin(void) 238 { 239 if (chkstop == 0 && setintr) 240 panystop(0); 241 if (loginsh) 242 return; 243 stderror(ERR_NOTLOGIN); 244 } 245 246 void 247 doif(Char **v, struct command *kp) 248 { 249 int i; 250 Char **vv; 251 252 v++; 253 i = expr(&v); 254 vv = v; 255 if (*vv == NULL) 256 stderror(ERR_NAME | ERR_EMPTYIF); 257 if (eq(*vv, STRthen)) { 258 if (*++vv) 259 stderror(ERR_NAME | ERR_IMPRTHEN); 260 setname(vis_str(STRthen)); 261 /* 262 * If expression was zero, then scan to else, otherwise just fall into 263 * following code. 264 */ 265 if (!i) 266 search(T_IF, 0, NULL); 267 return; 268 } 269 /* 270 * Simple command attached to this if. Left shift the node in this tree, 271 * munging it so we can reexecute it. 272 */ 273 if (i) { 274 lshift(kp->t_dcom, vv - kp->t_dcom); 275 reexecute(kp); 276 donefds(); 277 } 278 } 279 280 /* 281 * Reexecute a command, being careful not 282 * to redo i/o redirection, which is already set up. 283 */ 284 static void 285 reexecute(struct command *kp) 286 { 287 kp->t_dflg &= F_SAVE; 288 kp->t_dflg |= F_REPEAT; 289 /* 290 * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set 291 * pgrp's as the jobs would then have no way to get the tty (we can't give 292 * it to them, and our parent wouldn't know their pgrp, etc. 293 */ 294 execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL); 295 } 296 297 void 298 /*ARGSUSED*/ 299 doelse(Char **v, struct command *t) 300 { 301 search(T_ELSE, 0, NULL); 302 } 303 304 void 305 /*ARGSUSED*/ 306 dogoto(Char **v, struct command *t) 307 { 308 Char *lp; 309 310 gotolab(lp = globone(v[1], G_ERROR)); 311 xfree((ptr_t) lp); 312 } 313 314 void 315 gotolab(Char *lab) 316 { 317 struct whyle *wp; 318 /* 319 * While we still can, locate any unknown ends of existing loops. This 320 * obscure code is the WORST result of the fact that we don't really parse. 321 */ 322 zlast = T_GOTO; 323 for (wp = whyles; wp; wp = wp->w_next) 324 if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) { 325 search(T_BREAK, 0, NULL); 326 btell(&wp->w_end); 327 } 328 else 329 bseek(&wp->w_end); 330 search(T_GOTO, 0, lab); 331 /* 332 * Eliminate loops which were exited. 333 */ 334 wfree(); 335 } 336 337 void 338 /*ARGSUSED*/ 339 doswitch(Char **v, struct command *t) 340 { 341 Char *cp, *lp; 342 343 v++; 344 if (!*v || *(*v++) != '(') 345 stderror(ERR_SYNTAX); 346 cp = **v == ')' ? STRNULL : *v++; 347 if (*(*v++) != ')') 348 v--; 349 if (*v) 350 stderror(ERR_SYNTAX); 351 search(T_SWITCH, 0, lp = globone(cp, G_ERROR)); 352 xfree((ptr_t) lp); 353 } 354 355 void 356 /*ARGSUSED*/ 357 dobreak(Char **v, struct command *t) 358 { 359 if (whyles) 360 toend(); 361 else 362 stderror(ERR_NAME | ERR_NOTWHILE); 363 } 364 365 void 366 /*ARGSUSED*/ 367 doexit(Char **v, struct command *t) 368 { 369 if (chkstop == 0 && (intty || intact) && evalvec == 0) 370 panystop(0); 371 /* 372 * Don't DEMAND parentheses here either. 373 */ 374 v++; 375 if (*v) { 376 set(STRstatus, putn(expr(&v))); 377 if (*v) 378 stderror(ERR_NAME | ERR_EXPRESSION); 379 } 380 btoeof(); 381 if (intty) 382 (void) close(SHIN); 383 } 384 385 void 386 /*ARGSUSED*/ 387 doforeach(Char **v, struct command *t) 388 { 389 Char *cp, *sp; 390 struct whyle *nwp; 391 392 v++; 393 sp = cp = strip(*v); 394 if (!letter(*sp)) 395 stderror(ERR_NAME | ERR_VARBEGIN); 396 while (*cp && alnum(*cp)) 397 cp++; 398 if (*cp) 399 stderror(ERR_NAME | ERR_VARALNUM); 400 if ((cp - sp) > MAXVARLEN) 401 stderror(ERR_NAME | ERR_VARTOOLONG); 402 cp = *v++; 403 if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 404 stderror(ERR_NAME | ERR_NOPAREN); 405 v++; 406 gflag = 0, tglob(v); 407 v = globall(v); 408 if (v == 0) 409 stderror(ERR_NAME | ERR_NOMATCH); 410 nwp = (struct whyle *) xcalloc(1, sizeof *nwp); 411 nwp->w_fe = nwp->w_fe0 = v; 412 gargv = 0; 413 btell(&nwp->w_start); 414 nwp->w_fename = Strsave(cp); 415 nwp->w_next = whyles; 416 nwp->w_end.type = F_SEEK; 417 whyles = nwp; 418 /* 419 * Pre-read the loop so as to be more comprehensible to a terminal user. 420 */ 421 zlast = T_FOREACH; 422 if (intty) 423 preread(); 424 doagain(); 425 } 426 427 void 428 /*ARGSUSED*/ 429 dowhile(Char **v, struct command *t) 430 { 431 int status; 432 bool again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) && 433 whyles->w_fename == 0; 434 435 v++; 436 /* 437 * Implement prereading here also, taking care not to evaluate the 438 * expression before the loop has been read up from a terminal. 439 */ 440 if (intty && !again) 441 status = !exp0(&v, 1); 442 else 443 status = !expr(&v); 444 if (*v) 445 stderror(ERR_NAME | ERR_EXPRESSION); 446 if (!again) { 447 struct whyle *nwp = 448 (struct whyle *) xcalloc(1, sizeof(*nwp)); 449 450 nwp->w_start = lineloc; 451 nwp->w_end.type = F_SEEK; 452 nwp->w_end.f_seek = 0; 453 nwp->w_next = whyles; 454 whyles = nwp; 455 zlast = T_WHILE; 456 if (intty) { 457 /* 458 * The tty preread 459 */ 460 preread(); 461 doagain(); 462 return; 463 } 464 } 465 if (status) 466 /* We ain't gonna loop no more, no more! */ 467 toend(); 468 } 469 470 static void 471 preread(void) 472 { 473 sigset_t sigset; 474 475 whyles->w_end.type = I_SEEK; 476 if (setintr) { 477 sigemptyset(&sigset); 478 sigaddset(&sigset, SIGINT); 479 sigprocmask(SIG_UNBLOCK, &sigset, NULL); 480 } 481 482 search(T_BREAK, 0, NULL); /* read the expression in */ 483 if (setintr) 484 sigprocmask(SIG_BLOCK, &sigset, NULL); 485 btell(&whyles->w_end); 486 } 487 488 void 489 /*ARGSUSED*/ 490 doend(Char **v, struct command *t) 491 { 492 if (!whyles) 493 stderror(ERR_NAME | ERR_NOTWHILE); 494 btell(&whyles->w_end); 495 doagain(); 496 } 497 498 void 499 /*ARGSUSED*/ 500 docontin(Char **v, struct command *t) 501 { 502 if (!whyles) 503 stderror(ERR_NAME | ERR_NOTWHILE); 504 doagain(); 505 } 506 507 static void 508 doagain(void) 509 { 510 /* Repeating a while is simple */ 511 if (whyles->w_fename == 0) { 512 bseek(&whyles->w_start); 513 return; 514 } 515 /* 516 * The foreach variable list actually has a spurious word ")" at the end of 517 * the w_fe list. Thus we are at the of the list if one word beyond this 518 * is 0. 519 */ 520 if (!whyles->w_fe[1]) { 521 dobreak(NULL, NULL); 522 return; 523 } 524 set(whyles->w_fename, Strsave(*whyles->w_fe++)); 525 bseek(&whyles->w_start); 526 } 527 528 void 529 dorepeat(Char **v, struct command *kp) 530 { 531 int i; 532 sigset_t sigset; 533 534 i = getn(v[1]); 535 if (setintr) { 536 sigemptyset(&sigset); 537 sigaddset(&sigset, SIGINT); 538 sigprocmask(SIG_BLOCK, &sigset, NULL); 539 } 540 lshift(v, 2); 541 while (i > 0) { 542 if (setintr) 543 sigprocmask(SIG_UNBLOCK, &sigset, NULL); 544 reexecute(kp); 545 --i; 546 } 547 donefds(); 548 if (setintr) 549 sigprocmask(SIG_UNBLOCK, &sigset, NULL); 550 } 551 552 void 553 /*ARGSUSED*/ 554 doswbrk(Char **v, struct command *t) 555 { 556 search(T_BRKSW, 0, NULL); 557 } 558 559 int 560 srchx(Char *cp) 561 { 562 struct srch *sp, *sp1, *sp2; 563 int i; 564 565 /* 566 * Binary search Sp1 is the beginning of the current search range. Sp2 is 567 * one past the end. 568 */ 569 for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 570 sp = sp1 + ((sp2 - sp1) >> 1); 571 if ((i = *cp - *sp->s_name) == 0 && 572 (i = Strcmp(cp, str2short(sp->s_name))) == 0) 573 return sp->s_value; 574 if (i < 0) 575 sp2 = sp; 576 else 577 sp1 = sp + 1; 578 } 579 return (-1); 580 } 581 582 static Char Stype; 583 static Char *Sgoal; 584 585 /*VARARGS2*/ 586 static void 587 search(int type, int level, Char *goal) 588 { 589 Char wordbuf[BUFSIZ]; 590 Char *aword = wordbuf; 591 Char *cp; 592 593 Stype = type; 594 Sgoal = goal; 595 if (type == T_GOTO) { 596 struct Ain a; 597 a.type = F_SEEK; 598 a.f_seek = 0; 599 bseek(&a); 600 } 601 do { 602 if (intty && fseekp == feobp && aret == F_SEEK) 603 (void) fprintf(cshout, "? "), (void) fflush(cshout); 604 aword[0] = 0; 605 (void) getword(aword); 606 switch (srchx(aword)) { 607 608 case T_ELSE: 609 if (level == 0 && type == T_IF) 610 return; 611 break; 612 613 case T_IF: 614 while (getword(aword)) 615 continue; 616 if ((type == T_IF || type == T_ELSE) && 617 eq(aword, STRthen)) 618 level++; 619 break; 620 621 case T_ENDIF: 622 if (type == T_IF || type == T_ELSE) 623 level--; 624 break; 625 626 case T_FOREACH: 627 case T_WHILE: 628 if (type == T_BREAK) 629 level++; 630 break; 631 632 case T_END: 633 if (type == T_BREAK) 634 level--; 635 break; 636 637 case T_SWITCH: 638 if (type == T_SWITCH || type == T_BRKSW) 639 level++; 640 break; 641 642 case T_ENDSW: 643 if (type == T_SWITCH || type == T_BRKSW) 644 level--; 645 break; 646 647 case T_LABEL: 648 if (type == T_GOTO && getword(aword) && eq(aword, goal)) 649 level = -1; 650 break; 651 652 default: 653 if (type != T_GOTO && (type != T_SWITCH || level != 0)) 654 break; 655 if (lastchr(aword) != ':') 656 break; 657 aword[Strlen(aword) - 1] = 0; 658 if ((type == T_GOTO && eq(aword, goal)) || 659 (type == T_SWITCH && eq(aword, STRdefault))) 660 level = -1; 661 break; 662 663 case T_CASE: 664 if (type != T_SWITCH || level != 0) 665 break; 666 (void) getword(aword); 667 if (lastchr(aword) == ':') 668 aword[Strlen(aword) - 1] = 0; 669 cp = strip(Dfix1(aword)); 670 if (Gmatch(goal, cp)) 671 level = -1; 672 xfree((ptr_t) cp); 673 break; 674 675 case T_DEFAULT: 676 if (type == T_SWITCH && level == 0) 677 level = -1; 678 break; 679 } 680 (void) getword(NULL); 681 } while (level >= 0); 682 } 683 684 static int 685 getword(Char *wp) 686 { 687 int found = 0; 688 int c, d; 689 int kwd = 0; 690 Char *owp = wp; 691 692 c = readc(1); 693 d = 0; 694 do { 695 while (c == ' ' || c == '\t') 696 c = readc(1); 697 if (c == '#') 698 do 699 c = readc(1); 700 while (c >= 0 && c != '\n'); 701 if (c < 0) 702 goto past; 703 if (c == '\n') { 704 if (wp) 705 break; 706 return (0); 707 } 708 unreadc(c); 709 found = 1; 710 do { 711 c = readc(1); 712 if (c == '\\' && (c = readc(1)) == '\n') 713 c = ' '; 714 if (c == '\'' || c == '"') { 715 if (d == 0) 716 d = c; 717 else if (d == c) 718 d = 0; 719 } 720 if (c < 0) 721 goto past; 722 if (wp) { 723 *wp++ = c; 724 *wp = 0; /* end the string b4 test */ 725 } 726 } while ((d || (!(kwd = keyword(owp)) && c != ' ' 727 && c != '\t')) && c != '\n'); 728 } while (wp == 0); 729 730 /* 731 * if we have read a keyword ( "if", "switch" or "while" ) then we do not 732 * need to unreadc the look-ahead char 733 */ 734 if (!kwd) { 735 unreadc(c); 736 if (found) 737 *--wp = 0; 738 } 739 740 return (found); 741 742 past: 743 switch (Stype) { 744 745 case T_IF: 746 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); 747 748 case T_ELSE: 749 stderror(ERR_NAME | ERR_NOTFOUND, "endif"); 750 751 case T_BRKSW: 752 case T_SWITCH: 753 stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); 754 755 case T_BREAK: 756 stderror(ERR_NAME | ERR_NOTFOUND, "end"); 757 758 case T_GOTO: 759 setname(vis_str(Sgoal)); 760 stderror(ERR_NAME | ERR_NOTFOUND, "label"); 761 } 762 /* NOTREACHED */ 763 return (0); 764 } 765 766 /* 767 * keyword(wp) determines if wp is one of the built-n functions if, 768 * switch or while. It seems that when an if statement looks like 769 * "if(" then getword above sucks in the '(' and so the search routine 770 * never finds what it is scanning for. Rather than rewrite doword, I hack 771 * in a test to see if the string forms a keyword. Then doword stops 772 * and returns the word "if" -strike 773 */ 774 775 static int 776 keyword(Char *wp) 777 { 778 static Char STRif[] = {'i', 'f', '\0'}; 779 static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'}; 780 static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'}; 781 782 if (!wp) 783 return (0); 784 785 if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0) 786 || (Strcmp(wp, STRswitch) == 0)) 787 return (1); 788 789 return (0); 790 } 791 792 static void 793 toend(void) 794 { 795 if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) { 796 search(T_BREAK, 0, NULL); 797 btell(&whyles->w_end); 798 whyles->w_end.f_seek--; 799 } 800 else 801 bseek(&whyles->w_end); 802 wfree(); 803 } 804 805 void 806 wfree(void) 807 { 808 struct Ain o; 809 struct whyle *nwp; 810 811 btell(&o); 812 813 for (; whyles; whyles = nwp) { 814 struct whyle *wp = whyles; 815 nwp = wp->w_next; 816 817 /* 818 * We free loops that have different seek types. 819 */ 820 if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type && 821 wp->w_start.type == o.type) { 822 if (wp->w_end.type == F_SEEK) { 823 if (o.f_seek >= wp->w_start.f_seek && 824 (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) 825 break; 826 } 827 else { 828 if (o.a_seek >= wp->w_start.a_seek && 829 (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) 830 break; 831 } 832 } 833 834 if (wp->w_fe0) 835 blkfree(wp->w_fe0); 836 if (wp->w_fename) 837 xfree((ptr_t) wp->w_fename); 838 xfree((ptr_t) wp); 839 } 840 } 841 842 void 843 /*ARGSUSED*/ 844 doecho(Char **v, struct command *t) 845 { 846 xecho(' ', v); 847 } 848 849 void 850 /*ARGSUSED*/ 851 doglob(Char **v, struct command *t) 852 { 853 xecho(0, v); 854 (void) fflush(cshout); 855 } 856 857 static void 858 xecho(int sep, Char **v) 859 { 860 Char *cp; 861 int nonl = 0; 862 sigset_t sigset; 863 864 if (setintr) { 865 sigemptyset(&sigset); 866 sigaddset(&sigset, SIGINT); 867 sigprocmask(SIG_UNBLOCK, &sigset, NULL); 868 } 869 v++; 870 if (*v == 0) 871 return; 872 gflag = 0, tglob(v); 873 if (gflag) { 874 v = globall(v); 875 if (v == 0) 876 stderror(ERR_NAME | ERR_NOMATCH); 877 } 878 else { 879 v = gargv = saveblk(v); 880 trim(v); 881 } 882 if (sep == ' ' && *v && eq(*v, STRmn)) 883 nonl++, v++; 884 while ((cp = *v++) != NULL) { 885 int c; 886 887 while ((c = *cp++) != '\0') 888 (void) vis_fputc(c | QUOTE, cshout); 889 890 if (*v) 891 (void) vis_fputc(sep | QUOTE, cshout); 892 } 893 if (sep && nonl == 0) 894 (void) fputc('\n', cshout); 895 else 896 (void) fflush(cshout); 897 if (setintr) 898 sigprocmask(SIG_BLOCK, &sigset, NULL); 899 if (gargv) 900 blkfree(gargv), gargv = 0; 901 } 902 903 void 904 /*ARGSUSED*/ 905 dosetenv(Char **v, struct command *t) 906 { 907 Char *vp, *lp; 908 sigset_t sigset; 909 910 v++; 911 if ((vp = *v++) == 0) { 912 Char **ep; 913 914 if (setintr) { 915 sigemptyset(&sigset); 916 sigaddset(&sigset, SIGINT); 917 sigprocmask(SIG_UNBLOCK, &sigset, NULL); 918 } 919 for (ep = STR_environ; *ep; ep++) 920 (void) fprintf(cshout, "%s\n", vis_str(*ep)); 921 return; 922 } 923 if ((lp = *v++) == 0) 924 lp = STRNULL; 925 Setenv(vp, lp = globone(lp, G_APPEND)); 926 if (eq(vp, STRPATH)) { 927 importpath(lp); 928 dohash(NULL, NULL); 929 } 930 else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) { 931 #ifdef NLS 932 int k; 933 934 (void) setlocale(LC_ALL, ""); 935 for (k = 0200; k <= 0377 && !Isprint(k); k++) 936 continue; 937 AsciiOnly = k > 0377; 938 #else 939 AsciiOnly = 0; 940 #endif /* NLS */ 941 } 942 xfree((ptr_t) lp); 943 } 944 945 void 946 /*ARGSUSED*/ 947 dounsetenv(Char **v, struct command *t) 948 { 949 Char **ep, *p, *n; 950 int i, maxi; 951 static Char *name = NULL; 952 953 if (name) 954 xfree((ptr_t) name); 955 /* 956 * Find the longest environment variable 957 */ 958 for (maxi = 0, ep = STR_environ; *ep; ep++) { 959 for (i = 0, p = *ep; *p && *p != '='; p++, i++) 960 continue; 961 if (i > maxi) 962 maxi = i; 963 } 964 965 name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char)); 966 967 while (++v && *v) 968 for (maxi = 1; maxi;) 969 for (maxi = 0, ep = STR_environ; *ep; ep++) { 970 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) 971 continue; 972 *n = '\0'; 973 if (!Gmatch(name, *v)) 974 continue; 975 maxi = 1; 976 if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) { 977 #ifdef NLS 978 int k; 979 980 (void) setlocale(LC_ALL, ""); 981 for (k = 0200; k <= 0377 && !Isprint(k); k++) 982 continue; 983 AsciiOnly = k > 0377; 984 #else 985 AsciiOnly = getenv("LANG") == NULL && 986 getenv("LC_CTYPE") == NULL; 987 #endif /* NLS */ 988 } 989 /* 990 * Delete name, and start again cause the environment changes 991 */ 992 Unsetenv(name); 993 break; 994 } 995 xfree((ptr_t) name); 996 name = NULL; 997 } 998 999 void 1000 Setenv(Char *name, Char *val) 1001 { 1002 Char **ep = STR_environ; 1003 Char *cp, *dp; 1004 Char *blk[2]; 1005 Char **oep = ep; 1006 1007 for (; *ep; ep++) { 1008 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1009 continue; 1010 if (*cp != 0 || *dp != '=') 1011 continue; 1012 cp = Strspl(STRequal, val); 1013 xfree((ptr_t) * ep); 1014 *ep = strip(Strspl(name, cp)); 1015 xfree((ptr_t) cp); 1016 blkfree((Char **) environ); 1017 environ = short2blk(STR_environ); 1018 return; 1019 } 1020 cp = Strspl(name, STRequal); 1021 blk[0] = strip(Strspl(cp, val)); 1022 xfree((ptr_t) cp); 1023 blk[1] = 0; 1024 STR_environ = blkspl(STR_environ, blk); 1025 blkfree((Char **) environ); 1026 environ = short2blk(STR_environ); 1027 xfree((ptr_t) oep); 1028 } 1029 1030 static void 1031 Unsetenv(Char *name) 1032 { 1033 Char **ep = STR_environ; 1034 Char *cp, *dp; 1035 Char **oep = ep; 1036 1037 for (; *ep; ep++) { 1038 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 1039 continue; 1040 if (*cp != 0 || *dp != '=') 1041 continue; 1042 cp = *ep; 1043 *ep = 0; 1044 STR_environ = blkspl(STR_environ, ep + 1); 1045 environ = short2blk(STR_environ); 1046 *ep = cp; 1047 xfree((ptr_t) cp); 1048 xfree((ptr_t) oep); 1049 return; 1050 } 1051 } 1052 1053 void 1054 /*ARGSUSED*/ 1055 doumask(Char **v, struct command *t) 1056 { 1057 Char *cp = v[1]; 1058 int i; 1059 1060 if (cp == 0) { 1061 i = umask(0); 1062 (void) umask(i); 1063 (void) fprintf(cshout, "%o\n", i); 1064 return; 1065 } 1066 i = 0; 1067 while (Isdigit(*cp) && *cp != '8' && *cp != '9') 1068 i = i * 8 + *cp++ - '0'; 1069 if (*cp || i < 0 || i > 0777) 1070 stderror(ERR_NAME | ERR_MASK); 1071 (void) umask(i); 1072 } 1073 1074 typedef quad_t RLIM_TYPE; 1075 1076 static struct limits { 1077 int limconst; 1078 char *limname; 1079 int limdiv; 1080 char *limscale; 1081 } limits[] = { 1082 { RLIMIT_CPU, "cputime", 1, "seconds" }, 1083 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, 1084 { RLIMIT_DATA, "datasize", 1024, "kbytes" }, 1085 { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, 1086 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, 1087 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, 1088 #ifdef RLIMIT_VMEM 1089 { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" }, 1090 #endif 1091 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, 1092 { RLIMIT_NPROC, "maxproc", 1, "" }, 1093 { RLIMIT_NOFILE, "openfiles", 1, "" }, 1094 { -1, NULL, 0, NULL } 1095 }; 1096 1097 static struct limits *findlim(Char *); 1098 static RLIM_TYPE getval(struct limits *, Char **); 1099 static void limtail(Char *, char *); 1100 static void plim(struct limits *, Char); 1101 static int setlim(struct limits *, Char, RLIM_TYPE); 1102 1103 static struct limits * 1104 findlim(Char *cp) 1105 { 1106 struct limits *lp, *res; 1107 1108 res = NULL; 1109 for (lp = limits; lp->limconst >= 0; lp++) 1110 if (prefix(cp, str2short(lp->limname))) { 1111 if (res) 1112 stderror(ERR_NAME | ERR_AMBIG); 1113 res = lp; 1114 } 1115 if (res) 1116 return (res); 1117 stderror(ERR_NAME | ERR_LIMIT); 1118 /* NOTREACHED */ 1119 return (0); 1120 } 1121 1122 void 1123 /*ARGSUSED*/ 1124 dolimit(Char **v, struct command *t) 1125 { 1126 struct limits *lp; 1127 RLIM_TYPE limit; 1128 char hard = 0; 1129 1130 v++; 1131 if (*v && eq(*v, STRmh)) { 1132 hard = 1; 1133 v++; 1134 } 1135 if (*v == 0) { 1136 for (lp = limits; lp->limconst >= 0; lp++) 1137 plim(lp, hard); 1138 return; 1139 } 1140 lp = findlim(v[0]); 1141 if (v[1] == 0) { 1142 plim(lp, hard); 1143 return; 1144 } 1145 limit = getval(lp, v + 1); 1146 if (setlim(lp, hard, limit) < 0) 1147 stderror(ERR_SILENT); 1148 } 1149 1150 static RLIM_TYPE 1151 getval(struct limits *lp, Char **v) 1152 { 1153 float f; 1154 Char *cp = *v++; 1155 1156 f = atof(short2str(cp)); 1157 1158 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 1159 cp++; 1160 if (*cp == 0) { 1161 if (*v == 0) 1162 return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv)); 1163 cp = *v; 1164 } 1165 switch (*cp) { 1166 case ':': 1167 if (lp->limconst != RLIMIT_CPU) 1168 goto badscal; 1169 return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1)))); 1170 case 'h': 1171 if (lp->limconst != RLIMIT_CPU) 1172 goto badscal; 1173 limtail(cp, "hours"); 1174 f *= 3600.0; 1175 break; 1176 case 'm': 1177 if (lp->limconst == RLIMIT_CPU) { 1178 limtail(cp, "minutes"); 1179 f *= 60.0; 1180 break; 1181 } 1182 *cp = 'm'; 1183 limtail(cp, "megabytes"); 1184 f *= 1024.0 * 1024.0; 1185 break; 1186 case 's': 1187 if (lp->limconst != RLIMIT_CPU) 1188 goto badscal; 1189 limtail(cp, "seconds"); 1190 break; 1191 case 'M': 1192 if (lp->limconst == RLIMIT_CPU) 1193 goto badscal; 1194 *cp = 'm'; 1195 limtail(cp, "megabytes"); 1196 f *= 1024.0 * 1024.0; 1197 break; 1198 case 'k': 1199 if (lp->limconst == RLIMIT_CPU) 1200 goto badscal; 1201 limtail(cp, "kbytes"); 1202 f *= 1024.0; 1203 break; 1204 case 'u': 1205 limtail(cp, "unlimited"); 1206 return (RLIM_INFINITY); 1207 default: 1208 badscal: 1209 stderror(ERR_NAME | ERR_SCALEF); 1210 } 1211 f += 0.5; 1212 if (f > (float) RLIM_INFINITY) 1213 return RLIM_INFINITY; 1214 else 1215 return ((RLIM_TYPE) f); 1216 } 1217 1218 static void 1219 limtail(Char *cp, char *str) 1220 { 1221 char *origstr = str; 1222 1223 while (*cp && *cp == *str) 1224 cp++, str++; 1225 if (*cp) 1226 stderror(ERR_BADSCALE, origstr); 1227 } 1228 1229 /*ARGSUSED*/ 1230 static void 1231 plim(struct limits *lp, Char hard) 1232 { 1233 struct rlimit rlim; 1234 RLIM_TYPE limit; 1235 1236 (void) fprintf(cshout, "%s \t", lp->limname); 1237 1238 (void) getrlimit(lp->limconst, &rlim); 1239 limit = hard ? rlim.rlim_max : rlim.rlim_cur; 1240 1241 if (limit == RLIM_INFINITY) 1242 (void) fprintf(cshout, "unlimited"); 1243 else if (lp->limconst == RLIMIT_CPU) 1244 psecs((long) limit); 1245 else 1246 (void) fprintf(cshout, "%ld %s", (long) (limit / lp->limdiv), 1247 lp->limscale); 1248 (void) fputc('\n', cshout); 1249 } 1250 1251 void 1252 /*ARGSUSED*/ 1253 dounlimit(Char **v, struct command *t) 1254 { 1255 struct limits *lp; 1256 int lerr = 0; 1257 Char hard = 0; 1258 1259 v++; 1260 if (*v && eq(*v, STRmh)) { 1261 hard = 1; 1262 v++; 1263 } 1264 if (*v == 0) { 1265 for (lp = limits; lp->limconst >= 0; lp++) 1266 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 1267 lerr++; 1268 if (lerr) 1269 stderror(ERR_SILENT); 1270 return; 1271 } 1272 while (*v) { 1273 lp = findlim(*v++); 1274 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) 1275 stderror(ERR_SILENT); 1276 } 1277 } 1278 1279 static int 1280 setlim(struct limits *lp, Char hard, RLIM_TYPE limit) 1281 { 1282 struct rlimit rlim; 1283 1284 (void) getrlimit(lp->limconst, &rlim); 1285 1286 if (hard) 1287 rlim.rlim_max = limit; 1288 else if (limit == RLIM_INFINITY && geteuid() != 0) 1289 rlim.rlim_cur = rlim.rlim_max; 1290 else 1291 rlim.rlim_cur = limit; 1292 1293 if (setrlimit(lp->limconst, &rlim) < 0) { 1294 (void) fprintf(csherr, "%s: %s: Can't %s%s limit\n", bname, lp->limname, 1295 limit == RLIM_INFINITY ? "remove" : "set", 1296 hard ? " hard" : ""); 1297 return (-1); 1298 } 1299 return (0); 1300 } 1301 1302 void 1303 /*ARGSUSED*/ 1304 dosuspend(Char **v, struct command *t) 1305 { 1306 int ctpgrp; 1307 1308 void (*old) (int); 1309 1310 if (loginsh) 1311 stderror(ERR_SUSPLOG); 1312 untty(); 1313 1314 old = signal(SIGTSTP, SIG_DFL); 1315 (void) kill(0, SIGTSTP); 1316 /* the shell stops here */ 1317 (void) signal(SIGTSTP, old); 1318 1319 if (tpgrp != -1) { 1320 retry: 1321 ctpgrp = tcgetpgrp(FSHTTY); 1322 if (ctpgrp != opgrp) { 1323 old = signal(SIGTTIN, SIG_DFL); 1324 (void) kill(0, SIGTTIN); 1325 (void) signal(SIGTTIN, old); 1326 goto retry; 1327 } 1328 (void) setpgid(0, shpgrp); 1329 (void) tcsetpgrp(FSHTTY, shpgrp); 1330 } 1331 } 1332 1333 /* This is the dreaded EVAL built-in. 1334 * If you don't fiddle with file descriptors, and reset didfds, 1335 * this command will either ignore redirection inside or outside 1336 * its arguments, e.g. eval "date >x" vs. eval "date" >x 1337 * The stuff here seems to work, but I did it by trial and error rather 1338 * than really knowing what was going on. If tpgrp is zero, we are 1339 * probably a background eval, e.g. "eval date &", and we want to 1340 * make sure that any processes we start stay in our pgrp. 1341 * This is also the case for "time eval date" -- stay in same pgrp. 1342 * Otherwise, under stty tostop, processes will stop in the wrong 1343 * pgrp, with no way for the shell to get them going again. -IAN! 1344 */ 1345 1346 static Char **gv = NULL; 1347 1348 void 1349 /*ARGSUSED*/ 1350 doeval(Char **v, struct command *t) 1351 { 1352 Char **oevalvec; 1353 Char *oevalp; 1354 int odidfds; 1355 jmp_buf osetexit; 1356 int my_reenter; 1357 Char **savegv = gv; 1358 int saveIN; 1359 int saveOUT; 1360 int saveERR; 1361 int oSHIN; 1362 int oSHOUT; 1363 int oSHERR; 1364 1365 UNREGISTER(v); 1366 1367 oevalvec = evalvec; 1368 oevalp = evalp; 1369 odidfds = didfds; 1370 oSHIN = SHIN; 1371 oSHOUT = SHOUT; 1372 oSHERR = SHERR; 1373 1374 v++; 1375 if (*v == 0) 1376 return; 1377 gflag = 0, tglob(v); 1378 if (gflag) { 1379 gv = v = globall(v); 1380 gargv = 0; 1381 if (v == 0) 1382 stderror(ERR_NOMATCH); 1383 v = copyblk(v); 1384 } 1385 else { 1386 gv = NULL; 1387 v = copyblk(v); 1388 trim(v); 1389 } 1390 1391 saveIN = dcopy(SHIN, -1); 1392 saveOUT = dcopy(SHOUT, -1); 1393 saveERR = dcopy(SHERR, -1); 1394 1395 getexit(osetexit); 1396 1397 if ((my_reenter = setexit()) == 0) { 1398 evalvec = v; 1399 evalp = 0; 1400 SHIN = dcopy(0, -1); 1401 SHOUT = dcopy(1, -1); 1402 SHERR = dcopy(2, -1); 1403 didfds = 0; 1404 process(0); 1405 } 1406 1407 evalvec = oevalvec; 1408 evalp = oevalp; 1409 doneinp = 0; 1410 didfds = odidfds; 1411 (void) close(SHIN); 1412 (void) close(SHOUT); 1413 (void) close(SHERR); 1414 SHIN = dmove(saveIN, oSHIN); 1415 SHOUT = dmove(saveOUT, oSHOUT); 1416 SHERR = dmove(saveERR, oSHERR); 1417 if (gv) 1418 blkfree(gv), gv = NULL; 1419 resexit(osetexit); 1420 gv = savegv; 1421 if (my_reenter) 1422 stderror(ERR_SILENT); 1423 } 1424