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