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