1
0
Files
irix-657m-src/eoe/cmd/csh/sh.func.c
2022-09-29 17:59:04 +03:00

1466 lines
26 KiB
C

/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
/* UNIX System Laboratories, Inc. */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "$Revision: 2.13 $"
/*******************************************************************
PROPRIETARY NOTICE (Combined)
This source code is unpublished proprietary information
constituting, or derived under license from AT&T's UNIX(r) System V.
In addition, portions of such source code were derived from Berkeley
4.3 BSD under license from the Regents of the University of
California.
Copyright Notice
Notice of copyright on this source code product does not indicate
publication.
(c) 1986,1987,1988,1989 Sun Microsystems, Inc
(c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
All rights reserved.
********************************************************************/
#include <sys/types.h>
#include <sys/syssgi.h>
#include <locale.h> /* For LC_ALL */
#include <unistd.h>
#include <pfmt.h>
#include "sh.h"
#include "sh.proc.h"
#include "sh.wconst.h"
struct limits {
int limconst;
wchar_t *limname;
int limdiv;
wchar_t *limscale;
};
static void doagain(void);
static void echo(wchar_t, wchar_t **);
static struct limits *findlim(wchar_t *);
static rlim_t getval(struct limits *, wchar_t **);
static int getword(wchar_t *);
static void islogin(void);
static void limtail(wchar_t *, wchar_t *);
static void plim(struct limits *, wchar_t);
static void preread_(void);
static void reexecute(struct command *);
static int setlim(struct limits *, wchar_t, rlim_t);
static void toend(void);
static void unsetenv(wchar_t *);
/*
* C shell
*/
static void
dolabel(void)
{
#ifdef TRACE
tprintf("TRACE- dolabel()\n");
#endif
}
static struct biltins label = { S_, (bf_t)dolabel, 0, 0 };
static struct biltins foregnd = { S_Pjob, (bf_t)dofg1, 0, 0 };
static struct biltins backgnd = { S_PjobAND, (bf_t)dobg1, 0, 0 };
static void
preread_(void)
{
#ifdef TRACE
tprintf("TRACE- preread()\n");
#endif
whyles->w_end = -1;
if(setintr)
(void)sigsetmask(sigblock(0) & ~sigmask(SIGINT));
search(ZBREAK, 0, (wchar_t *)0);
if(setintr)
(void)sigblock(sigmask(SIGINT));
whyles->w_end = btell();
}
struct biltins *
isbfunc(struct command *t)
{
register wchar_t *cp = t->t_dcom[0];
register struct biltins *bp, *bp1, *bp2;
register int i;
#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;) {
bp = bp1 + ((bp2 - bp1) >> 1);
if( !(i = *cp - *bp->bname) && !(i = wscmp(cp, bp->bname)) )
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(gettxt(_SGI_DMMX_csh_2fewargs, "Too few arguments"));
if(i > bp->maxargs)
bferr(gettxt(_SGI_DMMX_csh_2manyargs, "Too many arguments"));
(*bp->bfunct)(t->t_dcom, t);
}
void
doonintr(wchar_t **v)
{
register wchar_t *cp;
register wchar_t *vv = v[1];
#ifdef TRACE
tprintf("TRACE- doonintr()\n");
#endif
if(parintr == SIG_IGN)
return;
if(setintr && intty)
err_notfromtty();
cp = gointr, gointr = 0, xfree(cp);
if( !vv) {
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(void)
{
#ifdef TRACE
tprintf("TRACE- donohup()\n");
#endif
if(intty)
err_notfromtty();
if(setintr == 0) {
(void) signal(SIGHUP, SIG_IGN);
#ifdef CC
submit(getpid());
#endif
}
}
void
dozip(void)
{
}
void
prvars(void)
{
#ifdef TRACE
tprintf("TRACE- prvars()\n");
#endif
plist(&shvhed);
}
void
doalias(wchar_t **v)
{
register struct varent *vp;
register wchar_t *p;
#ifdef TRACE
tprintf("TRACE- doalias()\n");
#endif
v++; /* 'alias' already checked */
p = *v++;
if( !p)
plist(&aliases);
else if( !*v) {
vp = adrof1(strip(p), &aliases);
if(vp)
blkpr(vp->vec), shprintf("\n");
} else {
if(eq(p, S_alias) || eq(p, S_unalias)) {
setname(p);
bferr(gettxt(_SGI_DMMX_csh_xalias,
"Too dangerous to alias that"));
}
set1(strip(p), saveblk(v), &aliases);
}
}
void
unalias(wchar_t **v)
{
#ifdef TRACE
tprintf("TRACE- unalias()\n");
#endif
unset1(v, &aliases);
}
void
dologout(void)
{
#ifdef TRACE
tprintf("TRACE- dologout()\n");
#endif
islogin();
goodbye();
}
void
dologin(wchar_t **v)
{
register char *v_;
#ifdef TRACE
tprintf("TRACE- dologin()\n");
#endif
islogin();
rechist();
(void)signal(SIGTERM, parterm);
if(v[1])
v_ = tstostr(NOSTR, v[1], 0); /* No need to free */
else
v_ = 0;
execl("/bin/login", "login", v_, 0);
untty();
done(1);
}
#ifdef NEWGRP
void
donewgrp(wchar_t **v)
{
register char *v_;
#ifdef TRACE
tprintf("TRACE- donewgrp()\n");
#endif
if( !chkstop && setintr)
panystop(0);
(void)signal(SIGTERM, parterm);
if(v[1])
v_ = tstostr(NOSTR, v[1], 0); /* No need to free */
else
v_ = 0;
execl("/bin/newgrp", "newgrp", v_, 0);
execl("/usr/bin/newgrp", "newgrp", v_, 0);
untty();
done(1);
}
#endif
static void
islogin(void)
{
#ifdef TRACE
tprintf("TRACE- islogin()\n");
#endif
if( !chkstop && setintr) {
panystop(0);
}
if(loginsh)
return;
err_notlogin();
}
void
doif(wchar_t **v, struct command *kp)
{
register int i;
register wchar_t **vv;
#ifdef TRACE
tprintf("TRACE- doif()\n");
#endif
v++;
i = exp(&v);
vv = v;
if(*vv == NOSTR)
bferr(gettxt(_SGI_DMMX_csh_emptyIF, "Empty if"));
if(eq(*vv, S_then)) {
if(*++vv)
bferr(gettxt(_SGI_DMMX_csh_ImprTHEN, "Improper then"));
setname(S_then);
/*
* If expression was zero, then scan to else,
* otherwise just fall into following code.
*/
if( !i)
search(ZIF, 0, (wchar_t *)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.
*/
static 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(void)
{
#ifdef TRACE
tprintf("TRACE- doelse()\n");
#endif
search(ZELSE, 0, (wchar_t *)0);
}
void
dogoto(wchar_t **v)
{
register struct whyle *wp;
register wchar_t *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, (wchar_t *)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(wchar_t **v)
{
register wchar_t *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:
syntaxerr();
search(ZSWITCH, 0, lp = globone(cp));
xfree(lp);
}
void
dobreak(void)
{
#ifdef TRACE
tprintf("TRACE- dobreak()\n");
#endif
if(whyles)
toend();
else
err_notinwf();
}
void
doexit(wchar_t **v)
{
#ifdef TRACE
tprintf("TRACE- doexit()\n");
#endif
if( !chkstop) {
panystop(0);
}
/*
* Don't DEMAND parentheses here either.
*/
v++;
if(*v) {
set(S_status, putn(exp(&v)));
if(*v)
err_experr();
}
btoeof();
if(intty)
(void)close(SHIN);
}
void
doforeach(wchar_t **v)
{
register wchar_t *cp;
register struct whyle *nwp;
#ifdef TRACE
tprintf("TRACE- doforeach()\n");
#endif
v++;
cp = strip(*v);
while (*cp && alnum(*cp))
cp++;
if(*cp || !letter(**v))
bferr(gettxt(_SGI_DMMX_csh_invvar, "Invalid variable"));
cp = *v++;
if (v[0][0] != '(' || v[blklen(v)-1][0] != ')')
bferr(gettxt(_SGI_DMMX_csh_wordsned, "Words not ()'ed"));
v++;
gflag = 0, tglob(v);
v = glob(v);
if (v == 0)
err_nomatch();
nwp = (struct whyle *)salloc(1, sizeof(struct whyle));
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(wchar_t **v)
{
register int status;
register struct whyle *nwp;
register bool again;
#ifdef TRACE
tprintf("TRACE- dowhile()\n");
#endif
again = (whyles
&& (whyles->w_start == lineloc)
&& (whyles->w_fename == 0));
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)
err_experr();
if( !again) {
nwp = (struct whyle *)salloc(1, sizeof(struct whyle));
nwp->w_start = lineloc;
nwp->w_end = 0;
nwp->w_next = whyles;
whyles = nwp;
if(intty) {
preread_(); /* tty preread */
doagain();
return;
}
}
if(status)
toend(); /* ain't gonna loop no more */
}
void
doend(void)
{
#ifdef TRACE
tprintf("TRACE- doend()\n");
#endif
if( !whyles)
err_notinwf();
whyles->w_end = btell();
doagain();
}
void
docontin(void)
{
#ifdef TRACE
tprintf("TRACE- docontin()\n");
#endif
if( !whyles)
err_notinwf();
doagain();
}
static void
doagain(void)
{
#ifdef TRACE
tprintf("TRACE- doagain()\n");
#endif
/*
* Repeating a while is simple
*/
if( !whyles->w_fename) {
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(wchar_t **v, struct command *kp)
{
register 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(void)
{
#ifdef TRACE
tprintf("TRACE- doswbrk()\n");
#endif
search(ZBRKSW, 0, (wchar_t *)0);
}
int
srchx(wchar_t *cp)
{
register struct srch *sp, *sp1, *sp2;
register 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) && !(i = wscmp(cp, sp->s_name)))
return(sp->s_value);
if(i < 0)
sp2 = sp;
else
sp1 = sp + 1;
}
return(-1);
}
wchar_t Stype;
wchar_t *Sgoal;
void
search(int type, int level, wchar_t *goal)
{
register wchar_t *aword;
register wchar_t *cp;
wchar_t wordbuf[CSHBUFSIZ];
#ifdef TRACE
tprintf("TRACE- search()\n");
#endif
aword = wordbuf;
Stype = type; Sgoal = goal;
if (type == ZGOTO)
bseek((off_t)0);
do {
if (intty && fseekp == feobp)
shprintf("? "), 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[wslen(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[wslen(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);
}
static int
getword(wchar_t *wp)
{
register int found = 0;
int first;
register wchar_t 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);
}
unreadc(c);
found = 1;
first = 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;
*wp = '\0'; /* end the string before test */
}
if (!first && !d && c == '(') {
if (wp) {
unreadc(c);
*--wp = '\0';
return found;
}
else
break;
}
first = 0;
} while ((d || !issp(c) ) && c != '\n');
/*WAS: } while ((d || c != ' ' && c != '\t') && c != '\n');*/
} while (wp == 0);
unreadc(c);
if (found)
*--wp = '\0';
return (found);
past:
switch(Stype) {
case ZIF:
bferr(gettxt(_SGI_DMMX_csh_tenotfnd, "then/endif not found"));
case ZELSE:
bferr(gettxt(_SGI_DMMX_csh_endif, "endif not found"));
case ZBRKSW:
case ZSWITCH:
bferr(gettxt(_SGI_DMMX_csh_endsw, "endsw not found"));
case ZBREAK:
bferr(gettxt(_SGI_DMMX_csh_end, "end not found"));
case ZGOTO:
setname(Sgoal);
bferr(gettxt(_SGI_DMMX_csh_label, "label not found"));
}
/*NOTREACHED*/
}
static void
toend(void)
{
#ifdef TRACE
tprintf("TRACE- toend()\n");
#endif
if (whyles->w_end == 0) {
search(ZBREAK, 0, (wchar_t *)0);
whyles->w_end = btell() - 1;
} else
bseek(whyles->w_end);
wfree();
}
void
wfree(void)
{
off_t o = btell();
#ifdef TRACE
tprintf("TRACE- wfree()\n");
#endif
while (whyles) {
register struct whyle *wp = whyles;
register 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(wp);
whyles = nwp;
}
}
void
doecho(wchar_t **v)
{
#ifdef TRACE
tprintf("TRACE- doecho()\n");
#endif
echo(' ', v);
}
void
doglob(wchar_t **v)
{
#ifdef TRACE
tprintf("TRACE- doglob()\n");
#endif
echo(0, v);
flush();
}
static void
echo(wchar_t sep, wchar_t **v)
{
register wchar_t *cp;
int nonl = 0;
#ifdef TRACE
tprintf("TRACE- echo()\n");
#endif
if (setintr)
(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
v++;
if (*v == 0) {
if (sep)
wputchar('\n');
return;
}
gflag = 0, tglob(v);
if (gflag) {
v = glob(v);
if (v == 0)
err_nomatch();
} else
trim(v);
if((sep == ' ') && *v && !wscmp(*v, S_n))
nonl++, v++;
while (cp = *v++) {
register int c;
/* handle back-slash processing */
while (c = *cp++) {
if (c == '\\')
switch (c = *cp++) {
case 'c':
nonl++;
break;;
case 'b':
wputchar('\b' | QUOTE);
break;
case 'f':
wputchar('\f' | QUOTE);
break;
case 'n':
wputchar('\n' | QUOTE);
break;
case 'r':
wputchar('\r' | QUOTE);
break;
case 't':
wputchar('\t' | QUOTE);
break;
case '\\':
wputchar('\\' | QUOTE);
break;
case '\000':
wputchar('\\' | QUOTE);
cp--;
break;
/*
* pdc: change to allow \0xxx, which is
* what /bin/echo takes, and \nnn, which
* is the irix 4.0 csh syntax. Basically,
* if we see a leading zero, don't count
* it.
*/
default:
if (c >= '0' && c <= '7') { /* 1 */
int val;
if (c == '0') { /* echo compat */
c = *cp++; /* new 1 */
}
val = c - '0';
c = *cp;
if (c >= '0' && c <= '7') { /* 2 */
val = val * 8 + c - '0';
cp++;
c = *cp;
if (c >= '0' && c <= '7') { /* 3 */
val = val * 8 + c - '0';
cp++;
}
}
wputchar((wchar_t)(val | QUOTE));
} else {
wputchar('\\' | QUOTE);
wputchar((wchar_t)(c | QUOTE));
}
break;
}
else
wputchar((wchar_t)(c | QUOTE));
}
if (*v)
wputchar((wchar_t)(sep | QUOTE));
}
if (sep && nonl == 0)
wputchar('\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.
*/
static bool
islocalevar(wchar_t *vp)
{
static wchar_t *categories_we_care[] = {
S_LANG,
S_LC_CTYPE,
S_LC_MESSAGES,
NOSTR
};
register wchar_t **p;
p = categories_we_care;
do {
if( !wscmp(vp, *p))
return(1);
} while(*(++p));
return(0);
}
void
dosetenv(wchar_t **v)
{
register char **ep;
register wchar_t *vp, *lp;
char chbuf[CSHBUFSIZ];
#ifdef TRACE
tprintf("TRACE- dosetenv()\n");
#endif
v++;
if( !(vp = *v++)) {
if(setintr)
(void)sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
for(ep = environ; *ep; ep++)
shprintf("%s\n", *ep);
return;
}
if( !(lp = *v++))
lp = S_;
setenv(vp, lp = globone(lp));
if(eq(vp, S_PATH)) {
importpath(lp);
dohash();
} else {
/*
* if locale is affected, change it
*/
if(islocalevar(vp)) {
if( !setlocale(LC_ALL, "") && intty ) {
showstr(MM_INFO,
gettxt(_SGI_DMMX_csh_illlocale,
"%s: Invalid locale - csh locale unchanged"),
tstostr(chbuf, lp, NOFLAG));
}
}
}
xfree(lp);
}
void
dounsetenv(wchar_t **v)
{
bool locale_changed=0;
#ifdef TRACE
tprintf("TRACE- dounsetenv()\n");
#endif
v++;
do{
unsetenv(*v);
if(islocalevar(*v++)) locale_changed=1;
}while (*v);
if(locale_changed) setlocale(LC_ALL, "");/* Hope no error! */
}
void
setenv(wchar_t *name, wchar_t *val)
{
register wchar_t *cp, *ep;
register char *s;
#ifdef TRACE
tprintf("TRACE- setenv(%t, %t)\n", name, val);
#endif
cp = strspl(S_EQ, val);
ep = strspl(name, cp);
xfree(cp);
s = tstostr(NOSTR, ep, NOFLAG);
xfree(ep);
putenv(s);
}
static void
unsetenv(wchar_t *name)
{
register char **ep = environ;
register char **oep = ep;
register int n;
char *dp;
char *cp_; /* tmp use */
#ifdef TRACE
tprintf("TRACE- unsetenv()\n");
#endif
for(; *ep; ep++) {
if((n = cmpmbwc(name, *ep, &dp)) < 0) {
illmbchar(*ep);
illenvvar(*ep);
continue;
}
if(name[n] || (*dp != '='))
continue;
cp_ = *ep;
*ep = 0;
environ = blkspl_(environ, ep+1);
*ep = cp_;
xfree(cp_);
xfree(oep);
return;
}
}
void
doumask(wchar_t **v)
{
register wchar_t *cp = v[1];
register int i;
#ifdef TRACE
tprintf("TRACE- dounmask()\n");
#endif
if (cp == 0) {
i = (int)umask(0);
(void) umask(i);
shprintf("%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(gettxt(_SGI_DMMX_csh_imprmask, "Improper mask"));
(void) umask(i);
}
struct limits 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_RSS, S_memorysize/*"memoryuse"*/, 1024,S_kbytes/*"kbytes*/,
#ifdef RLIMIT_NOFILE /* SunOS 4.1 and later. */
RLIMIT_NOFILE, S_descriptors, 1, S_,
#endif
#ifdef RLIMIT_VMEM
RLIMIT_VMEM, S_vmemoryuse, 1024, S_kbytes,
#endif
#ifdef RLIMIT_PTHREAD
RLIMIT_PTHREAD, S_threads, 1, S_,
#endif
-1, 0,
};
static struct limits *
findlim(wchar_t *cp)
{
register 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)
ambiguous();
res = lp;
}
if (res)
return (res);
bferr(gettxt(_SGI_DMMX_csh_nolimit, "No such limit"));
/*NOTREACHED*/
}
void
dolimit(wchar_t **v)
{
wchar_t hard = 0;
register struct limits *lp;
register rlim_t limit;
#ifdef TRACE
tprintf("TRACE- dolimit()\n");
#endif
v++;
if (*v && eq(*v, S_h/*"-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;
}
limit = (rlim_t) getval(lp, v+1);
if (setlim(lp, hard, limit) < 0)
error(NOSTR);
}
static rlim_t
getval(struct limits *lp, wchar_t **v)
{
register double f;
wchar_t *cp = *v++;
#ifdef TRACE
tprintf("TRACE- getval()\n");
#endif
f = atof_(cp);
while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
cp++;
if (*cp == 0) {
if (*v == 0)
return ((rlim_t)(f+0.5) * lp->limdiv);
cp = *v;
}
switch (*cp) {
case ':':
if (lp->limconst != RLIMIT_CPU)
goto badscal;
return ((rlim_t)(f * 60.0 + atof_(cp+1)));
case 'h':
if (lp->limconst != RLIMIT_CPU)
goto badscal;
limtail(cp, S_hours/*"hours"*/);
f *= 3600.;
break;
case 'm':
if (lp->limconst == RLIMIT_CPU) {
limtail(cp, S_minutes/*"minutes"*/);
f *= 60.;
break;
}
case 'M':
if (lp->limconst == RLIMIT_CPU)
goto badscal;
*cp = 'm';
limtail(cp, S_megabytes/*"megabytes"*/);
f *= 1024.*1024.;
break;
case 's':
if (lp->limconst != RLIMIT_CPU)
goto badscal;
limtail(cp, S_seconds/*"seconds"*/);
break;
case 'k':
if (lp->limconst == RLIMIT_CPU)
goto badscal;
limtail(cp, S_kbytes/*"kbytes"*/);
f *= 1024;
break;
case 'u':
limtail(cp, S_unlimited/*"unlimited"*/);
return (RLIM_INFINITY);
default:
badscal:
bferr(gettxt(_SGI_DMMX_csh_illscale,
"Improper or unknown scale factor"));
}
return ((rlim_t)(f+0.5));
}
static void
limtail(wchar_t *cp, wchar_t *str0)
{
register wchar_t *str = str0;
char chbuf[CSHBUFSIZ];
#ifdef TRACE
tprintf("TRACE- limtail()\n");
#endif
while(*cp && *cp == *str)
cp++, str++;
if(*cp)
error(gettxt(_SGI_DMMX_csh_badscal,
"Bad scaling; did you mean ``%s''?"),
tstostr(chbuf, str0, NOFLAG));
}
static void
plim(struct limits *lp, wchar_t hard)
{
struct rlimit rlim;
rlim_t limit;
#ifdef TRACE
tprintf("TRACE- plim()\n");
#endif
shprintf("%t \t", lp->limname);
(void) getrlimit(lp->limconst, &rlim);
limit = hard ? rlim.rlim_max : rlim.rlim_cur;
if (limit == RLIM_INFINITY)
shprintf("unlimited");
else if (lp->limconst == RLIMIT_CPU)
psecs(limit);
else
shprintf("%lld %t", limit / lp->limdiv, lp->limscale);
shprintf("\n");
}
void
dounlimit(wchar_t **v)
{
register struct limits *lp;
int err = 0;
wchar_t hard = 0;
#ifdef TRACE
tprintf("TRACE- dounlimit()\n");
#endif
v++;
if (*v && eq(*v, S_h/*"-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);
}
}
static int
setlim(struct limits *lp, wchar_t 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) {
shprintf("%t: %t: Can't %s%s limit\n", bname, lp->limname,
limit == RLIM_INFINITY ? "remove" : "set",
hard ? " hard" : "");
return (-1);
}
return (0);
}
void
dosuspend(void)
{
int ctpgrp;
void (*old)();
#ifdef TRACE
tprintf("TRACE- dosuspend()\n");
#endif
if (loginsh)
error(gettxt(_SGI_DMMX_csh_cantsusp,
"Can't suspend a login shell (yet)"));
untty();
old = signal(SIGTSTP, SIG_DFL);
(void) kill(0, SIGTSTP);
/* the shell stops here */
(void) signal(SIGTSTP, old);
if (tpgrp != -1) {
retry:
ctpgrp = tcgetpgrp(FSHTTY);
if (ctpgrp != opgrp) {
old = signal(SIGTTIN, SIG_DFL);
(void) kill(0, SIGTTIN);
(void) signal(SIGTTIN, old);
goto retry;
}
(void) setpgid(0, shpgrp);
(void) tcsetpgrp(FSHTTY, shpgrp);
}
}
void
doeval(wchar_t **v)
{
wchar_t **oevalvec = evalvec;
wchar_t *oevalp = evalp;
jmp_buf osetexit;
volatile int reenter;
wchar_t **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)
err_nomatch();
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);
}