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