1*47823Sbostic /*- 2*47823Sbostic * Copyright (c) 1980, 1991 The Regents of the University of California. 3*47823Sbostic * All rights reserved. 4*47823Sbostic * 5*47823Sbostic * %sccs.include.redist.c% 621933Sdist */ 721933Sdist 817519Sedward #ifndef lint 9*47823Sbostic static char sccsid[] = "@(#)func.c 5.14 (Berkeley) 04/04/91"; 1047413Sbostic #endif /* not lint */ 111294Sbill 121294Sbill #include "sh.h" 131294Sbill #include <sys/ioctl.h> 1437025Sbostic #include "pathnames.h" 151294Sbill 161294Sbill /* 171294Sbill * C shell 181294Sbill */ 191294Sbill 201294Sbill struct biltins * 211294Sbill isbfunc(t) 2217519Sedward struct command *t; 231294Sbill { 241294Sbill register char *cp = t->t_dcom[0]; 2517519Sedward register struct biltins *bp, *bp1, *bp2; 261294Sbill int dolabel(), dofg1(), dobg1(); 271294Sbill static struct biltins label = { "", dolabel, 0, 0 }; 281294Sbill static struct biltins foregnd = { "%job", dofg1, 0, 0 }; 291294Sbill static struct biltins backgnd = { "%job &", dobg1, 0, 0 }; 301294Sbill 311294Sbill if (lastchr(cp) == ':') { 321294Sbill label.bname = cp; 331294Sbill return (&label); 341294Sbill } 351294Sbill if (*cp == '%') { 3647724Sbostic if (t->t_dflg & F_AMPERSAND) { 3747724Sbostic t->t_dflg &= ~F_AMPERSAND; 381294Sbill backgnd.bname = cp; 391294Sbill return (&backgnd); 4017519Sedward } 411294Sbill foregnd.bname = cp; 421294Sbill return (&foregnd); 431294Sbill } 4417519Sedward /* 4517519Sedward * Binary search 4617519Sedward * Bp1 is the beginning of the current search range. 4717519Sedward * Bp2 is one past the end. 4817519Sedward */ 4917519Sedward for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { 5017519Sedward register i; 5117519Sedward 5217519Sedward bp = bp1 + (bp2 - bp1 >> 1); 5317519Sedward if ((i = *cp - *bp->bname) == 0 && 5417519Sedward (i = strcmp(cp, bp->bname)) == 0) 5517519Sedward return bp; 5617519Sedward if (i < 0) 5717519Sedward bp2 = bp; 5817519Sedward else 5917519Sedward bp1 = bp + 1; 601294Sbill } 611294Sbill return (0); 621294Sbill } 631294Sbill 641294Sbill func(t, bp) 651294Sbill register struct command *t; 661294Sbill register struct biltins *bp; 671294Sbill { 681294Sbill int i; 691294Sbill 701294Sbill xechoit(t->t_dcom); 711294Sbill setname(bp->bname); 721294Sbill i = blklen(t->t_dcom) - 1; 731294Sbill if (i < bp->minargs) 741294Sbill bferr("Too few arguments"); 751294Sbill if (i > bp->maxargs) 761294Sbill bferr("Too many arguments"); 771294Sbill (*bp->bfunct)(t->t_dcom, t); 781294Sbill } 791294Sbill 801294Sbill dolabel() 811294Sbill { 821294Sbill 831294Sbill } 841294Sbill 851294Sbill doonintr(v) 861294Sbill char **v; 871294Sbill { 881294Sbill register char *cp; 891294Sbill register char *vv = v[1]; 901294Sbill 911294Sbill if (parintr == SIG_IGN) 921294Sbill return; 931294Sbill if (setintr && intty) 941294Sbill bferr("Can't from terminal"); 951294Sbill cp = gointr, gointr = 0, xfree(cp); 961294Sbill if (vv == 0) { 971294Sbill if (setintr) 9817519Sedward (void) sigblock(sigmask(SIGINT)); 991294Sbill else 10017519Sedward (void) signal(SIGINT, SIG_DFL); 1011294Sbill gointr = 0; 1021294Sbill } else if (eq((vv = strip(vv)), "-")) { 10317519Sedward (void) signal(SIGINT, SIG_IGN); 1041294Sbill gointr = "-"; 1051294Sbill } else { 1061294Sbill gointr = savestr(vv); 10717519Sedward (void) signal(SIGINT, pintr); 1081294Sbill } 1091294Sbill } 1101294Sbill 1111294Sbill donohup() 1121294Sbill { 1131294Sbill 1141294Sbill if (intty) 1151294Sbill bferr("Can't from terminal"); 1161294Sbill if (setintr == 0) { 11717519Sedward (void) signal(SIGHUP, SIG_IGN); 1181294Sbill #ifdef CC 1191294Sbill submit(getpid()); 1201294Sbill #endif 1211294Sbill } 1221294Sbill } 1231294Sbill 1241294Sbill dozip() 1251294Sbill { 1261294Sbill 1271294Sbill ; 1281294Sbill } 1291294Sbill 1301294Sbill prvars() 1311294Sbill { 1321294Sbill 1331294Sbill plist(&shvhed); 1341294Sbill } 1351294Sbill 1361294Sbill doalias(v) 1371294Sbill register char **v; 1381294Sbill { 1391294Sbill register struct varent *vp; 1401294Sbill register char *p; 1411294Sbill 1421294Sbill v++; 1431294Sbill p = *v++; 1441294Sbill if (p == 0) 1451294Sbill plist(&aliases); 1461294Sbill else if (*v == 0) { 1471294Sbill vp = adrof1(strip(p), &aliases); 1481294Sbill if (vp) 1491294Sbill blkpr(vp->vec), printf("\n"); 1501294Sbill } else { 1511294Sbill if (eq(p, "alias") || eq(p, "unalias")) { 1521294Sbill setname(p); 1531294Sbill bferr("Too dangerous to alias that"); 1541294Sbill } 1551294Sbill set1(strip(p), saveblk(v), &aliases); 1561294Sbill } 1571294Sbill } 1581294Sbill 1591294Sbill unalias(v) 1601294Sbill char **v; 1611294Sbill { 1621294Sbill 1631294Sbill unset1(v, &aliases); 1641294Sbill } 1651294Sbill 1661294Sbill dologout() 1671294Sbill { 1681294Sbill 1691294Sbill islogin(); 1701294Sbill goodbye(); 1711294Sbill } 1721294Sbill 1731294Sbill dologin(v) 1741294Sbill char **v; 1751294Sbill { 1761294Sbill 1771294Sbill islogin(); 1784189Smckusic rechist(); 17917519Sedward (void) signal(SIGTERM, parterm); 18037025Sbostic execl(_PATH_LOGIN, "login", v[1], 0); 1811294Sbill untty(); 1821294Sbill exit(1); 1831294Sbill } 1841294Sbill 1851294Sbill islogin() 1861294Sbill { 1871294Sbill 1881294Sbill if (chkstop == 0 && setintr) 1891294Sbill panystop(0); 1901294Sbill if (loginsh) 1911294Sbill return; 1921294Sbill error("Not login shell"); 1931294Sbill } 1941294Sbill 1951294Sbill doif(v, kp) 1961294Sbill char **v; 1971294Sbill struct command *kp; 1981294Sbill { 1991294Sbill register int i; 2001294Sbill register char **vv; 2011294Sbill 2021294Sbill v++; 2031294Sbill i = exp(&v); 2041294Sbill vv = v; 2051294Sbill if (*vv == NOSTR) 2061294Sbill bferr("Empty if"); 2071294Sbill if (eq(*vv, "then")) { 2081294Sbill if (*++vv) 2091294Sbill bferr("Improper then"); 2101294Sbill setname("then"); 2111294Sbill /* 2121294Sbill * If expression was zero, then scan to else, 2131294Sbill * otherwise just fall into following code. 2141294Sbill */ 2151294Sbill if (!i) 21647724Sbostic search(T_IF, 0); 2171294Sbill return; 2181294Sbill } 2191294Sbill /* 2201294Sbill * Simple command attached to this if. 2211294Sbill * Left shift the node in this tree, munging it 2221294Sbill * so we can reexecute it. 2231294Sbill */ 2241294Sbill if (i) { 2251294Sbill lshift(kp->t_dcom, vv - kp->t_dcom); 2261294Sbill reexecute(kp); 2271294Sbill donefds(); 2281294Sbill } 2291294Sbill } 2301294Sbill 2311294Sbill /* 2321294Sbill * Reexecute a command, being careful not 2331294Sbill * to redo i/o redirection, which is already set up. 2341294Sbill */ 2351294Sbill reexecute(kp) 2361294Sbill register struct command *kp; 2371294Sbill { 2381294Sbill 23947724Sbostic kp->t_dflg &= F_SAVE; 24047724Sbostic kp->t_dflg |= F_REPEAT; 2411294Sbill /* 2421294Sbill * If tty is still ours to arbitrate, arbitrate it; 2431294Sbill * otherwise dont even set pgrp's as the jobs would 2441294Sbill * then have no way to get the tty (we can't give it 2451294Sbill * to them, and our parent wouldn't know their pgrp, etc. 2461294Sbill */ 2471294Sbill execute(kp, tpgrp > 0 ? tpgrp : -1); 2481294Sbill } 2491294Sbill 2501294Sbill doelse() 2511294Sbill { 2521294Sbill 25347724Sbostic search(T_ELSE, 0); 2541294Sbill } 2551294Sbill 2561294Sbill dogoto(v) 2571294Sbill char **v; 2581294Sbill { 2591294Sbill register struct whyle *wp; 2601294Sbill char *lp; 2611294Sbill 2621294Sbill /* 2631294Sbill * While we still can, locate any unknown ends of existing loops. 2641294Sbill * This obscure code is the WORST result of the fact that we 2651294Sbill * don't really parse. 2661294Sbill */ 2671294Sbill for (wp = whyles; wp; wp = wp->w_next) 2681294Sbill if (wp->w_end == 0) { 26947724Sbostic search(T_BREAK, 0); 2701294Sbill wp->w_end = btell(); 2711294Sbill } else 2721294Sbill bseek(wp->w_end); 27347724Sbostic search(T_GOTO, 0, lp = globone(v[1])); 2741294Sbill xfree(lp); 2751294Sbill /* 2761294Sbill * Eliminate loops which were exited. 2771294Sbill */ 2781294Sbill wfree(); 2791294Sbill } 2801294Sbill 2811294Sbill doswitch(v) 2821294Sbill register char **v; 2831294Sbill { 2841294Sbill register char *cp, *lp; 2851294Sbill 2861294Sbill v++; 2871294Sbill if (!*v || *(*v++) != '(') 2881294Sbill goto syntax; 2891294Sbill cp = **v == ')' ? "" : *v++; 2901294Sbill if (*(*v++) != ')') 2911294Sbill v--; 2921294Sbill if (*v) 2931294Sbill syntax: 2941294Sbill error("Syntax error"); 29547724Sbostic search(T_SWITCH, 0, lp = globone(cp)); 2961294Sbill xfree(lp); 2971294Sbill } 2981294Sbill 2991294Sbill dobreak() 3001294Sbill { 3011294Sbill 3021294Sbill if (whyles) 3031294Sbill toend(); 3041294Sbill else 3051294Sbill bferr("Not in while/foreach"); 3061294Sbill } 3071294Sbill 3081294Sbill doexit(v) 3091294Sbill char **v; 3101294Sbill { 3111294Sbill 3121294Sbill if (chkstop == 0) 3131294Sbill panystop(0); 3141294Sbill /* 3151294Sbill * Don't DEMAND parentheses here either. 3161294Sbill */ 3171294Sbill v++; 3181294Sbill if (*v) { 3191294Sbill set("status", putn(exp(&v))); 3201294Sbill if (*v) 3211294Sbill bferr("Expression syntax"); 3221294Sbill } 3231294Sbill btoeof(); 3241294Sbill if (intty) 32517519Sedward (void) close(SHIN); 3261294Sbill } 3271294Sbill 3281294Sbill doforeach(v) 3291294Sbill register char **v; 3301294Sbill { 3311294Sbill register char *cp; 3321294Sbill register struct whyle *nwp; 3331294Sbill 3341294Sbill v++; 3351294Sbill cp = strip(*v); 3361294Sbill while (*cp && letter(*cp)) 3371294Sbill cp++; 3381294Sbill if (*cp || strlen(*v) >= 20) 3391294Sbill bferr("Invalid variable"); 3401294Sbill cp = *v++; 3411294Sbill if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') 3421294Sbill bferr("Words not ()'ed"); 3431294Sbill v++; 34417519Sedward gflag = 0, tglob(v); 34547412Sbostic v = globall(v); 3461294Sbill if (v == 0) 3471294Sbill bferr("No match"); 3481294Sbill nwp = (struct whyle *) calloc(1, sizeof *nwp); 3491294Sbill nwp->w_fe = nwp->w_fe0 = v; gargv = 0; 3501294Sbill nwp->w_start = btell(); 3511294Sbill nwp->w_fename = savestr(cp); 3521294Sbill nwp->w_next = whyles; 3531294Sbill whyles = nwp; 3541294Sbill /* 3551294Sbill * Pre-read the loop so as to be more 3561294Sbill * comprehensible to a terminal user. 3571294Sbill */ 3581294Sbill if (intty) 3591294Sbill preread(); 3601294Sbill doagain(); 3611294Sbill } 3621294Sbill 3631294Sbill dowhile(v) 3641294Sbill char **v; 3651294Sbill { 3661294Sbill register int status; 3671294Sbill register bool again = whyles != 0 && whyles->w_start == lineloc && 3681294Sbill whyles->w_fename == 0; 3691294Sbill 3701294Sbill v++; 3711294Sbill /* 3721294Sbill * Implement prereading here also, taking care not to 3731294Sbill * evaluate the expression before the loop has been read up 3741294Sbill * from a terminal. 3751294Sbill */ 3761294Sbill if (intty && !again) 3771294Sbill status = !exp0(&v, 1); 3781294Sbill else 3791294Sbill status = !exp(&v); 3801294Sbill if (*v) 3811294Sbill bferr("Expression syntax"); 3821294Sbill if (!again) { 3831294Sbill register struct whyle *nwp = (struct whyle *) calloc(1, sizeof (*nwp)); 3841294Sbill 3851294Sbill nwp->w_start = lineloc; 3861294Sbill nwp->w_end = 0; 3871294Sbill nwp->w_next = whyles; 3881294Sbill whyles = nwp; 3891294Sbill if (intty) { 3901294Sbill /* 3911294Sbill * The tty preread 3921294Sbill */ 3931294Sbill preread(); 3941294Sbill doagain(); 3951294Sbill return; 3961294Sbill } 3971294Sbill } 3981294Sbill if (status) 3991294Sbill /* We ain't gonna loop no more, no more! */ 4001294Sbill toend(); 4011294Sbill } 4021294Sbill 4031294Sbill preread() 4041294Sbill { 4051294Sbill 4061294Sbill whyles->w_end = -1; 4071294Sbill if (setintr) 40831685Sbostic (void) sigsetmask(sigblock(0L) & ~sigmask(SIGINT)); 40947724Sbostic search(T_BREAK, 0); 4101294Sbill if (setintr) 41117519Sedward (void) sigblock(sigmask(SIGINT)); 4121294Sbill whyles->w_end = btell(); 4131294Sbill } 4141294Sbill 4151294Sbill doend() 4161294Sbill { 4171294Sbill 4181294Sbill if (!whyles) 4191294Sbill bferr("Not in while/foreach"); 4201294Sbill whyles->w_end = btell(); 4211294Sbill doagain(); 4221294Sbill } 4231294Sbill 4241294Sbill docontin() 4251294Sbill { 4261294Sbill 4271294Sbill if (!whyles) 4281294Sbill bferr("Not in while/foreach"); 4291294Sbill doagain(); 4301294Sbill } 4311294Sbill 4321294Sbill doagain() 4331294Sbill { 4341294Sbill 4351294Sbill /* Repeating a while is simple */ 4361294Sbill if (whyles->w_fename == 0) { 4371294Sbill bseek(whyles->w_start); 4381294Sbill return; 4391294Sbill } 4401294Sbill /* 4411294Sbill * The foreach variable list actually has a spurious word 4421294Sbill * ")" at the end of the w_fe list. Thus we are at the 4431294Sbill * of the list if one word beyond this is 0. 4441294Sbill */ 4451294Sbill if (!whyles->w_fe[1]) { 4461294Sbill dobreak(); 4471294Sbill return; 4481294Sbill } 4491294Sbill set(whyles->w_fename, savestr(*whyles->w_fe++)); 4501294Sbill bseek(whyles->w_start); 4511294Sbill } 4521294Sbill 4531294Sbill dorepeat(v, kp) 4541294Sbill char **v; 4551294Sbill struct command *kp; 4561294Sbill { 45731685Sbostic register int i; 45831685Sbostic register long omask; 4591294Sbill 4601294Sbill i = getn(v[1]); 4611294Sbill if (setintr) 46217138Sralph omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); 4631294Sbill lshift(v, 2); 4641294Sbill while (i > 0) { 4651294Sbill if (setintr) 46617519Sedward (void) sigsetmask(omask); 4671294Sbill reexecute(kp); 4681294Sbill --i; 4691294Sbill } 4701294Sbill donefds(); 4711294Sbill if (setintr) 47217519Sedward (void) sigsetmask(omask); 4731294Sbill } 4741294Sbill 4751294Sbill doswbrk() 4761294Sbill { 4771294Sbill 47847724Sbostic search(T_BRKSW, 0); 4791294Sbill } 4801294Sbill 4811294Sbill srchx(cp) 4821294Sbill register char *cp; 4831294Sbill { 48417519Sedward register struct srch *sp, *sp1, *sp2; 48517519Sedward register i; 4861294Sbill 48717519Sedward /* 48817519Sedward * Binary search 48917519Sedward * Sp1 is the beginning of the current search range. 49017519Sedward * Sp2 is one past the end. 49117519Sedward */ 49217519Sedward for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { 49317519Sedward sp = sp1 + (sp2 - sp1 >> 1); 49417519Sedward if ((i = *cp - *sp->s_name) == 0 && 49517519Sedward (i = strcmp(cp, sp->s_name)) == 0) 49617519Sedward return sp->s_value; 49717519Sedward if (i < 0) 49817519Sedward sp2 = sp; 49917519Sedward else 50017519Sedward sp1 = sp + 1; 50117519Sedward } 5021294Sbill return (-1); 5031294Sbill } 5041294Sbill 5051294Sbill char Stype; 5061294Sbill char *Sgoal; 5071294Sbill 5081294Sbill /*VARARGS2*/ 5091294Sbill search(type, level, goal) 5101294Sbill int type; 5111294Sbill register int level; 5121294Sbill char *goal; 5131294Sbill { 5141294Sbill char wordbuf[BUFSIZ]; 5151294Sbill register char *aword = wordbuf; 5161294Sbill register char *cp; 5171294Sbill 5181294Sbill Stype = type; Sgoal = goal; 51947724Sbostic if (type == T_GOTO) 52017519Sedward bseek((off_t)0); 5211294Sbill do { 5221294Sbill if (intty && fseekp == feobp) 5231294Sbill printf("? "), flush(); 52417519Sedward aword[0] = 0; 52517519Sedward (void) getword(aword); 5261294Sbill switch (srchx(aword)) { 5271294Sbill 52847724Sbostic case T_ELSE: 52947724Sbostic if (level == 0 && type == T_IF) 5301294Sbill return; 5311294Sbill break; 5321294Sbill 53347724Sbostic case T_IF: 5341294Sbill while (getword(aword)) 5351294Sbill continue; 53647724Sbostic if ((type == T_IF || type == T_ELSE) && 53747724Sbostic eq(aword, "then")) 5381294Sbill level++; 5391294Sbill break; 5401294Sbill 54147724Sbostic case T_ENDIF: 54247724Sbostic if (type == T_IF || type == T_ELSE) 5431294Sbill level--; 5441294Sbill break; 5451294Sbill 54647724Sbostic case T_FOREACH: 54747724Sbostic case T_WHILE: 54847724Sbostic if (type == T_BREAK) 5491294Sbill level++; 5501294Sbill break; 5511294Sbill 55247724Sbostic case T_END: 55347724Sbostic if (type == T_BREAK) 5541294Sbill level--; 5551294Sbill break; 5561294Sbill 55747724Sbostic case T_SWITCH: 55847724Sbostic if (type == T_SWITCH || type == T_BRKSW) 5591294Sbill level++; 5601294Sbill break; 5611294Sbill 56247724Sbostic case T_ENDSW: 56347724Sbostic if (type == T_SWITCH || type == T_BRKSW) 5641294Sbill level--; 5651294Sbill break; 5661294Sbill 56747724Sbostic case T_LABEL: 56847724Sbostic if (type == T_GOTO && getword(aword) && eq(aword, goal)) 5691294Sbill level = -1; 5701294Sbill break; 5711294Sbill 5721294Sbill default: 57347724Sbostic if (type != T_GOTO && (type != T_SWITCH || level != 0)) 5741294Sbill break; 5751294Sbill if (lastchr(aword) != ':') 5761294Sbill break; 5771294Sbill aword[strlen(aword) - 1] = 0; 57847724Sbostic if (type == T_GOTO && eq(aword, goal) || 57947724Sbostic type == T_SWITCH && eq(aword, "default")) 5801294Sbill level = -1; 5811294Sbill break; 5821294Sbill 58347724Sbostic case T_CASE: 58447724Sbostic if (type != T_SWITCH || level != 0) 5851294Sbill break; 58617519Sedward (void) getword(aword); 5871294Sbill if (lastchr(aword) == ':') 5881294Sbill aword[strlen(aword) - 1] = 0; 5891294Sbill cp = strip(Dfix1(aword)); 5901294Sbill if (Gmatch(goal, cp)) 5911294Sbill level = -1; 5921294Sbill xfree(cp); 5931294Sbill break; 5941294Sbill 59547724Sbostic case T_DEFAULT: 59647724Sbostic if (type == T_SWITCH && level == 0) 5971294Sbill level = -1; 5981294Sbill break; 5991294Sbill } 60017519Sedward (void) getword(NOSTR); 6011294Sbill } while (level >= 0); 6021294Sbill } 6031294Sbill 6041294Sbill getword(wp) 6051294Sbill register char *wp; 6061294Sbill { 6071294Sbill register int found = 0; 6081294Sbill register int c, d; 6091294Sbill 6101294Sbill c = readc(1); 6111294Sbill d = 0; 6121294Sbill do { 6131294Sbill while (c == ' ' || c == '\t') 6141294Sbill c = readc(1); 6153798Sroot if (c == '#') 6163798Sroot do 6173798Sroot c = readc(1); 6183798Sroot while (c >= 0 && c != '\n'); 6191294Sbill if (c < 0) 6201294Sbill goto past; 6211294Sbill if (c == '\n') { 6221294Sbill if (wp) 6231294Sbill break; 6241294Sbill return (0); 6251294Sbill } 6261294Sbill unreadc(c); 6271294Sbill found = 1; 6281294Sbill do { 6291294Sbill c = readc(1); 6301294Sbill if (c == '\\' && (c = readc(1)) == '\n') 6311294Sbill c = ' '; 63217519Sedward if (c == '\'' || c == '"') 6331294Sbill if (d == 0) 6341294Sbill d = c; 6351294Sbill else if (d == c) 6361294Sbill d = 0; 6371294Sbill if (c < 0) 6381294Sbill goto past; 6391294Sbill if (wp) 6401294Sbill *wp++ = c; 6411294Sbill } while ((d || c != ' ' && c != '\t') && c != '\n'); 6421294Sbill } while (wp == 0); 6431294Sbill unreadc(c); 6441294Sbill if (found) 6451294Sbill *--wp = 0; 6461294Sbill return (found); 6471294Sbill 6481294Sbill past: 6491294Sbill switch (Stype) { 6501294Sbill 65147724Sbostic case T_IF: 6521294Sbill bferr("then/endif not found"); 6531294Sbill 65447724Sbostic case T_ELSE: 6551294Sbill bferr("endif not found"); 6561294Sbill 65747724Sbostic case T_BRKSW: 65847724Sbostic case T_SWITCH: 6591294Sbill bferr("endsw not found"); 6601294Sbill 66147724Sbostic case T_BREAK: 6621294Sbill bferr("end not found"); 6631294Sbill 66447724Sbostic case T_GOTO: 6651294Sbill setname(Sgoal); 6661294Sbill bferr("label not found"); 6671294Sbill } 6681294Sbill /*NOTREACHED*/ 6691294Sbill } 6701294Sbill 6711294Sbill toend() 6721294Sbill { 6731294Sbill 6741294Sbill if (whyles->w_end == 0) { 67547724Sbostic search(T_BREAK, 0); 6761294Sbill whyles->w_end = btell() - 1; 6771294Sbill } else 6781294Sbill bseek(whyles->w_end); 6791294Sbill wfree(); 6801294Sbill } 6811294Sbill 6821294Sbill wfree() 6831294Sbill { 6841294Sbill long o = btell(); 6851294Sbill 6861294Sbill while (whyles) { 6871294Sbill register struct whyle *wp = whyles; 6881294Sbill register struct whyle *nwp = wp->w_next; 6891294Sbill 6901294Sbill if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) 6911294Sbill break; 6921294Sbill if (wp->w_fe0) 6931294Sbill blkfree(wp->w_fe0); 6941294Sbill if (wp->w_fename) 6951294Sbill xfree(wp->w_fename); 6961294Sbill xfree((char *)wp); 6971294Sbill whyles = nwp; 6981294Sbill } 6991294Sbill } 7001294Sbill 7011294Sbill doecho(v) 7021294Sbill char **v; 7031294Sbill { 7041294Sbill 7051294Sbill echo(' ', v); 7061294Sbill } 7071294Sbill 7081294Sbill doglob(v) 7091294Sbill char **v; 7101294Sbill { 7111294Sbill 7121294Sbill echo(0, v); 7131294Sbill flush(); 7141294Sbill } 7151294Sbill 7161294Sbill echo(sep, v) 7171294Sbill char sep; 7181294Sbill register char **v; 7191294Sbill { 7201294Sbill register char *cp; 7211294Sbill int nonl = 0; 7221294Sbill 7231294Sbill if (setintr) 72431685Sbostic (void) sigsetmask(sigblock(0L) & ~sigmask(SIGINT)); 7251294Sbill v++; 7261294Sbill if (*v == 0) 7271294Sbill return; 72817519Sedward gflag = 0, tglob(v); 7291294Sbill if (gflag) { 73047412Sbostic v = globall(v); 7311294Sbill if (v == 0) 7321294Sbill bferr("No match"); 7331294Sbill } else 73417519Sedward trim(v); 73518422Smckusick if (sep == ' ' && *v && !strcmp(*v, "-n")) 7361294Sbill nonl++, v++; 7371294Sbill while (cp = *v++) { 7381294Sbill register int c; 7391294Sbill 7401294Sbill while (c = *cp++) 74134340Sbostic cshputchar(c | QUOTE); 7421294Sbill if (*v) 74334340Sbostic cshputchar(sep | QUOTE); 7441294Sbill } 7451294Sbill if (sep && nonl == 0) 74634340Sbostic cshputchar('\n'); 7471294Sbill else 7481294Sbill flush(); 7491294Sbill if (setintr) 75017519Sedward (void) sigblock(sigmask(SIGINT)); 7511294Sbill if (gargv) 7521294Sbill blkfree(gargv), gargv = 0; 7531294Sbill } 7541294Sbill 7551294Sbill char **environ; 7561294Sbill 7571294Sbill dosetenv(v) 7581294Sbill register char **v; 7591294Sbill { 76021753Sedward char *vp, *lp; 7611294Sbill 76221753Sedward v++; 76321753Sedward if ((vp = *v++) == 0) { 76421753Sedward register char **ep; 76521753Sedward 76621753Sedward if (setintr) 76731685Sbostic (void) sigsetmask(sigblock(0L) & ~ sigmask(SIGINT)); 76821753Sedward for (ep = environ; *ep; ep++) 76921753Sedward printf("%s\n", *ep); 77021753Sedward return; 77121753Sedward } 77221753Sedward if ((lp = *v++) == 0) 77321753Sedward lp = ""; 77421753Sedward setenv(vp, lp = globone(lp)); 77521753Sedward if (eq(vp, "PATH")) { 7761294Sbill importpath(lp); 7771294Sbill dohash(); 7781294Sbill } 7791294Sbill xfree(lp); 7801294Sbill } 7811294Sbill 7821294Sbill dounsetenv(v) 7831294Sbill register char **v; 7841294Sbill { 7851294Sbill 7861294Sbill v++; 7871294Sbill do 7881294Sbill unsetenv(*v++); 7891294Sbill while (*v); 7901294Sbill } 7911294Sbill 79217519Sedward setenv(name, val) 79317519Sedward char *name, *val; 7941294Sbill { 7951294Sbill register char **ep = environ; 7961294Sbill register char *cp, *dp; 7971294Sbill char *blk[2], **oep = ep; 7981294Sbill 7991294Sbill for (; *ep; ep++) { 8001294Sbill for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 8011294Sbill continue; 8021294Sbill if (*cp != 0 || *dp != '=') 8031294Sbill continue; 80417519Sedward cp = strspl("=", val); 8051294Sbill xfree(*ep); 8061294Sbill *ep = strspl(name, cp); 8071294Sbill xfree(cp); 80817519Sedward trim(ep); 8091294Sbill return; 8101294Sbill } 8111294Sbill blk[0] = strspl(name, "="); blk[1] = 0; 8121294Sbill environ = blkspl(environ, blk); 8131294Sbill xfree((char *)oep); 81417519Sedward setenv(name, val); 8151294Sbill } 8161294Sbill 8171294Sbill unsetenv(name) 8181294Sbill char *name; 8191294Sbill { 8201294Sbill register char **ep = environ; 8211294Sbill register char *cp, *dp; 8221294Sbill char **oep = ep; 8231294Sbill 8241294Sbill for (; *ep; ep++) { 8251294Sbill for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) 8261294Sbill continue; 8271294Sbill if (*cp != 0 || *dp != '=') 8281294Sbill continue; 8291294Sbill cp = *ep; 8301294Sbill *ep = 0; 8311294Sbill environ = blkspl(environ, ep+1); 8321294Sbill *ep = cp; 8331294Sbill xfree(cp); 8341294Sbill xfree((char *)oep); 8351294Sbill return; 8361294Sbill } 8371294Sbill } 8381294Sbill 8391294Sbill doumask(v) 8401294Sbill register char **v; 8411294Sbill { 8421294Sbill register char *cp = v[1]; 8431294Sbill register int i; 8441294Sbill 8451294Sbill if (cp == 0) { 8461294Sbill i = umask(0); 84717519Sedward (void) umask(i); 8481294Sbill printf("%o\n", i); 8491294Sbill return; 8501294Sbill } 8511294Sbill i = 0; 8521294Sbill while (digit(*cp) && *cp != '8' && *cp != '9') 8531294Sbill i = i * 8 + *cp++ - '0'; 8541294Sbill if (*cp || i < 0 || i > 0777) 8551294Sbill bferr("Improper mask"); 85617519Sedward (void) umask(i); 8571294Sbill } 8581294Sbill 8591294Sbill 8601294Sbill struct limits { 8611294Sbill int limconst; 8621294Sbill char *limname; 8631294Sbill int limdiv; 8641294Sbill char *limscale; 8651294Sbill } limits[] = { 86610032Ssam RLIMIT_CPU, "cputime", 1, "seconds", 86710032Ssam RLIMIT_FSIZE, "filesize", 1024, "kbytes", 86810032Ssam RLIMIT_DATA, "datasize", 1024, "kbytes", 86910032Ssam RLIMIT_STACK, "stacksize", 1024, "kbytes", 87010032Ssam RLIMIT_CORE, "coredumpsize", 1024, "kbytes", 87110032Ssam RLIMIT_RSS, "memoryuse", 1024, "kbytes", 8721294Sbill -1, 0, 8731294Sbill }; 8741294Sbill 8751294Sbill struct limits * 8761294Sbill findlim(cp) 8771294Sbill char *cp; 8781294Sbill { 8791294Sbill register struct limits *lp, *res; 8801294Sbill 8811294Sbill res = 0; 8821294Sbill for (lp = limits; lp->limconst >= 0; lp++) 8831294Sbill if (prefix(cp, lp->limname)) { 8841294Sbill if (res) 8851294Sbill bferr("Ambiguous"); 8861294Sbill res = lp; 8871294Sbill } 8881294Sbill if (res) 8891294Sbill return (res); 8901294Sbill bferr("No such limit"); 89117519Sedward /*NOTREACHED*/ 8921294Sbill } 8931294Sbill 8941294Sbill dolimit(v) 8951294Sbill register char **v; 8961294Sbill { 8971294Sbill register struct limits *lp; 8981294Sbill register int limit; 89918539Sedward char hard = 0; 9001294Sbill 9011294Sbill v++; 90228050Slepreau if (*v && eq(*v, "-h")) { 90318539Sedward hard = 1; 90418539Sedward v++; 90518539Sedward } 9061294Sbill if (*v == 0) { 90718539Sedward for (lp = limits; lp->limconst >= 0; lp++) 90818539Sedward plim(lp, hard); 9091294Sbill return; 9101294Sbill } 9111294Sbill lp = findlim(v[0]); 9121294Sbill if (v[1] == 0) { 91318539Sedward plim(lp, hard); 9141294Sbill return; 9151294Sbill } 9161294Sbill limit = getval(lp, v+1); 91718539Sedward if (setlim(lp, hard, limit) < 0) 91818422Smckusick error(NOSTR); 9191294Sbill } 9201294Sbill 9211294Sbill getval(lp, v) 9221294Sbill register struct limits *lp; 9231294Sbill char **v; 9241294Sbill { 9251294Sbill register float f; 9261294Sbill double atof(); 9271294Sbill char *cp = *v++; 9281294Sbill 9291294Sbill f = atof(cp); 9301294Sbill while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') 9311294Sbill cp++; 9321294Sbill if (*cp == 0) { 9331294Sbill if (*v == 0) 9341294Sbill return ((int)(f+0.5) * lp->limdiv); 9351294Sbill cp = *v; 9361294Sbill } 9371294Sbill switch (*cp) { 9381294Sbill 9391294Sbill case ':': 94010032Ssam if (lp->limconst != RLIMIT_CPU) 9411294Sbill goto badscal; 9421294Sbill return ((int)(f * 60.0 + atof(cp+1))); 9431294Sbill 9441294Sbill case 'h': 94510032Ssam if (lp->limconst != RLIMIT_CPU) 9461294Sbill goto badscal; 9471294Sbill limtail(cp, "hours"); 9481294Sbill f *= 3600.; 9491294Sbill break; 9501294Sbill 9511294Sbill case 'm': 95210032Ssam if (lp->limconst == RLIMIT_CPU) { 9531294Sbill limtail(cp, "minutes"); 9541294Sbill f *= 60.; 9551294Sbill break; 9561294Sbill } 9571294Sbill case 'M': 95810032Ssam if (lp->limconst == RLIMIT_CPU) 9591294Sbill goto badscal; 9601294Sbill *cp = 'm'; 9611294Sbill limtail(cp, "megabytes"); 9621294Sbill f *= 1024.*1024.; 9631294Sbill break; 9641294Sbill 9651294Sbill case 's': 96610032Ssam if (lp->limconst != RLIMIT_CPU) 9671294Sbill goto badscal; 9681294Sbill limtail(cp, "seconds"); 9691294Sbill break; 9701294Sbill 9711294Sbill case 'k': 97210032Ssam if (lp->limconst == RLIMIT_CPU) 9731294Sbill goto badscal; 9741294Sbill limtail(cp, "kbytes"); 9751294Sbill f *= 1024; 9761294Sbill break; 9771294Sbill 9781294Sbill case 'u': 9791294Sbill limtail(cp, "unlimited"); 98010032Ssam return (RLIM_INFINITY); 9811294Sbill 9821294Sbill default: 9831294Sbill badscal: 9841294Sbill bferr("Improper or unknown scale factor"); 9851294Sbill } 9861294Sbill return ((int)(f+0.5)); 9871294Sbill } 9881294Sbill 9891294Sbill limtail(cp, str0) 9901294Sbill char *cp, *str0; 9911294Sbill { 9921294Sbill register char *str = str0; 9931294Sbill 9941294Sbill while (*cp && *cp == *str) 9951294Sbill cp++, str++; 9961294Sbill if (*cp) 9971294Sbill error("Bad scaling; did you mean ``%s''?", str0); 9981294Sbill } 9991294Sbill 100018539Sedward plim(lp, hard) 10011294Sbill register struct limits *lp; 100218539Sedward char hard; 10031294Sbill { 100410032Ssam struct rlimit rlim; 100518539Sedward int limit; 10061294Sbill 10071294Sbill printf("%s \t", lp->limname); 100817519Sedward (void) getrlimit(lp->limconst, &rlim); 100918539Sedward limit = hard ? rlim.rlim_max : rlim.rlim_cur; 101018539Sedward if (limit == RLIM_INFINITY) 10111294Sbill printf("unlimited"); 101210032Ssam else if (lp->limconst == RLIMIT_CPU) 101318539Sedward psecs((long)limit); 10141294Sbill else 101518539Sedward printf("%d %s", limit / lp->limdiv, lp->limscale); 10161294Sbill printf("\n"); 10171294Sbill } 10181294Sbill 10191294Sbill dounlimit(v) 10201294Sbill register char **v; 10211294Sbill { 10221294Sbill register struct limits *lp; 102318422Smckusick int err = 0; 102418539Sedward char hard = 0; 10251294Sbill 10261294Sbill v++; 102728050Slepreau if (*v && eq(*v, "-h")) { 102818539Sedward hard = 1; 102918539Sedward v++; 103018539Sedward } 10311294Sbill if (*v == 0) { 103218539Sedward for (lp = limits; lp->limconst >= 0; lp++) 103318539Sedward if (setlim(lp, hard, (int)RLIM_INFINITY) < 0) 103418422Smckusick err++; 103518422Smckusick if (err) 103618422Smckusick error(NOSTR); 10371294Sbill return; 10381294Sbill } 10391294Sbill while (*v) { 10401294Sbill lp = findlim(*v++); 104118539Sedward if (setlim(lp, hard, (int)RLIM_INFINITY) < 0) 104218422Smckusick error(NOSTR); 10431294Sbill } 10441294Sbill } 10451294Sbill 104618539Sedward setlim(lp, hard, limit) 10471294Sbill register struct limits *lp; 104818539Sedward char hard; 10491294Sbill { 105010032Ssam struct rlimit rlim; 10511294Sbill 105217519Sedward (void) getrlimit(lp->limconst, &rlim); 105318539Sedward if (hard) 105418539Sedward rlim.rlim_max = limit; 105518539Sedward else if (limit == RLIM_INFINITY && geteuid() != 0) 105616661Smckusick rlim.rlim_cur = rlim.rlim_max; 105716661Smckusick else 105817519Sedward rlim.rlim_cur = limit; 105918422Smckusick if (setrlimit(lp->limconst, &rlim) < 0) { 106018539Sedward printf("%s: %s: Can't %s%s limit\n", bname, lp->limname, 106118539Sedward limit == RLIM_INFINITY ? "remove" : "set", 106218539Sedward hard ? " hard" : ""); 106318422Smckusick return (-1); 106418422Smckusick } 106518422Smckusick return (0); 10661294Sbill } 10671294Sbill 10681294Sbill dosuspend() 10691294Sbill { 107039205Sbostic sig_t old; 107117138Sralph int ldisc, ctpgrp; 10721294Sbill 10731294Sbill if (loginsh) 10741294Sbill error("Can't suspend a login shell (yet)"); 10751294Sbill untty(); 107617138Sralph old = signal(SIGTSTP, SIG_DFL); 107717519Sedward (void) kill(0, SIGTSTP); 10781294Sbill /* the shell stops here */ 107917519Sedward (void) signal(SIGTSTP, old); 10801294Sbill if (tpgrp != -1) { 10811294Sbill retry: 108217519Sedward (void) ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp); 10831294Sbill if (ctpgrp != opgrp) { 108417138Sralph old = signal(SIGTTIN, SIG_DFL); 108517519Sedward (void) kill(0, SIGTTIN); 108617519Sedward (void) signal(SIGTTIN, old); 10871294Sbill goto retry; 10881294Sbill } 108939545Smarc (void) setpgrp(0, shpgrp); 109017519Sedward (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp); 10911294Sbill } 10921294Sbill } 10931294Sbill 10941294Sbill doeval(v) 10951294Sbill char **v; 10961294Sbill { 10971294Sbill char **oevalvec = evalvec; 10981294Sbill char *oevalp = evalp; 10991294Sbill jmp_buf osetexit; 11001294Sbill int reenter; 11011294Sbill char **gv = 0; 11021294Sbill 11031294Sbill v++; 11041294Sbill if (*v == 0) 11051294Sbill return; 110617519Sedward gflag = 0, tglob(v); 11071294Sbill if (gflag) { 110847412Sbostic gv = v = globall(v); 11091294Sbill gargv = 0; 11101294Sbill if (v == 0) 11111294Sbill error("No match"); 11121294Sbill v = copyblk(v); 11131294Sbill } else 111417519Sedward trim(v); 11151294Sbill getexit(osetexit); 11161294Sbill reenter = 0; 111747724Sbostic (void)setjmp(reslab); 11181294Sbill reenter++; 11191294Sbill if (reenter == 1) { 11201294Sbill evalvec = v; 11211294Sbill evalp = 0; 11221294Sbill process(0); 11231294Sbill } 11241294Sbill evalvec = oevalvec; 11251294Sbill evalp = oevalp; 11261294Sbill doneinp = 0; 11271294Sbill if (gv) 11281294Sbill blkfree(gv); 11291294Sbill resexit(osetexit); 11301294Sbill if (reenter >= 2) 11311294Sbill error(NOSTR); 11321294Sbill } 1133