diff options
Diffstat (limited to 'usr/src/cmd/csh/sh.func.c')
| -rw-r--r-- | usr/src/cmd/csh/sh.func.c | 1645 |
1 files changed, 1645 insertions, 0 deletions
diff --git a/usr/src/cmd/csh/sh.func.c b/usr/src/cmd/csh/sh.func.c new file mode 100644 index 0000000000..c69f8882e1 --- /dev/null +++ b/usr/src/cmd/csh/sh.func.c @@ -0,0 +1,1645 @@ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley Software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "sh.h" +#include <locale.h> /* For LC_ALL */ +#include "sh.tconst.h" +#include <sys/types.h> +#include <stdlib.h> + +/* + * N.B.: Some of the limits change from SunOS 4.x to SunOS 5.0. In + * particular, RLIMIT_RSS is gone and RLIMIT_VMEM is new. Beware of consusing + * the keywords that the command prints for these two. The old one was + * "memoryuse" and the new one is "memorysize". Note also that a given limit + * doesn't necessarily appear in the same position in the two releases. + */ +struct limits { + int limconst; + tchar *limname; + int limdiv; + tchar *limscale; +} limits[] = { + RLIMIT_CPU, S_cputime, /* "cputime" */ + 1, S_seconds, /* "seconds" */ + RLIMIT_FSIZE, S_filesize, /* "filesize" */ + 1024, S_kbytes, /* "kbytes" */ + RLIMIT_DATA, S_datasize, /* "datasize" */ + 1024, S_kbytes, /* "kbytes" */ + RLIMIT_STACK, S_stacksize, /* "stacksize" */ + 1024, S_kbytes, /* "kbytes" */ + RLIMIT_CORE, S_coredumpsize, /* "coredumpsize" */ + 1024, S_kbytes, /* "kbytes" */ + RLIMIT_NOFILE, S_descriptors, /* "descriptors" */ + 1, S_, /* "" */ + RLIMIT_VMEM, S_memorysize, /* "memorysize" */ + 1024, S_kbytes, /* "kbytes" */ + -1, 0, +}; + +static int getval(struct limits *lp, tchar **v, rlim_t *); +void islogin(); +int dolabel(); +void reexecute(struct command *kp); +void preread_(); +void doagain(); +void toend(); +void wfree(); +void echo(tchar sep, tchar **v); +void local_setenv(tchar *name, tchar *val); +void local_unsetenv(tchar *name); +void limtail(tchar *cp, tchar *str0); +void plim(struct limits *lp, tchar hard); +void search(); + +#define BUFSZ 1028 + +/* + * C shell + */ + +struct +biltins * +isbfunc(struct command *t) +{ + tchar *cp = t->t_dcom[0]; + struct biltins *bp, *bp1, *bp2; + int dofg1(), dobg1(); + + static struct biltins label = { S_, dolabel, 0, 0 }; + static struct biltins foregnd = { S_Pjob, dofg1, 0, 0 }; + static struct biltins backgnd = { S_PjobAND, dobg1, 0, 0 }; +#ifdef TRACE + tprintf("TRACE- isbfunc()\n"); +#endif + if (lastchr(cp) == ':') { + label.bname = cp; + return (&label); + } + if (*cp == '%') { + if (t->t_dflg & FAND) { + t->t_dflg &= ~FAND; + backgnd.bname = cp; + return (&backgnd); + } + foregnd.bname = cp; + return (&foregnd); + } + /* + * Binary search + * Bp1 is the beginning of the current search range. + * Bp2 is one past the end. + */ + for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2; ) { + int i; + + bp = bp1 + (bp2 - bp1 >> 1); + if ((i = *cp - *bp->bname) == 0 && + (i = strcmp_(cp, bp->bname)) == 0) { + return (bp); + } + if (i < 0) { + bp2 = bp; + } else { + bp1 = bp + 1; + } + } + return (0); +} + +void +func(struct command *t, struct biltins *bp) +{ + int i; + +#ifdef TRACE + tprintf("TRACE- func()\n"); +#endif + xechoit(t->t_dcom); + setname(bp->bname); + i = blklen(t->t_dcom) - 1; + if (i < bp->minargs) { + bferr("Too few arguments"); + } + if (i > bp->maxargs) { + bferr("Too many arguments"); + } + (*bp->bfunct)(t->t_dcom, t); +} + +int +dolabel() +{ +#ifdef TRACE + tprintf("TRACE- dolabel()\n"); +#endif + +} + +void +doonintr(tchar **v) +{ + tchar *cp; + tchar *vv = v[1]; + +#ifdef TRACE + tprintf("TRACE- doonintr()\n"); +#endif + if (parintr == SIG_IGN) { + return; + } + if (setintr && intty) { + bferr("Can't from terminal"); + } + cp = gointr, gointr = 0, xfree(cp); + if (vv == 0) { + if (setintr) { + (void) sigblock(sigmask(SIGINT)); + } else { + (void) signal(SIGINT, SIG_DFL); + } + gointr = 0; + } else if (eq((vv = strip(vv)), S_MINUS)) { + (void) signal(SIGINT, SIG_IGN); + gointr = S_MINUS; + } else { + gointr = savestr(vv); + (void) signal(SIGINT, pintr); + } +} + +void +donohup() +{ + +#ifdef TRACE + tprintf("TRACE- donohup()\n"); +#endif + if (intty) { + bferr("Can't from terminal"); + } + if (setintr == 0) { + (void) signal(SIGHUP, SIG_IGN); +#ifdef CC + submit(getpid()); +#endif + } +} + +void +dozip() +{ + ; +} + +void +prvars() +{ +#ifdef TRACE + tprintf("TRACE- prvars()\n"); +#endif + + plist(&shvhed); +} + +void +doalias(tchar **v) +{ + struct varent *vp; + tchar *p; + +#ifdef TRACE + tprintf("TRACE- doalias()\n"); +#endif + v++; + p = *v++; + if (p == 0) { + plist(&aliases); + } else if (*v == 0) { + vp = adrof1(strip(p), &aliases); + if (vp) { + blkpr(vp->vec), printf("\n"); + } + } else { + if (eq(p, S_alias) || + eq(p, S_unalias)) { + setname(p); + bferr("Too dangerous to alias that"); + } + set1(strip(p), saveblk(v), &aliases); + } +} + +void +unalias(tchar **v) +{ + +#ifdef TRACE + tprintf("TRACE- unalias()\n"); +#endif + unset1(v, &aliases); +} + +void +dologout() +{ + +#ifdef TRACE + tprintf("TRACE- dologout()\n"); +#endif + islogin(); + goodbye(); +} + +void +dologin(tchar **v) +{ + + char *v_; /* work */ +#ifdef TRACE + tprintf("TRACE- dologin()\n"); +#endif + islogin(); + rechist(); + (void) signal(SIGTERM, parterm); + if (v[1] != NULL) { + v_ = tstostr(NULL, v[1]); /* No need to free */ + } else { + v_ = 0; + } + execl("/bin/login", "login", v_, 0); + untty(); + exit(1); +} + +#ifdef NEWGRP +void +donewgrp(tchar **v) +{ + + char *v_; /* work */ +#ifdef TRACE + tprintf("TRACE- donewgrp()\n"); +#endif + if (chkstop == 0 && setintr) { + panystop(0); + } + (void) signal(SIGTERM, parterm); + + if (v[1] != NULL) { + v_ = tstostr(NOSTR, v[1]); /* No need to free */ + } else { + v_ = 0; + } + execl("/bin/newgrp", "newgrp", v_, 0); + execl("/usr/bin/newgrp", "newgrp", v_, 0); + untty(); + exit(1); +} +#endif + +void +islogin() +{ + +#ifdef TRACE + tprintf("TRACE- islogin()\n"); +#endif + if (chkstop == 0 && setintr) { + panystop(0); + } + if (loginsh) { + return; + } + error("Not login shell"); +} + +void +doif(tchar **v, struct command *kp) +{ + int i; + tchar **vv; + +#ifdef TRACE + tprintf("TRACE- doif()\n"); +#endif + v++; + i = exp(&v); + vv = v; + if (*vv == NOSTR) { + bferr("Empty if"); + } + if (eq(*vv, S_then)) { + if (*++vv) { + bferr("Improper then"); + } + setname(S_then); + /* + * If expression was zero, then scan to else, + * otherwise just fall into following code. + */ + if (!i) { + search(ZIF, 0); + } + return; + } + /* + * Simple command attached to this if. + * Left shift the node in this tree, munging it + * so we can reexecute it. + */ + if (i) { + lshift(kp->t_dcom, vv - kp->t_dcom); + reexecute(kp); + donefds(); + } +} + +/* + * Reexecute a command, being careful not + * to redo i/o redirection, which is already set up. + */ +void +reexecute(struct command *kp) +{ + +#ifdef TRACE + tprintf("TRACE- reexecute()\n"); +#endif + kp->t_dflg &= FSAVE; + kp->t_dflg |= FREDO; + /* + * If tty is still ours to arbitrate, arbitrate it; + * otherwise dont even set pgrp's as the jobs would + * then have no way to get the tty (we can't give it + * to them, and our parent wouldn't know their pgrp, etc. + */ + execute(kp, tpgrp > 0 ? tpgrp : -1); +} + +void +doelse() +{ + +#ifdef TRACE + tprintf("TRACE- doelse()\n"); +#endif + search(ZELSE, 0); +} + +void +dogoto(tchar **v) +{ + struct whyle *wp; + tchar *lp; +#ifdef TRACE + tprintf("TRACE- dogoto()\n"); +#endif + + /* + * While we still can, locate any unknown ends of existing loops. + * This obscure code is the WORST result of the fact that we + * don't really parse. + */ + for (wp = whyles; wp; wp = wp->w_next) { + if (wp->w_end == 0) { + search(ZBREAK, 0); + wp->w_end = btell(); + } else { + bseek(wp->w_end); + } + } + search(ZGOTO, 0, lp = globone(v[1])); + xfree(lp); + /* + * Eliminate loops which were exited. + */ + wfree(); +} + +void +doswitch(tchar **v) +{ + tchar *cp, *lp; + +#ifdef TRACE + tprintf("TRACE- doswitch()\n"); +#endif + v++; + if (!*v || *(*v++) != '(') { + goto syntax; + } + cp = **v == ')' ? S_ : *v++; + if (*(*v++) != ')') { + v--; + } + if (*v) { +syntax: + error("Syntax error"); + } + search(ZSWITCH, 0, lp = globone(cp)); + xfree(lp); +} + +void +dobreak() +{ + +#ifdef TRACE + tprintf("TRACE- dobreak()\n"); +#endif + if (whyles) { + toend(); + } else { + bferr("Not in while/foreach"); + } +} + +void +doexit(tchar **v) +{ + +#ifdef TRACE + tprintf("TRACE- doexit()\n"); +#endif + if (chkstop == 0) { + panystop(0); + } + /* + * Don't DEMAND parentheses here either. + */ + v++; + if (*v) { + set(S_status, putn(exp(&v))); + if (*v) { + bferr("Expression syntax"); + } + } + btoeof(); + if (intty) { + (void) close(SHIN); + unsetfd(SHIN); + } +} + +void +doforeach(tchar **v) +{ + tchar *cp; + struct whyle *nwp; + +#ifdef TRACE + tprintf("TRACE- doforeach()\n"); +#endif + v++; + cp = strip(*v); + while (*cp && alnum(*cp)) { + cp++; + } + if (*cp || strlen_(*v) >= 20 || !letter(**v)) { + bferr("Invalid variable"); + } + cp = *v++; + if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') { + bferr("Words not ()'ed"); + } + v++; + gflag = 0, tglob(v); + v = glob(v); + if (v == 0) { + bferr("No match"); + } + nwp = (struct whyle *)calloc(1, sizeof (*nwp)); + nwp->w_fe = nwp->w_fe0 = v; gargv = 0; + nwp->w_start = btell(); + nwp->w_fename = savestr(cp); + nwp->w_next = whyles; + whyles = nwp; + /* + * Pre-read the loop so as to be more + * comprehensible to a terminal user. + */ + if (intty) { + preread_(); + } + doagain(); +} + +void +dowhile(tchar **v) +{ + int status; + bool again = whyles != 0 && whyles->w_start == lineloc && + whyles->w_fename == 0; + +#ifdef TRACE + tprintf("TRACE- dowhile()\n"); +#endif + v++; + /* + * Implement prereading here also, taking care not to + * evaluate the expression before the loop has been read up + * from a terminal. + */ + if (intty && !again) { + status = !exp0(&v, 1); + } else { + status = !exp(&v); + } + if (*v) { + bferr("Expression syntax"); + } + if (!again) { + struct whyle *nwp = (struct whyle *)calloc(1, sizeof (*nwp)); + + nwp->w_start = lineloc; + nwp->w_end = 0; + nwp->w_next = whyles; + whyles = nwp; + if (intty) { + /* + * The tty preread + */ + preread_(); + doagain(); + return; + } + } + if (status) { + /* We ain't gonna loop no more, no more! */ + toend(); + } +} + +void +preread_() +{ +#ifdef TRACE + tprintf("TRACE- preread()\n"); +#endif + + whyles->w_end = -1; + if (setintr) { + (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT)); + } + search(ZBREAK, 0); + if (setintr) { + (void) sigblock(sigmask(SIGINT)); + } + whyles->w_end = btell(); +} + +void +doend() +{ + +#ifdef TRACE + tprintf("TRACE- doend()\n"); +#endif + if (!whyles) { + bferr("Not in while/foreach"); + } + whyles->w_end = btell(); + doagain(); +} + +void +docontin() +{ +#ifdef TRACE + tprintf("TRACE- docontin()\n"); +#endif + + if (!whyles) { + bferr("Not in while/foreach"); + } + doagain(); +} + +void +doagain() +{ + +#ifdef TRACE + tprintf("TRACE- doagain()\n"); +#endif + /* Repeating a while is simple */ + if (whyles->w_fename == 0) { + bseek(whyles->w_start); + return; + } + /* + * The foreach variable list actually has a spurious word + * ")" at the end of the w_fe list. Thus we are at the + * of the list if one word beyond this is 0. + */ + if (!whyles->w_fe[1]) { + dobreak(); + return; + } + set(whyles->w_fename, savestr(*whyles->w_fe++)); + bseek(whyles->w_start); +} + +void +dorepeat(tchar **v, struct command *kp) +{ + int i, omask; + +#ifdef TRACE + tprintf("TRACE- dorepeat()\n"); +#endif + i = getn(v[1]); + if (setintr) { + omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); + } + lshift(v, 2); + while (i > 0) { + if (setintr) { + (void) sigsetmask(omask); + } + reexecute(kp); + --i; + } + donefds(); + if (setintr) { + (void) sigsetmask(omask); + } +} + +void +doswbrk() +{ + +#ifdef TRACE + tprintf("TRACE- doswbrk()\n"); +#endif + search(ZBRKSW, 0); +} + +int +srchx(tchar *cp) +{ + struct srch *sp, *sp1, *sp2; + int i; + +#ifdef TRACE + tprintf("TRACE- srchx()\n"); +#endif + /* + * Binary search + * Sp1 is the beginning of the current search range. + * Sp2 is one past the end. + */ + for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2; ) { + sp = sp1 + (sp2 - sp1 >> 1); + if ((i = *cp - *sp->s_name) == 0 && + (i = strcmp_(cp, sp->s_name)) == 0) { + return (sp->s_value); + } + if (i < 0) { + sp2 = sp; + } else { + sp1 = sp + 1; + } + } + return (-1); +} + +tchar Stype; +tchar *Sgoal; + +/*VARARGS2*/ +void +search(type, level, goal) + int type; int level; tchar *goal; +{ + tchar wordbuf[BUFSIZ]; + tchar *aword = wordbuf; + tchar *cp; + +#ifdef TRACE + tprintf("TRACE- search()\n"); +#endif + Stype = type; Sgoal = goal; + if (type == ZGOTO) { + bseek((off_t)0); + } + do { + if (intty && fseekp == feobp) { + printf("? "), flush(); + } + aword[0] = 0; + (void) getword(aword); + + switch (srchx(aword)) { + + case ZELSE: + if (level == 0 && type == ZIF) { + return; + } + break; + + case ZIF: + while (getword(aword)) { + continue; + } + if ((type == ZIF || type == ZELSE) && + eq(aword, S_then)) { + level++; + } + break; + + case ZENDIF: + if (type == ZIF || type == ZELSE) { + level--; + } + break; + + case ZFOREACH: + case ZWHILE: + if (type == ZBREAK) { + level++; + } + break; + + case ZEND: + if (type == ZBREAK) { + level--; + } + break; + + case ZSWITCH: + if (type == ZSWITCH || type == ZBRKSW) { + level++; + } + break; + + case ZENDSW: + if (type == ZSWITCH || type == ZBRKSW) { + level--; + } + break; + + case ZLABEL: + if (type == ZGOTO && getword(aword) && + eq(aword, goal)) { + level = -1; + } + break; + + default: + if (type != ZGOTO && (type != ZSWITCH || level != 0)) { + break; + } + if (lastchr(aword) != ':') { + break; + } + aword[strlen_(aword) - 1] = 0; + if (type == ZGOTO && eq(aword, goal) || + type == ZSWITCH && eq(aword, S_default)) { + level = -1; + } + break; + + case ZCASE: + if (type != ZSWITCH || level != 0) { + break; + } + (void) getword(aword); + if (lastchr(aword) == ':') { + aword[strlen_(aword) - 1] = 0; + } + cp = strip(Dfix1(aword)); + if (Gmatch(goal, cp)) { + level = -1; + } + xfree(cp); + break; + + case ZDEFAULT: + if (type == ZSWITCH && level == 0) { + level = -1; + } + break; + } + (void) getword(NOSTR); + } while (level >= 0); +} + +int +getword(tchar *wp) +{ + int found = 0; + int c, d; +#ifdef TRACE + tprintf("TRACE- getword()\n"); +#endif + + c = readc(1); + d = 0; + do { + while (issp(c)) { + c = readc(1); + } + if (c == '#') { + do { + c = readc(1); + } while (c >= 0 && c != '\n'); + } + if (c < 0) { + goto past; + } + if (c == '\n') { + if (wp) { + break; + } + return (0); + } + + /* ( and ) form separate words */ + if (c == '(' || c == ')') { + return (1); + } + + unreadc(c); + found = 1; + do { + c = readc(1); + if (c == '\\' && (c = readc(1)) == '\n') { + c = ' '; + } + if (c == '\'' || c == '"') { + if (d == 0) { + d = c; + } else if (d == c) { + d = 0; + } + } + if (c < 0) { + goto past; + } + if (wp) { + *wp++ = c; + } + } while ((d || !issp(c) && c != '(' && c != ')') && c != '\n'); + } while (wp == 0); + unreadc(c); + if (found) { + *--wp = 0; + } + return (found); + +past: + switch (Stype) { + + case ZIF: + bferr("then/endif not found"); + + case ZELSE: + bferr("endif not found"); + + case ZBRKSW: + case ZSWITCH: + bferr("endsw not found"); + + case ZBREAK: + bferr("end not found"); + + case ZGOTO: + setname(Sgoal); + bferr("label not found"); + } + /*NOTREACHED*/ +} + +void +toend() +{ + +#ifdef TRACE + tprintf("TRACE- toend()\n"); +#endif + if (whyles->w_end == 0) { + search(ZBREAK, 0); + whyles->w_end = btell() - 1; + } else { + bseek(whyles->w_end); + } + wfree(); +} + +void +wfree() +{ + long o = btell(); + +#ifdef TRACE + tprintf("TRACE- wfree()\n"); +#endif + while (whyles) { + struct whyle *wp = whyles; + struct whyle *nwp = wp->w_next; + + if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) { + break; + } + if (wp->w_fe0) { + blkfree(wp->w_fe0); + } + if (wp->w_fename) { + xfree(wp->w_fename); + } + xfree((char *)wp); + whyles = nwp; + } +} + +void +doecho(tchar **v) +{ + +#ifdef TRACE + tprintf("TRACE- doecho()\n"); +#endif + echo(' ', v); +} + +void +doglob(tchar **v) +{ + +#ifdef TRACE + tprintf("TRACE- doglob()\n"); +#endif + echo(0, v); + flush(); +} + +void +echo(tchar sep, tchar **v) +{ + tchar *cp; + int nonl = 0; + +#ifdef TRACE + tprintf("TRACE- echo()\n"); +#endif + if (setintr) { + (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT)); + } + v++; + if (*v == 0) { + /* + * echo command needs to have newline when there are no + * flags or arguments. glob should have no newline. If + * the separator is a blank, we are doing an echo. If the + * separator is zero, we are globbing. + */ + if (sep == (tchar)' ') + Putchar('\n'); + return; + } + gflag = 0, tglob(v); + if (gflag) { + v = glob(v); + if (v == 0) { + bferr("No match"); + } + } + /* check for -n arg, NOTE: it might be quoted */ + if (sep == ' ' && *v && strlen_(*v) == 2 && + ((**v&TRIM) == '-' && (*(*v + 1) & TRIM) == 'n' && + (*(*v+2)&TRIM) == 0)) { + nonl++, v++; + } + while (cp = *v++) { + int c; + + while (c = *cp++) { + Putchar(c | QUOTE); + } + if (*v) { + Putchar(sep | QUOTE); + } + } + if (sep && nonl == 0) { + Putchar('\n'); + } else { + flush(); + } + if (setintr) { + (void) sigblock(sigmask(SIGINT)); + } + if (gargv) { + blkfree(gargv), gargv = 0; + } +} + +extern char **environ; + +/* + * Check if the environment variable vp affects this csh's behavior + * and therefore we should call setlocale() or not. + * This function has two side effects when it returns 1: + * variable islocalevar_catnum is set to the LC_xxx value. + * variable islocalevar_catname is set to the string "LC_xxx" + */ +static int islocalevar_catnum; +static char *islocalevar_catname; + +static +bool +islocalevar(tchar *vp) +{ + static struct lcinfo { + tchar * evname; /* The name of the env. var. */ + } categories_we_care[] = { + S_LANG, S_LC_ALL, S_LC_CTYPE, S_LC_MESSAGES, + NOSTR /* assumption: LC_xxx >= 0 */ + }; + struct lcinfo *p = categories_we_care; + + do { + if (strcmp_(vp, p->evname) == 0) { + return (1); + } + } while (((++p)->evname) != NOSTR); + return (0); +} + +void +dosetenv(tchar **v) +{ + tchar *vp, *lp; + +#ifdef TRACE + tprintf("TRACE- dosetenv()\n"); +#endif + v++; + if ((vp = *v++) == 0) { + char **ep; + + if (setintr) { + (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT)); + } + for (ep = environ; *ep; ep++) { + printf("%s\n", *ep); + } + return; + } + + if ((lp = *v++) == 0) { + lp = S_; /* "" */ + } + local_setenv(vp, lp = globone(lp)); + if (eq(vp, S_PATH)) { + importpath(lp); + dohash(xhash); + } else if (islocalevar(vp)) { + if (!setlocale(LC_ALL, "")) { + error("Locale could not be set properly"); + } + } + + xfree(lp); +} + +void +dounsetenv(tchar **v) +{ +#ifdef TRACE + tprintf("TRACE- dounsetenv()\n"); +#endif + v++; + do { + local_unsetenv(*v); + if (islocalevar(*v++)) { + setlocale(LC_ALL, ""); /* Hope no error! */ + } + } while (*v); +} + +void +local_setenv(tchar *name, tchar *val) +{ + char **ep = environ; + tchar *cp; + char *dp; + tchar *ep_; /* temporary */ + char *blk[2], **oep = ep; + +#ifdef TRACE + /* tprintf("TRACE- local_setenv(%t, %t)\n", name, val); */ + /* printf("IN local_setenv args = (%t)\n", val); */ +#endif + for (; *ep; ep++) { +#ifdef MBCHAR + for (cp = name, dp = *ep; *cp && *dp; cp++) { + /* + * This loop compares two chars in different + * representations, EUC (as char *) and wchar_t + * (in tchar), and ends when they are different. + */ + wchar_t dwc; + int n; + + n = mbtowc(&dwc, dp, MB_CUR_MAX); + if (n <= 0) { + break; /* Illegal multibyte. */ + } + dp += n; /* Advance to next multibyte char. */ + if (dwc == (wchar_t)(*cp & TRIM)) { + continue; + } else { + break; + } + } +#else /* !MBCHAR */ + for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) { + continue; + } +#endif /* !MBCHAR */ + if (*cp != 0 || *dp != '=') { + continue; + } + cp = strspl(S_EQ, val); + xfree(*ep); + ep_ = strspl(name, cp); /* ep_ is xalloc'ed */ + xfree(cp); + /* + * Trimming is not needed here. + * trim(); + */ + *ep = tstostr(NULL, ep_); + xfree(ep_); /* because temp. use */ + return; + } + ep_ = strspl(name, S_EQ); /* ep_ is xalloc'ed */ + blk[0] = tstostr(NULL, ep_); + blk[1] = 0; + xfree(ep_); + environ = (char **)blkspl_((unsigned char **)environ, blk); + xfree((void *)oep); + local_setenv(name, val); +} + +void +local_unsetenv(tchar *name) +{ + char **ep = environ; + tchar *cp; + char *dp; + char **oep = ep; + char *cp_; /* tmp use */ + static cnt = 0; /* delete counter */ + +#ifdef TRACE + tprintf("TRACE- local_unsetenv()\n"); +#endif + for (; *ep; ep++) { +#ifdef MBCHAR + for (cp = name, dp = *ep; *cp && *dp; cp++) { + /* + * This loop compares two chars in different + * representations, EUC (as char *) and wchar_t + * (in tchar), and ends when they are different. + */ + wchar_t dwc; + int n; + + n = mbtowc(&dwc, dp, MB_CUR_MAX); + if (n <= 0) { + break; /* Illegal multibyte. */ + } + dp += n; /* Advance to next multibyte char. */ + if (dwc == (wchar_t)(*cp & TRIM)) { + continue; + } else { + break; + } + } +#else /* !MBCHAR */ + for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) { + continue; + } +#endif /* !MBCHAR */ + if (*cp != 0 || *dp != '=') { + continue; + } + cp_ = *ep; + *ep = 0; + environ = (char **)blkspl_((unsigned char **)environ, ep+1); + *ep = cp_; + xfree(cp_); + xfree((void *)oep); + return; + } +} + +void +doumask(tchar **v) +{ + tchar *cp = v[1]; + int i; + +#ifdef TRACE + tprintf("TRACE- dounmask()\n"); +#endif + if (cp == 0) { + i = umask(0); + (void) umask(i); + printf("%o\n", i); + return; + } + i = 0; + while (digit(*cp) && *cp != '8' && *cp != '9') { + i = i * 8 + *cp++ - '0'; + } + if (*cp || i < 0 || i > 0777) { + bferr("Improper mask"); + } + (void) umask(i); +} + + +struct limits * +findlim(tchar *cp) +{ + struct limits *lp, *res; + +#ifdef TRACE + tprintf("TRACE- findlim()\n"); +#endif + res = 0; + for (lp = limits; lp->limconst >= 0; lp++) { + if (prefix(cp, lp->limname)) { + if (res) { + bferr("Ambiguous"); + } + res = lp; + } + } + if (res) { + return (res); + } + bferr("No such limit"); + /*NOTREACHED*/ +} + +void +dolimit(tchar **v) +{ + struct limits *lp; + rlim_t limit; + tchar hard = 0; + +#ifdef TRACE + tprintf("TRACE- dolimit()\n"); +#endif + v++; + if (*v && eq(*v, S_h)) { + hard = 1; + v++; + } + if (*v == 0) { + for (lp = limits; lp->limconst >= 0; lp++) { + plim(lp, hard); + } + return; + } + lp = findlim(v[0]); + if (v[1] == 0) { + plim(lp, hard); + return; + } + switch (getval(lp, v+1, &limit)) { + case 0: + error("Value specified for limit is too large"); + return; + case (-1): + error("Numeric conversion failed"); + return; + default: + if (setlim(lp, hard, limit) < 0) { + error(NOSTR); + } + } +} + +static int +getval(struct limits *lp, tchar **v, rlim_t *retval) +{ + rlim_t value, tmp, tmp2; + tchar *cp = *v++; + char chbuf[BUFSIZ * MB_LEN_MAX]; + +#ifdef TRACE + tprintf("TRACE- getval()\n"); +#endif + + tstostr(chbuf, cp); + errno = 0; + value = strtoull(chbuf, NULL, 0); +/* + * we must accept zero, but the conversion can fail and give us + * zero as well...try to deal with it as gracefully as possible + * by checking for EINVAL + */ + if (value == 0 && errno == EINVAL) + return (-1); + + while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') { + cp++; + } + if (*cp == 0) { + if (*v == 0) { + tmp = value * (rlim_t)lp->limdiv; + /* Check for overflow */ + if (tmp >= value) { + *retval = tmp; + return (1); + } else { + return (0); + } + } + cp = *v; + } + switch (*cp) { + + case ':': + if (lp->limconst != RLIMIT_CPU) { + goto badscal; + } + tstostr(chbuf, cp + 1); + tmp = strtoull(chbuf, NULL, 0); + tmp2 = value * 60 + tmp; + if (tmp2 >= value) { + *retval = tmp2; + return (1); + } else { + return (0); + } + + case 'h': + if (lp->limconst != RLIMIT_CPU) { + goto badscal; + } + limtail(cp, S_hours); + tmp = value * 3600; + if (tmp < value) { + return (0); + } + value = tmp; + break; + + case 'm': + if (lp->limconst == RLIMIT_CPU) { + limtail(cp, S_minutes); + tmp = value * 60; + if (tmp < value) { + return (0); + } + value = tmp; + break; + } + case 'M': + if (lp->limconst == RLIMIT_CPU) { + goto badscal; + } + *cp = 'm'; + limtail(cp, S_megabytes); + tmp = value * 1024 * 1024; + if (tmp < value) { + return (0); + } + value = tmp; + break; + + case 's': + if (lp->limconst != RLIMIT_CPU) { + goto badscal; + } + limtail(cp, S_seconds); + break; + + case 'k': + if (lp->limconst == RLIMIT_CPU) { + goto badscal; + } + limtail(cp, S_kbytes); + tmp = value * 1024; + if (tmp < value) { + return (0); + } + value = tmp; + break; + + case 'u': + limtail(cp, S_unlimited); + *retval = RLIM_INFINITY; + return (1); + + default: +badscal: + bferr("Improper or unknown scale factor"); + } + *retval = value; + return (1); +} + +void +limtail(tchar *cp, tchar *str0) +{ + tchar *str = str0; +#ifdef TRACE + tprintf("TRACE- limtail()\n"); +#endif + + while (*cp && *cp == *str) { + cp++, str++; + } + if (*cp) { + error("Bad scaling; did you mean ``%t''?", str0); + } +} + +void +plim(struct limits *lp, tchar hard) +{ + struct rlimit rlim; + char buf[BUFSZ]; + char *pbuf; + rlim_t limit; + +#ifdef TRACE + tprintf("TRACE- plim()\n"); +#endif + printf("%t \t", lp->limname); + (void) getrlimit(lp->limconst, &rlim); + limit = hard ? rlim.rlim_max : rlim.rlim_cur; + if (limit == RLIM_INFINITY) { + printf("unlimited"); + } else if (lp->limconst == RLIMIT_CPU) { + psecs_ull(limit); + } else { + buf[BUFSZ - 1] = '\0'; + pbuf = ulltostr((limit / lp->limdiv), &buf[BUFSZ - 1]); + printf("%s %t", pbuf, lp->limscale); + } + printf("\n"); +} + +void +dounlimit(tchar **v) +{ + struct limits *lp; + int err = 0; + tchar hard = 0; +#ifdef TRACE + tprintf("TRACE- dounlimit()\n"); +#endif + + v++; + if (*v && eq(*v, S_h)) { + hard = 1; + v++; + } + if (*v == 0) { + for (lp = limits; lp->limconst >= 0; lp++) { + if (setlim(lp, hard, RLIM_INFINITY) < 0) { + err++; + } + } + if (err) { + error(NULL); + } + return; + } + while (*v) { + lp = findlim(*v++); + if (setlim(lp, hard, RLIM_INFINITY) < 0) { + error(NULL); + } + } +} + +int +setlim(struct limits *lp, tchar hard, rlim_t limit) +{ + struct rlimit rlim; + +#ifdef TRACE + tprintf("TRACE- setlim()\n"); +#endif + (void) getrlimit(lp->limconst, &rlim); + if (hard) { + rlim.rlim_max = limit; + } else if (limit == RLIM_INFINITY && geteuid() != 0) { + rlim.rlim_cur = rlim.rlim_max; + } else { + rlim.rlim_cur = limit; + } + if (setrlimit(lp->limconst, &rlim) < 0) { + printf("%t: %t: Can't %s%s limit\n", bname, lp->limname, + limit == RLIM_INFINITY ? "remove" : "set", + hard ? " hard" : ""); + return (-1); + } + return (0); +} + +void +dosuspend() +{ + int ctpgrp; + void (*old)(); + +#ifdef TRACE + tprintf("TRACE- dosuspend()\n"); +#endif + if (loginsh) { + error("Can't suspend a login shell (yet)"); + } + if (getpid() == getsid(0)) { + error("Can't suspend this shell"); + } + untty(); + old = (void (*)())signal(SIGTSTP, SIG_DFL); + (void) kill(0, SIGTSTP); + /* the shell stops here */ + (void) signal(SIGTSTP, old); + if (tpgrp != -1) { +retry: + (void) ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp); + if (ctpgrp != opgrp) { + old = (void (*)())signal(SIGTTIN, SIG_DFL); + (void) kill(0, SIGTTIN); + (void) signal(SIGTTIN, old); + goto retry; + } + (void) setpgid(0, shpgrp); + (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp); + } +} + +void +doeval(tchar **v) +{ + tchar **oevalvec = evalvec; + tchar *oevalp = evalp; + jmp_buf osetexit; + int reenter; + tchar **gv = 0; + +#ifdef TRACE + tprintf("TRACE- doeval()\n"); +#endif + v++; + if (*v == 0) { + return; + } + gflag = 0, tglob(v); + if (gflag) { + gv = v = glob(v); + gargv = 0; + if (v == 0) { + error("No match"); + } + v = copyblk(v); + } else { + trim(v); + } + getexit(osetexit); + reenter = 0; + setexit(); + reenter++; + if (reenter == 1) { + evalvec = v; + evalp = 0; + process(0); + } + evalvec = oevalvec; + evalp = oevalp; + doneinp = 0; + if (gv) { + blkfree(gv); + } + resexit(osetexit); + if (reenter >= 2) { + error(NULL); + } +} |
