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