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