diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/sh | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/sh')
44 files changed, 13333 insertions, 0 deletions
diff --git a/usr/src/cmd/sh/Makefile b/usr/src/cmd/sh/Makefile new file mode 100644 index 0000000000..4e34aad193 --- /dev/null +++ b/usr/src/cmd/sh/Makefile @@ -0,0 +1,89 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +PROG = sh +ROOTFS_PROG = $(PROG) + +OBJS= args.o blok.o cmd.o defs.o error.o fault.o hash.o hashserv.o \ + io.o msg.o print.o stak.o string.o word.o xec.o \ + ctype.o echo.o expand.o func.o macro.o pwd.o setbrk.o test.o \ + bltin.o jobs.o ulimit.o sh_policy.o main.o name.o service.o +SRCS= $(OBJS:%.o=%.c) + +include ../Makefile.cmd + +# This flag is being added only for SCO (x86) compatibility +CFLAGS += $(iBCS2FLAG) + +# +# for message cataloge +# +POFILE= sh.po +POFILES= $(SRCS:%.c=%.po) +XGETFLAGS += -a -x sh.xcl +CPPFLAGS += -D_FILE_OFFSET_BITS=64 -DACCT + +LAZYLIBS = $(ZLAZYLOAD) -lgen -lsecdb $(ZNOLAZYLOAD) +lint := LAZYLIBS = -lgen -lsecdb +LDLIBS += $(LAZYLIBS) +GROUP = root + +.KEEP_STATE: + +.PARALLEL: $(OBJS) + +all: $(ROOTFS_PROG) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +$(POFILE): $(POFILES) + $(RM) $@ + $(CAT) $(POFILES) > $@ + +install: all $(ROOTSBINPROG) + $(RM) $(ROOTSBIN)/jsh + $(SYMLINK) sh $(ROOTSBIN)/jsh + $(RM) $(ROOTSBIN)/pfsh + $(SYMLINK) sh $(ROOTSBIN)/pfsh + $(RM) $(ROOTBIN)/sh + $(SYMLINK) ../../sbin/sh $(ROOTBIN)/sh + $(RM) $(ROOTBIN)/jsh + $(SYMLINK) ../../sbin/sh $(ROOTBIN)/jsh + $(RM) $(ROOTBIN)/pfsh + $(SYMLINK) ../../sbin/sh $(ROOTBIN)/pfsh + $(RM) $(ROOTLIB)/rsh + $(SYMLINK) ../../sbin/sh $(ROOTLIB)/rsh + +clean: + $(RM) $(OBJS) + +lint: lint_SRCS + +include ../Makefile.targ diff --git a/usr/src/cmd/sh/args.c b/usr/src/cmd/sh/args.c new file mode 100644 index 0000000000..d0fe087e27 --- /dev/null +++ b/usr/src/cmd/sh/args.c @@ -0,0 +1,416 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10.4.1 */ + +/* + * UNIX shell + */ + +#include "defs.h" + +static struct dolnod *copyargs(); +static struct dolnod *freedolh(); +extern struct dolnod *freeargs(); +static struct dolnod *dolh; + +/* Used to save outermost positional parameters */ +static struct dolnod *globdolh; +static unsigned char **globdolv; +static int globdolc; + +unsigned char flagadr[16]; + +unsigned char flagchar[] = +{ + 'x', + 'n', + 'v', + 't', + STDFLG, + 'i', + 'e', + 'r', + 'k', + 'u', + 'h', + 'f', + 'a', + 'm', + 'p', + 0 +}; + +long flagval[] = +{ + execpr, + noexec, + readpr, + oneflg, + stdflg, + intflg, + errflg, + rshflg, + keyflg, + setflg, + hashflg, + nofngflg, + exportflg, + monitorflg, + privflg, + 0 +}; + +/* ======== option handling ======== */ + + +options(argc,argv) + unsigned char **argv; + int argc; +{ + register unsigned char *cp; + register unsigned char **argp = argv; + register unsigned char *flagc; + unsigned char *flagp; + int len; + wchar_t wc; + + if (argc > 1 && *argp[1] == '-') + { + /* + * if first argument is "--" then options are not + * to be changed. Fix for problems getting + * $1 starting with a "-" + */ + + cp = argp[1]; + if (cp[1] == '-') + { + argp[1] = argp[0]; + argc--; + return(argc); + } + if (cp[1] == '\0') + flags &= ~(execpr|readpr); + + /* + * Step along 'flagchar[]' looking for matches. + * 'sicrp' are not legal with 'set' command. + */ + cp++; + while (*cp) { + if ((len = mbtowc(&wc, (char *)cp, MB_LEN_MAX)) <= 0) { + len = 1; + wc = (unsigned char)*cp; + failed(argv[1],badopt); + } + cp += len; + + flagc = flagchar; + while (*flagc && wc != *flagc) + flagc++; + if (wc == *flagc) + { + if (eq(argv[0], "set") && any(wc, "sicrp")) + failed(argv[1], badopt); + else + { + flags |= flagval[flagc-flagchar]; + if (flags & errflg) + eflag = errflg; + } + } + else if (wc == 'c' && argc > 2 && comdiv == 0) + { + comdiv = argp[2]; + argp[1] = argp[0]; + argp++; + argc--; + } + else + failed(argv[1],badopt); + } + argp[1] = argp[0]; + argc--; + } + else if (argc > 1 && *argp[1] == '+') /* unset flags x, k, t, n, v, e, u */ + { + cp = argp[1]; + cp++; + while (*cp) + { + if ((len = mbtowc(&wc, (char *)cp, MB_LEN_MAX)) <= 0) { + cp++; + continue; + } + + flagc = flagchar; + while (*flagc && wc != *flagc) + flagc++; + /* + * step through flags + */ + if (!any(wc, "sicrp") && wc == *flagc) { + flags &= ~(flagval[flagc-flagchar]); + if (wc == 'e') + eflag = 0; + } + cp += len; + } + argp[1] = argp[0]; + argc--; + } + /* + * set up $- + */ + flagp = flagadr; + if (flags) + { + flagc = flagchar; + while (*flagc) + { + if (flags & flagval[flagc-flagchar]) + *flagp++ = *flagc; + flagc++; + } + } + *flagp = 0; + return(argc); +} + +/* + * sets up positional parameters + */ +setargs(argi) + unsigned char *argi[]; +{ + register unsigned char **argp = argi; /* count args */ + register int argn = 0; + + while (*argp++ != (unsigned char *)ENDARGS) + argn++; + /* + * free old ones unless on for loop chain + */ + freedolh(); + dolh = copyargs(argi, argn); + dolc = argn - 1; +} + + +static struct dolnod * +freedolh() +{ + register unsigned char **argp; + register struct dolnod *argblk; + + if (argblk = dolh) + { + if ((--argblk->doluse) == 0) + { + for (argp = argblk->dolarg; *argp != (unsigned char *)ENDARGS; argp++) + free(*argp); + free(argblk->dolarg); + free(argblk); + } + } +} + +struct dolnod * +freeargs(blk) + struct dolnod *blk; +{ + register unsigned char **argp; + register struct dolnod *argr = 0; + register struct dolnod *argblk; + int cnt; + + if (argblk = blk) + { + argr = argblk->dolnxt; + cnt = --argblk->doluse; + + if (argblk == dolh) + { + if (cnt == 1) + return(argr); + else + return(argblk); + } + else + { + if (cnt == 0) + { + for (argp = argblk->dolarg; *argp != (unsigned char *)ENDARGS; argp++) + free(*argp); + free(argblk->dolarg); + free(argblk); + } + } + } + return(argr); +} + +static struct dolnod * +copyargs(from, n) + unsigned char *from[]; +{ + register struct dolnod *np = (struct dolnod *)alloc(sizeof(struct dolnod)); + register unsigned char **fp = from; + register unsigned char **pp; + + np -> dolnxt = 0; + np->doluse = 1; /* use count */ + pp = np->dolarg = (unsigned char **)alloc((n+1)*sizeof(char *)); + dolv = pp; + + while (n--) + *pp++ = make(*fp++); + *pp++ = ENDARGS; + return(np); +} + + +struct dolnod * +clean_args(blk) + struct dolnod *blk; +{ + register unsigned char **argp; + register struct dolnod *argr = 0; + register struct dolnod *argblk; + + if (argblk = blk) + { + argr = argblk->dolnxt; + + if (argblk == dolh) + argblk->doluse = 1; + else + { + for (argp = argblk->dolarg; *argp != (unsigned char *)ENDARGS; argp++) + free(*argp); + free(argblk->dolarg); + free(argblk); + } + } + return(argr); +} + +clearup() +{ + /* + * force `for' $* lists to go away + */ + if(globdolv) + dolv = globdolv; + if(globdolc) + dolc = globdolc; + if(globdolh) + dolh = globdolh; + globdolv = 0; + globdolc = 0; + globdolh = 0; + while (argfor = clean_args(argfor)) + ; + /* + * clean up io files + */ + while (pop()) + ; + + /* + * Clean up pipe file descriptor + * from command substitution + */ + + if(savpipe != -1) { + close(savpipe); + savpipe = -1; + } + + /* + * clean up tmp files + */ + while (poptemp()) + ; +} + +/* + * Save positiional parameters before outermost function invocation + * in case we are interrupted. + * Increment use count for current positional parameters so that they aren't thrown + * away. + */ + +struct dolnod *savargs(funcnt) +int funcnt; +{ + if (!funcnt) { + globdolh = dolh; + globdolv = dolv; + globdolc = dolc; + } + useargs(); + return(dolh); +} + +/* After function invocation, free positional parameters, + * restore old positional parameters, and restore + * use count. + */ + +void restorargs(olddolh, funcnt) +struct dolnod *olddolh; +{ + if(argfor != olddolh) + while ((argfor = clean_args(argfor)) != olddolh && argfor); + if(!argfor) + return; + freedolh(); + dolh = olddolh; + if(dolh) + dolh -> doluse++; /* increment use count so arguments aren't freed */ + argfor = freeargs(dolh); + if(funcnt == 1) { + globdolh = 0; + globdolv = 0; + globdolc = 0; + } +} + +struct dolnod * +useargs() +{ + if (dolh) + { + if (dolh->doluse++ == 1) + { + dolh->dolnxt = argfor; + argfor = dolh; + } + } + return(dolh); +} + diff --git a/usr/src/cmd/sh/blok.c b/usr/src/cmd/sh/blok.c new file mode 100644 index 0000000000..4eccca8f85 --- /dev/null +++ b/usr/src/cmd/sh/blok.c @@ -0,0 +1,349 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * UNIX shell + */ + +#include "defs.h" + + +/* + * storage allocator + * (circular first fit strategy) + */ + +#define BUSY 01 +#define busy(x) (Rcheat((x)->word) & BUSY) + +unsigned brkincr = BRKINCR; +struct blk *blokp; /* current search pointer */ +struct blk *bloktop; /* top of arena (last blok) */ + +unsigned char *brkbegin; +unsigned char *setbrk(); + +#ifdef __STDC__ +void * +#else +char * +#endif +alloc(nbytes) + size_t nbytes; +{ + register unsigned rbytes = round(nbytes+BYTESPERWORD, BYTESPERWORD); + + if (stakbot == 0) { + addblok((unsigned)0); + } + + for (;;) + { + int c = 0; + register struct blk *p = blokp; + register struct blk *q; + + do + { + if (!busy(p)) + { + while (!busy(q = p->word)) + p->word = q->word; + if ((char *)q - (char *)p >= rbytes) + { + blokp = (struct blk *) + ((char *)p + rbytes); + if (q > blokp) + blokp->word = p->word; + p->word = (struct blk *) + (Rcheat(blokp) | BUSY); + return ((char *)(p + 1)); + } + } + q = p; + p = (struct blk *)(Rcheat(p->word) & ~BUSY); + } while (p > q || (c++) == 0); + addblok(rbytes); + } +} + +addblok(reqd) + unsigned reqd; +{ + if (stakbot == 0) + { + brkbegin = setbrk(3 * BRKINCR); + bloktop = (struct blk *)brkbegin; + } + + if (stakbas != staktop) + { + register unsigned char *rndstak; + register struct blk *blokstak; + + if (staktop >= brkend) + growstak(staktop); + pushstak(0); + rndstak = (unsigned char *)round(staktop, BYTESPERWORD); + blokstak = (struct blk *)(stakbas) - 1; + blokstak->word = stakbsy; + stakbsy = blokstak; + bloktop->word = (struct blk *)(Rcheat(rndstak) | BUSY); + bloktop = (struct blk *)(rndstak); + } + reqd += brkincr; + reqd &= ~(brkincr - 1); + blokp = bloktop; + /* + * brkend points to the first invalid address. + * make sure bloktop is valid. + */ + if ((unsigned char *)&bloktop->word >= brkend) + { + if (setbrk((unsigned)((unsigned char *) + (&bloktop->word) - brkend + sizeof (struct blk))) == + (unsigned char *)-1) + error(nospace); + } + bloktop = bloktop->word = (struct blk *)(Rcheat(bloktop) + reqd); + if ((unsigned char *)&bloktop->word >= brkend) + { + if (setbrk((unsigned)((unsigned char *) + (&bloktop->word) - brkend + sizeof (struct blk))) == + (unsigned char *)-1) + error(nospace); + } + bloktop->word = (struct blk *)(brkbegin + 1); + { + register unsigned char *stakadr = (unsigned char *) + (bloktop + 2); + register unsigned char *sp = stakadr; + if (reqd = (staktop-stakbot)) + { + if (stakadr + reqd >= brkend) + growstak(stakadr + reqd); + while (reqd-- > 0) + *sp++ = *stakbot++; + sp--; + } + staktop = sp; + if (staktop >= brkend) + growstak(staktop); + stakbas = stakbot = stakadr; + } +} + +void +free(ap) + void *ap; +{ + register struct blk *p; + + if ((p = (struct blk *)ap) && p < bloktop && p > (struct blk *)brkbegin) + { +#ifdef DEBUG + chkbptr(p); +#endif + --p; + p->word = (struct blk *)(Rcheat(p->word) & ~BUSY); + } + + +} + + +#ifdef DEBUG + +chkbptr(ptr) + struct blk *ptr; +{ + int exf = 0; + register struct blk *p = (struct blk *)brkbegin; + register struct blk *q; + int us = 0, un = 0; + + for (;;) + { + q = (struct blk *)(Rcheat(p->word) & ~BUSY); + + if (p+1 == ptr) + exf++; + + if (q < (struct blk *)brkbegin || q > bloktop) + abort(3); + + if (p == bloktop) + break; + + if (busy(p)) + us += q - p; + else + un += q - p; + + if (p >= q) + abort(4); + + p = q; + } + if (exf == 0) + abort(1); +} + + +chkmem() +{ + register struct blk *p = (struct blk *)brkbegin; + register struct blk *q; + int us = 0, un = 0; + + for (;;) { + q = (struct blk *)(Rcheat(p->word) & ~BUSY); + + if (q < (struct blk *)brkbegin || q > bloktop) + abort(3); + + if (p == bloktop) + break; + + if (busy(p)) + us += q - p; + else + un += q - p; + + if (p >= q) + abort(4); + + p = q; + } + + prs("un/used/avail "); + prn(un); + blank(); + prn(us); + blank(); + prn((char *)bloktop - brkbegin - (un + us)); + newline(); + +} + +#endif + +size_t +blklen(q) +char *q; +{ + register struct blk *pp = (struct blk *)q; + register struct blk *p; + + --pp; + p = (struct blk *)(Rcheat(pp->word) & ~BUSY); + + return ((size_t)((long)p - (long)q)); +} + +/* + * This is a really hasty hack at putting realloc() in the shell, along + * with alloc() and free(). I really hate having to do things like this, + * hacking in something before I understand _why_ libcollate does any + * memory (re)allocation, let alone feel comfortable with this particular + * implementation of realloc, assuming it actually gets used by anything. + * + * I plan to revist this, for now this is just to get sh to compile so + * that xcu4 builds may be done and we get xcu4 on our desktops. + * + * Eric Brunner, 10/21/94 + * + * Implemented a variation on the suggested fix in Trusted Solaris 2.5, + * then forward ported the fix into the mainline shell. + * + * 3/3/99 + */ +#ifdef __STDC__ +void * +realloc(pp, nbytes) +void *pp; +size_t nbytes; +#else +char * +realloc(pp, nbytes) +char *pp; +size_t nbytes; +#endif +{ + char *q; + size_t blen; + + if (pp == NULL) + return (alloc(nbytes)); + if ((nbytes == 0) && (pp != NULL)) + free(pp); + + blen = blklen(pp); + + if (blen < nbytes) { /* need to grow */ + q = alloc(nbytes); + memcpy(q, pp, blen); + free(pp); + return ((char *)q); + } else if (blen == nbytes) { /* do nothing */ + return (pp); + } else { /* free excess */ + q = alloc(nbytes); + memcpy(q, pp, nbytes); + free(pp); + return ((char *)q); + } + +#ifdef undef + /* + * all of what follows is the _idea_ of what is going to be done + * getting the size of the block is a problem -- what follows + * is _not_ "real", since "sizeof" isn't going to tell me any + * thing usefull, probably have to travers the list to the next + * blk, then subtract ptr addrs ... and be careful not to leave + * holes. + */ + p = (struct blk *)pp; + if (sizeof (p) < nbytes) { /* need to grow */ + q = alloc(nbytes); + memcpy(q, pp, sizeof (p)); + free(pp); + return ((char *)q); + } else if (sizeof (p) == nbytes) { /* do nothing */ + return (pp); + } else { /* free excess */ + q = alloc(nbytes); + memcpy(q, pp, nbytes); + free(pp); + return ((char *)q); + } +#endif +} diff --git a/usr/src/cmd/sh/bltin.c b/usr/src/cmd/sh/bltin.c new file mode 100644 index 0000000000..ec84f7cf06 --- /dev/null +++ b/usr/src/cmd/sh/bltin.c @@ -0,0 +1,480 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3.8.1 */ +/* + * + * UNIX shell + * + */ + + +#include "defs.h" +#include <errno.h> +#include "sym.h" +#include "hash.h" +#include <sys/types.h> +#include <sys/times.h> + +builtin(type, argc, argv, t) +int type, argc; +unsigned char **argv; +struct trenod *t; +{ + short index = initio(t->treio, (type != SYSEXEC)); + unsigned char *a1 = argv[1]; + + switch (type) + { + + case SYSSUSP: + syssusp(argc,argv); + break; + + case SYSSTOP: + sysstop(argc,argv); + break; + + case SYSKILL: + syskill(argc,argv); + break; + + case SYSFGBG: + sysfgbg(argc,argv); + break; + + case SYSJOBS: + sysjobs(argc,argv); + break; + + case SYSDOT: + if (a1) + { + register int f; + + if ((f = pathopen(getpath(a1), a1)) < 0) + failed(a1, notfound); + else + execexp(0, f); + } + break; + + case SYSTIMES: + { + struct tms tms; + + times(&tms); + prt(tms.tms_cutime); + prc_buff(SPACE); + prt(tms.tms_cstime); + prc_buff(NL); + } + break; + + case SYSEXIT: + if ( tried_to_exit++ || endjobs(JOB_STOPPED) ){ + flags |= forcexit; /* force exit */ + exitsh(a1 ? stoi(a1) : retval); + } + break; + + case SYSNULL: + t->treio = 0; + break; + + case SYSCONT: + if (loopcnt) + { + execbrk = breakcnt = 1; + if (a1) + breakcnt = stoi(a1); + if (breakcnt > loopcnt) + breakcnt = loopcnt; + else + breakcnt = -breakcnt; + } + break; + + case SYSBREAK: + if (loopcnt) + { + execbrk = breakcnt = 1; + if (a1) + breakcnt = stoi(a1); + if (breakcnt > loopcnt) + breakcnt = loopcnt; + } + break; + + case SYSTRAP: + systrap(argc,argv); + break; + + case SYSEXEC: + argv++; + ioset = 0; + if (a1 == 0) { + setmode(0); + break; + } + /* FALLTHROUGH */ + +#ifdef RES /* Research includes login as part of the shell */ + + case SYSLOGIN: + if (!endjobs(JOB_STOPPED|JOB_RUNNING)) + break; + oldsigs(); + execa(argv, -1); + done(0); +#else + + case SYSNEWGRP: + if (flags & rshflg) + failed(argv[0], restricted); + else if (!endjobs(JOB_STOPPED|JOB_RUNNING)) + break; + else + { + flags |= forcexit; /* bad exec will terminate shell */ + oldsigs(); + rmtemp(0); + rmfunctmp(); +#ifdef ACCT + doacct(); +#endif + execa(argv, -1); + done(0); + } + +#endif + + case SYSCD: + if (flags & rshflg) + failed(argv[0], restricted); + else if ((a1 && *a1) || (a1 == 0 && (a1 = homenod.namval))) + { + unsigned char *cdpath; + unsigned char *dir; + int f; + + if ((cdpath = cdpnod.namval) == 0 || + *a1 == '/' || + cf(a1, ".") == 0 || + cf(a1, "..") == 0 || + (*a1 == '.' && (*(a1+1) == '/' || *(a1+1) == '.' && *(a1+2) == '/'))) + cdpath = (unsigned char *)nullstr; + + do + { + dir = cdpath; + cdpath = catpath(cdpath,a1); + } + while ((f = (chdir((const char *) curstak()) < 0)) && + cdpath); + + if (f) { + switch(errno) { + case EMULTIHOP: + failed(a1, emultihop); + break; + case ENOTDIR: + failed(a1, enotdir); + break; + case ENOENT: + failed(a1, enoent); + break; + case EACCES: + failed(a1, eacces); + break; + case ENOLINK: + failed(a1, enolink); + break; + default: + failed(a1, baddir); + break; + } + } + else + { + cwd(curstak()); + if (cf(nullstr, dir) && + *dir != ':' && + any('/', curstak()) && + flags & prompt) + { + prs_buff(cwdget()); + prc_buff(NL); + } + } + zapcd(); + } + else + { + if (a1) + error(nulldir); + else + error(nohome); + } + + break; + + case SYSSHFT: + { + int places; + + places = a1 ? stoi(a1) : 1; + + if ((dolc -= places) < 0) + { + dolc = 0; + error(badshift); + } + else + dolv += places; + } + + break; + + case SYSWAIT: + syswait(argc,argv); + break; + + case SYSREAD: + if(argc < 2) + failed(argv[0],mssgargn); + rwait = 1; + exitval = readvar(&argv[1]); + rwait = 0; + break; + + case SYSSET: + if (a1) + { + int cnt; + + cnt = options(argc, argv); + if (cnt > 1) + setargs(argv + argc - cnt); + } + else if (comptr(t)->comset == 0) + { + /* + * scan name chain and print + */ + namscan(printnam); + } + break; + + case SYSRDONLY: + exitval = 0; + if (a1) + { + while (*++argv) + attrib(lookup(*argv), N_RDONLY); + } + else + namscan(printro); + + break; + + case SYSXPORT: + { + struct namnod *n; + + exitval = 0; + if (a1) + { + while (*++argv) + { + n = lookup(*argv); + if (n->namflg & N_FUNCTN) + error(badexport); + else + attrib(n, N_EXPORT); + } + } + else + namscan(printexp); + } + break; + + case SYSEVAL: + if (a1) + execexp(a1, &argv[2]); + break; + +#ifndef RES + case SYSULIMIT: + sysulimit(argc, argv); + break; + + case SYSUMASK: + if (a1) + { + int c; + mode_t i; + + i = 0; + while ((c = *a1++) >= '0' && c <= '7') + i = (i << 3) + c - '0'; + umask(i); + } + else + { + mode_t i; + int j; + + umask(i = umask(0)); + prc_buff('0'); + for (j = 6; j >= 0; j -= 3) + prc_buff(((i >> j) & 07) +'0'); + prc_buff(NL); + } + break; + +#endif + + case SYSTST: + exitval = test(argc, argv); + break; + + case SYSECHO: + exitval = echo(argc, argv); + break; + + case SYSHASH: + exitval = 0; + + if (a1) + { + if (a1[0] == '-') + { + if (a1[1] == 'r') + zaphash(); + else + error(badopt); + } + else + { + while (*++argv) + { + if (hashtype(hash_cmd(*argv)) == NOTFOUND) + failed(*argv, notfound); + } + } + } + else + hashpr(); + + break; + + case SYSPWD: + { + exitval = 0; + cwdprint(); + } + break; + + case SYSRETURN: + if (funcnt == 0) + error(badreturn); + + execbrk = 1; + exitval = (a1 ? stoi(a1) : retval); + break; + + case SYSTYPE: + exitval = 0; + if (a1) + { + /* return success only if all names are found */ + while (*++argv) + exitval |= what_is_path(*argv); + } + break; + + case SYSUNS: + exitval = 0; + if (a1) + { + while (*++argv) + unset_name(*argv); + } + break; + + case SYSGETOPT: { + int getoptval; + struct namnod *n; + extern unsigned char numbuf[]; + unsigned char *varnam = argv[2]; + unsigned char c[2]; + if(argc < 3) { + failure(argv[0],mssgargn); + break; + } + exitval = 0; + n = lookup("OPTIND"); + optind = stoi(n->namval); + if(argc > 3) { + argv[2] = dolv[0]; + getoptval = getopt(argc-2, (char **)&argv[2], (char *)argv[1]); + } + else + getoptval = getopt(dolc+1, (char **)dolv, (char *)argv[1]); + if(getoptval == -1) { + itos(optind); + assign(n, numbuf); + n = lookup(varnam); + assign(n, nullstr); + exitval = 1; + break; + } + argv[2] = varnam; + itos(optind); + assign(n, numbuf); + c[0] = getoptval; + c[1] = 0; + n = lookup(varnam); + assign(n, c); + n = lookup("OPTARG"); + assign(n, optarg); + } + break; + + default: + prs_buff("unknown builtin\n"); + } + + + flushb(); + restore(index); + chktrap(); +} diff --git a/usr/src/cmd/sh/brkincr.h b/usr/src/cmd/sh/brkincr.h new file mode 100644 index 0000000000..a77e4ce012 --- /dev/null +++ b/usr/src/cmd/sh/brkincr.h @@ -0,0 +1,29 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */ +/* 3.0 SID # 1.1 */ +#define BRKINCR 01000 +#define BRKMAX 04000 diff --git a/usr/src/cmd/sh/cmd.c b/usr/src/cmd/sh/cmd.c new file mode 100644 index 0000000000..0e74a4d884 --- /dev/null +++ b/usr/src/cmd/sh/cmd.c @@ -0,0 +1,619 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.12.1.4 */ +/* + * UNIX shell + */ + +#include "defs.h" +#include "sym.h" + +static struct ionod * inout(); +static int chkword(); +static int chksym(); +static struct trenod * term(); +static struct trenod * makelist(); +static struct trenod * list(); +static struct regnod * syncase(); +static struct trenod * item(); +static int skipnl(); +static int prsym(); +static int synbad(); + + +/* ======== storage allocation for functions ======== */ + +unsigned char * +getstor(asize) + int asize; +{ + if (fndef) + return((unsigned char *)alloc(asize)); + else + return(getstak(asize)); +} + + +/* ======== command line decoding ========*/ + + + + +struct trenod * +makefork(flgs, i) + int flgs; + struct trenod *i; +{ + register struct forknod *t; + + t = (struct forknod *)getstor(sizeof(struct forknod)); + t->forktyp = flgs|TFORK; + t->forktre = i; + t->forkio = 0; + return((struct trenod *)t); +} + +static struct trenod * +makelist(type, i, r) + int type; + struct trenod *i, *r; +{ + register struct lstnod *t; + + if (i == 0 || r == 0) + synbad(); + else + { + t = (struct lstnod *)getstor(sizeof(struct lstnod)); + t->lsttyp = type; + t->lstlef = i; + t->lstrit = r; + } + return((struct trenod *)t); +} + +/* + * cmd + * empty + * list + * list & [ cmd ] + * list [ ; cmd ] + */ +struct trenod * +cmd(sym, flg) + register int sym; + int flg; +{ + register struct trenod *i, *e; + i = list(flg); + if (wdval == NL) + { + if (flg & NLFLG) + { + wdval = ';'; + chkpr(); + } + } + else if (i == 0 && (flg & MTFLG) == 0) + synbad(); + + switch (wdval) + { + case '&': + if (i) + i = makefork(FAMP, i); + else + synbad(); + + case ';': + if (e = cmd(sym, flg | MTFLG)) + i = makelist(TLST, i, e); + else if (i == 0) + synbad(); + break; + + case EOFSYM: + if (sym == NL) + break; + + default: + if (sym) + chksym(sym); + } + return(i); +} + +/* + * list + * term + * list && term + * list || term + */ +static struct trenod * +list(flg) +{ + register struct trenod *r; + register int b; + r = term(flg); + while (r && ((b = (wdval == ANDFSYM)) || wdval == ORFSYM)) + r = makelist((b ? TAND : TORF), r, term(NLFLG)); + return(r); +} + +/* + * term + * item + * item |^ term + */ +static struct trenod * +term(flg) +{ + register struct trenod *t; + + reserv++; + if (flg & NLFLG) + skipnl(); + else + word(); + if ((t = item(TRUE)) && (wdval == '^' || wdval == '|')) + { + struct trenod *left; + struct trenod *right; + + left = makefork(FPOU, t); + right = makefork(FPIN, term(NLFLG)); + return(makefork(0, makelist(TFIL, left, right))); + } + else + return(t); +} + + +static struct regnod * +syncase(esym) +register int esym; +{ + skipnl(); + if (wdval == esym) + return(0); + else + { + register struct regnod *r = (struct regnod *)getstor(sizeof(struct regnod)); + register struct argnod *argp; + + r->regptr = 0; + for (;;) + { + if (fndef) + { + argp= wdarg; + wdarg = (struct argnod *)alloc(length(argp->argval) + BYTESPERWORD); + movstr(argp->argval, wdarg->argval); + } + + wdarg->argnxt = r->regptr; + r->regptr = wdarg; + + /* 'in' is not a reserved word in this case */ + if (wdval == INSYM){ + wdval = 0; + } + if (wdval || (word() != ')' && wdval != '|')) + synbad(); + if (wdval == '|') + word(); + else + break; + } + r->regcom = cmd(0, NLFLG | MTFLG); + if (wdval == ECSYM) + r->regnxt = syncase(esym); + else + { + chksym(esym); + r->regnxt = 0; + } + return(r); + } +} + +/* + * item + * + * ( cmd ) [ < in ] [ > out ] + * word word* [ < in ] [ > out ] + * if ... then ... else ... fi + * for ... while ... do ... done + * case ... in ... esac + * begin ... end + */ +static struct trenod * +item(flag) + BOOL flag; +{ + register struct trenod *r; + register struct ionod *io; + + if (flag) + io = inout((struct ionod *)0); + else + io = 0; + switch (wdval) + { + case CASYM: + { + register struct swnod *t; + + t = (struct swnod *)getstor(sizeof(struct swnod)); + r = (struct trenod *)t; + + chkword(); + if (fndef) + t->swarg = make(wdarg->argval); + else + t->swarg = wdarg->argval; + skipnl(); + chksym(INSYM | BRSYM); + t->swlst = syncase(wdval == INSYM ? ESSYM : KTSYM); + t->swtyp = TSW; + break; + } + + case IFSYM: + { + register int w; + register struct ifnod *t; + + t = (struct ifnod *)getstor(sizeof(struct ifnod)); + r = (struct trenod *)t; + + t->iftyp = TIF; + t->iftre = cmd(THSYM, NLFLG); + t->thtre = cmd(ELSYM | FISYM | EFSYM, NLFLG); + t->eltre = ((w = wdval) == ELSYM ? cmd(FISYM, NLFLG) : (w == EFSYM ? (wdval = IFSYM, item(0)) : 0)); + if (w == EFSYM) + return(r); + break; + } + + case FORSYM: + { + register struct fornod *t; + + t = (struct fornod *)getstor(sizeof(struct fornod)); + r = (struct trenod *)t; + + t->fortyp = TFOR; + t->forlst = 0; + chkword(); + if (fndef) + t->fornam = make(wdarg->argval); + else + t->fornam = wdarg->argval; + if (skipnl() == INSYM) + { + chkword(); + + nohash++; + t->forlst = (struct comnod *)item(0); + nohash--; + + if (wdval != NL && wdval != ';') + synbad(); + if (wdval == NL) + chkpr(); + skipnl(); + } + chksym(DOSYM | BRSYM); + t->fortre = cmd(wdval == DOSYM ? ODSYM : KTSYM, NLFLG); + break; + } + + case WHSYM: + case UNSYM: + { + register struct whnod *t; + + t = (struct whnod *)getstor(sizeof(struct whnod)); + r = (struct trenod *)t; + + t->whtyp = (wdval == WHSYM ? TWH : TUN); + t->whtre = cmd(DOSYM, NLFLG); + t->dotre = cmd(ODSYM, NLFLG); + break; + } + + case BRSYM: + r = cmd(KTSYM, NLFLG); + break; + + case '(': + { + register struct parnod *p; + + p = (struct parnod *)getstor(sizeof(struct parnod)); + p->partre = cmd(')', NLFLG); + p->partyp = TPAR; + r = makefork(0, p); + break; + } + + default: + if (io == 0) + return(0); + + case 0: + { + register struct comnod *t; + register struct argnod *argp; + register struct argnod **argtail; + register struct argnod **argset = 0; + int keywd = 1; + unsigned char *com; + + if ((wdval != NL) && ((peekn = skipwc()) == '(')) + { + struct fndnod *f; + struct ionod *saveio; + + saveio = iotemp; + peekn = 0; + if (skipwc() != ')') + synbad(); + + f = (struct fndnod *)getstor(sizeof(struct fndnod)); + r = (struct trenod *)f; + + f->fndtyp = TFND; + if (fndef) + f->fndnam = make(wdarg->argval); + else + f->fndnam = wdarg->argval; + reserv++; + fndef++; + skipnl(); + f->fndval = (struct trenod *)item(0); + fndef--; + + if (iotemp != saveio) + { + struct ionod *ioptr = iotemp; + + while (ioptr->iolst != saveio) + ioptr = ioptr->iolst; + + ioptr->iolst = fiotemp; + fiotemp = iotemp; + iotemp = saveio; + } + return(r); + } + else + { + t = (struct comnod *)getstor(sizeof(struct comnod)); + r = (struct trenod *)t; + + t->comio = io; /*initial io chain*/ + argtail = &(t->comarg); + + while (wdval == 0) + { + if (fndef) + { + argp = wdarg; + wdarg = (struct argnod *)alloc(length(argp->argval) + BYTESPERWORD); + movstr(argp->argval, wdarg->argval); + } + + argp = wdarg; + if (wdset && keywd) + { + argp->argnxt = (struct argnod *)argset; + argset = (struct argnod **)argp; + } + else + { + *argtail = argp; + argtail = &(argp->argnxt); + keywd = flags & keyflg; + } + word(); + if (flag) + { + if (io) + { + while(io->ionxt) + io = io->ionxt; + io->ionxt = inout((struct ionod *)0); + } + else + t->comio = io = inout((struct ionod *)0); + } + } + + t->comtyp = TCOM; + t->comset = (struct argnod *)argset; + *argtail = 0; + + if (nohash == 0 && (fndef == 0 || (flags & hashflg))) + { + if (t->comarg) + { + com = t->comarg->argval; + if (*com && *com != DOLLAR) + pathlook(com, 0, t->comset); + } + } + + return(r); + } + } + + } + reserv++; + word(); + if (io = inout(io)) + { + r = makefork(0,r); + r->treio = io; + } + return(r); +} + + +static int +skipnl() +{ + while ((reserv++, word() == NL)) + chkpr(); + return(wdval); +} + +static struct ionod * +inout(lastio) + struct ionod *lastio; +{ + register int iof; + register struct ionod *iop; + register unsigned int c; + + iof = wdnum; + switch (wdval) + { + case DOCSYM: /* << */ + iof |= IODOC; + break; + + case APPSYM: /* >> */ + case '>': + if (wdnum == 0) + iof |= 1; + iof |= IOPUT; + if (wdval == APPSYM) + { + iof |= IOAPP; + break; + } + + case '<': + if ((c = nextwc()) == '&') + iof |= IOMOV; + else if (c == '>') + iof |= IORDW; + else + peekn = c | MARK; + break; + + default: + return(lastio); + } + + chkword(); + iop = (struct ionod *)getstor(sizeof(struct ionod)); + + if (fndef) + iop->ioname = (char *) make(wdarg->argval); + else + iop->ioname = (char *) (wdarg->argval); + + iop->iolink = 0; + iop->iofile = iof; + if (iof & IODOC) + { + iop->iolst = iopend; + iopend = iop; + } + word(); + iop->ionxt = inout(lastio); + return(iop); +} + +static int +chkword() +{ + if (word()) + synbad(); +} + +static int +chksym(sym) +{ + register int x = sym & wdval; + + if (((x & SYMFLG) ? x : sym) != wdval) + synbad(); +} + +static int +prsym(sym) +{ + if (sym & SYMFLG) + { + register const struct sysnod *sp = reserved; + + while (sp->sysval && sp->sysval != sym) + sp++; + prs(sp->sysnam); + } + else if (sym == EOFSYM) + prs(endoffile); + else + { + if (sym & SYMREP) + prc(sym); + if (sym == NL) + prs("newline or ;"); + else + prc(sym); + } +} + +static int +synbad() +{ + prp(); + prs(synmsg); + if ((flags & ttyflg) == 0) + { + prs(atline); + prn(standin->flin); + } + prs(colon); + prc(LQ); + if (wdval) + prsym(wdval); + else + prs_cntl(wdarg->argval); + prc(RQ); + prs(unexpected); + newline(); + exitsh(SYNBAD); +} diff --git a/usr/src/cmd/sh/ctype.c b/usr/src/cmd/sh/ctype.c new file mode 100644 index 0000000000..92bc3fc5d1 --- /dev/null +++ b/usr/src/cmd/sh/ctype.c @@ -0,0 +1,135 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9.1.1 */ +/* + * UNIX shell + */ + +#include "defs.h" + +#ifdef __STDC__ +const +#endif +unsigned char _ctype1[] = +{ +/* 000 001 002 003 004 005 006 007 */ + _EOF, 0, 0, 0, 0, 0, 0, 0, + +/* bs ht nl vt np cr so si */ + 0, _TAB, _EOR, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + +/* sp ! " # $ % & ' */ + _SPC, 0, _DQU, 0, _DOL1, 0, _AMP, 0, + +/* ( ) * + , - . / */ + _BRA, _KET, 0, 0, 0, 0, 0, 0, + +/* 0 1 2 3 4 5 6 7 */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* 8 9 : ; < = > ? */ + 0, 0, 0, _SEM, _LT, 0, _GT, 0, + +/* @ A B C D E F G */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* H I J K L M N O */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* P Q R S T U V W */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* X Y Z [ \ ] ^ _ */ + 0, 0, 0, 0, _BSL, 0, _HAT, 0, + +/* ` a b c d e f g */ + _LQU, 0, 0, 0, 0, 0, 0, 0, + +/* h i j k l m n o */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* p q r s t u v w */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* x y z { | } ~ del */ + 0, 0, 0, 0, _BAR, 0, 0, 0 +}; + +#ifdef __STDC__ +const +#endif +unsigned char _ctype2[] = +{ +/* 000 001 002 003 004 005 006 007 */ + 0, 0, 0, 0, 0, 0, 0, 0, + +/* bs ht nl vt np cr so si */ + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + +/* sp ! " # $ % & ' */ + 0, _PCS, 0, _NUM, _DOL2, 0, 0, 0, + +/* ( ) * + , - . / */ + 0, 0, _AST, _PLS, 0, _MIN, 0, 0, + +/* 0 1 2 3 4 5 6 7 */ + _DIG, _DIG, _DIG, _DIG, _DIG, _DIG, _DIG, _DIG, + +/* 8 9 : ; < = > ? */ + _DIG, _DIG, 0, 0, 0, _EQ, 0, _QU, + +/* @ A B C D E F G */ + _AT, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + +/* H I J K L M N O */ + _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + +/* P Q R S T U V W */ + _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, _UPC, + +/* X Y Z [ \ ] ^ _ */ + _UPC, _UPC, _UPC, 0, 0, 0, 0, _UPC, + +/* ` a b c d e f g */ + 0, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, + +/* h i j k l m n o */ + _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, + +/* p q r s t u v w */ + _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, _LPC, + +/* x y z { | } ~ del */ + _LPC, _LPC, _LPC, _CBR, 0, _CKT, 0, 0 +}; diff --git a/usr/src/cmd/sh/ctype.h b/usr/src/cmd/sh/ctype.h new file mode 100644 index 0000000000..f34922a203 --- /dev/null +++ b/usr/src/cmd/sh/ctype.h @@ -0,0 +1,116 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10.1.1 */ +/* + * UNIX shell + */ + + +/* table 1 */ +#define T_SUB 01 +#define T_MET 02 +#define T_SPC 04 +#define T_DIP 010 +#define T_EOF 020 +#define T_EOR 040 +#define T_QOT 0100 +#define T_ESC 0200 + +/* table 2 */ +#define T_BRC 01 +#define T_DEF 02 +#define T_AST 04 +#define T_DIG 010 +#define T_SHN 040 +#define T_IDC 0100 +#define T_SET 0200 + +/* for single chars */ +#define _TAB (T_SPC) +#define _SPC (T_SPC) +#define _UPC (T_IDC) +#define _LPC (T_IDC) +#define _DIG (T_DIG) +#define _EOF (T_EOF) +#define _EOR (T_EOR) +#define _BAR (T_DIP) +#define _HAT (T_MET) +#define _BRA (T_MET) +#define _KET (T_MET) +#define _AMP (T_DIP) +#define _SEM (T_DIP) +#define _LT (T_DIP) +#define _GT (T_DIP) +#define _LQU (T_QOT|T_ESC) +#define _BSL (T_ESC) +#define _DQU (T_QOT|T_ESC) +#define _DOL1 (T_SUB|T_ESC) + +#define _CBR T_BRC +#define _CKT T_DEF +#define _AST (T_AST) +#define _EQ (T_DEF) +#define _MIN (T_DEF|T_SHN) +#define _PCS (T_SHN) +#define _NUM (T_SHN) +#define _DOL2 (T_SHN) +#define _PLS (T_DEF|T_SET) +#define _AT (T_AST) +#define _QU (T_DEF|T_SHN) + +/* abbreviations for tests */ +#define _IDCH (T_IDC|T_DIG) +#define _META (T_SPC|T_DIP|T_MET|T_EOR) + +extern +#ifdef __STDC__ +const +#endif +unsigned char _ctype1[]; + +/* nb these args are not call by value !!!! */ +#define space(c) ((c<QUOTE) && _ctype1[c]&(T_SPC)) +#define eofmeta(c) ((c<QUOTE) && _ctype1[c]&(_META|T_EOF)) +#define qotchar(c) ((c<QUOTE) && _ctype1[c]&(T_QOT)) +#define eolchar(c) ((c<QUOTE) && _ctype1[c]&(T_EOR|T_EOF)) +#define dipchar(c) ((c<QUOTE) && _ctype1[c]&(T_DIP)) +#define subchar(c) ((c<QUOTE) && _ctype1[c]&(T_SUB|T_QOT)) +#define escchar(c) ((c<QUOTE) && _ctype1[c]&(T_ESC)) + +extern +#ifdef __STDC__ +const +#endif +unsigned char _ctype2[]; + +#define digit(c) ((c<QUOTE) && _ctype2[c]&(T_DIG)) +#define dolchar(c) ((c<QUOTE) && _ctype2[c]&(T_AST|T_BRC|T_DIG|T_IDC|T_SHN)) +#define defchar(c) ((c<QUOTE) && _ctype2[c]&(T_DEF)) +#define setchar(c) ((c<QUOTE) && _ctype2[c]&(T_SET)) +#define digchar(c) ((c<QUOTE) && _ctype2[c]&(T_AST|T_DIG)) +#define letter(c) ((c<QUOTE) && _ctype2[c]&(T_IDC)) +#define alphanum(c) ((c<QUOTE) && _ctype2[c]&(_IDCH)) +#define astchar(c) ((c<QUOTE) && _ctype2[c]&(T_AST)) diff --git a/usr/src/cmd/sh/defs.c b/usr/src/cmd/sh/defs.c new file mode 100644 index 0000000000..4070f5125c --- /dev/null +++ b/usr/src/cmd/sh/defs.c @@ -0,0 +1,114 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * UNIX shell + */ + +#include <setjmp.h> +#include "mode.h" +#include "name.h" +#include <sys/param.h> +#ifndef NOFILE +#define NOFILE 20 +#endif +/* temp files and io */ + +int output = 2; +int ioset; +struct ionod *iotemp; /* files to be deleted sometime */ +struct ionod *fiotemp; /* function files to be deleted sometime */ +struct ionod *iopend; /* documents waiting to be read at NL */ +struct fdsave fdmap[NOFILE]; + +/* substitution */ +int dolc; +unsigned char **dolv; +struct dolnod *argfor; +struct argnod *gchain; + + +/* name tree and words */ +int wdval; +int wdnum; +int fndef; +int nohash; +struct argnod *wdarg; +int wdset; +BOOL reserv; + +/* special names */ +unsigned char *pcsadr; +unsigned char *pidadr; +unsigned char *cmdadr; + +/* transput */ +unsigned char *tmpname; +int serial; +unsigned peekc; +unsigned peekn; +unsigned char *comdiv; +long flags; +int rwait; /* flags read waiting */ + +/* error exits from various parts of shell */ +jmp_buf subshell; +jmp_buf errshell; + +/* fault handling */ +BOOL trapnote; + +/* execflgs */ +int exitval; +int retval; +BOOL execbrk; +int loopcnt; +int breakcnt; +int funcnt; +int eflag; +/* + * The following flag is set if you try to exit with stopped jobs. + * On the second try the exit will succeed. + */ +int tried_to_exit; +/* + * The following flag is set to true if /usr/ucb is found in the path + * before /usr/bin. This value is checked when executing the echo and test + * built-in commands. If true, the command behaves as in BSD systems. + */ +int ucb_builtins; + +/* The following stuff is from stak.h */ + +unsigned char *stakbas; +unsigned char *staktop; +unsigned char *stakbot = 0; +struct blk *stakbsy; +unsigned char *brkend; diff --git a/usr/src/cmd/sh/defs.h b/usr/src/cmd/sh/defs.h new file mode 100644 index 0000000000..e02aba660e --- /dev/null +++ b/usr/src/cmd/sh/defs.h @@ -0,0 +1,498 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +#ifndef _DEFS_H +#define _DEFS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * UNIX shell + */ + +/* execute flags */ +#define XEC_EXECED 01 +#define XEC_LINKED 02 +#define XEC_NOSTOP 04 + +/* endjobs flags */ +#define JOB_STOPPED 01 +#define JOB_RUNNING 02 + +/* error exits from various parts of shell */ +#define ERROR 1 +#define SYNBAD 2 +#define SIGFAIL 2000 +#define SIGFLG 0200 + +/* command tree */ +#define FPIN 0x0100 +#define FPOU 0x0200 +#define FAMP 0x0400 +#define COMMSK 0x00F0 +#define CNTMSK 0x000F + +#define TCOM 0x0000 +#define TPAR 0x0010 +#define TFIL 0x0020 +#define TLST 0x0030 +#define TIF 0x0040 +#define TWH 0x0050 +#define TUN 0x0060 +#define TSW 0x0070 +#define TAND 0x0080 +#define TORF 0x0090 +#define TFORK 0x00A0 +#define TFOR 0x00B0 +#define TFND 0x00C0 + +/* execute table */ +#define SYSSET 1 +#define SYSCD 2 +#define SYSEXEC 3 + +#ifdef RES /* include login code */ +#define SYSLOGIN 4 +#else +#define SYSNEWGRP 4 +#endif + +#define SYSTRAP 5 +#define SYSEXIT 6 +#define SYSSHFT 7 +#define SYSWAIT 8 +#define SYSCONT 9 +#define SYSBREAK 10 +#define SYSEVAL 11 +#define SYSDOT 12 +#define SYSRDONLY 13 +#define SYSTIMES 14 +#define SYSXPORT 15 +#define SYSNULL 16 +#define SYSREAD 17 +#define SYSTST 18 + +#ifndef RES /* exclude umask code */ +#define SYSUMASK 20 +#define SYSULIMIT 21 +#endif + +#define SYSECHO 22 +#define SYSHASH 23 +#define SYSPWD 24 +#define SYSRETURN 25 +#define SYSUNS 26 +#define SYSMEM 27 +#define SYSTYPE 28 +#define SYSGETOPT 29 +#define SYSJOBS 30 +#define SYSFGBG 31 +#define SYSKILL 32 +#define SYSSUSP 33 +#define SYSSTOP 34 + +/* used for input and output of shell */ +#define INIO 19 + +/* io nodes */ +#define USERIO 10 +#define IOUFD 15 +#define IODOC 16 +#define IOPUT 32 +#define IOAPP 64 +#define IOMOV 128 +#define IORDW 256 +#define IOSTRIP 512 +#define INPIPE 0 +#define OTPIPE 1 + +/* arg list terminator */ +#define ENDARGS 0 + +#include <unistd.h> +#include "mac.h" +#include "mode.h" +#include "name.h" +#include <signal.h> +#include <sys/types.h> + +/* id's */ +extern pid_t mypid; +extern pid_t mypgid; +extern pid_t mysid; + +/* getopt */ + +extern int optind; +extern int opterr; +extern int _sp; +extern char *optarg; + + +/* use sh-private versions of memory allocation routines */ + +#define alloc malloc + +/* result type declarations */ + +extern int handle(); +extern void chktrap(); +extern void done(); +extern void sh_free(); +extern unsigned char *make(); +extern unsigned char *movstr(); +extern unsigned char *movstrn(); +extern unsigned char *cwdget(); +extern struct trenod *cmd(); +extern struct trenod *makefork(); +extern struct namnod *lookup(); +extern struct namnod *findnam(); +extern struct dolnod *useargs(); +extern float expr(); +extern unsigned char *catpath(); +extern unsigned char *getpath(); +extern unsigned char *nextpath(); +extern unsigned char **scan(); +extern unsigned char *mactrim(); +extern unsigned char *macro(); +extern int exname(); +extern int printnam(); +extern int printro(); +extern int printexp(); +extern unsigned int readwc(); +extern unsigned int nextwc(); +extern unsigned char skipc(); +extern unsigned char **local_setenv(); +extern time_t time(); + +#define attrib(n, f) (n->namflg |= f) +#define round(a, b) (((int)(((char *)(a)+b)-1))&~((b)-1)) +#define closepipe(x) (close(x[INPIPE]), close(x[OTPIPE])) +#define eq(a, b) (cf(a, b) == 0) +#define max(a, b) ((a) > (b)?(a):(b)) +#define assert(x) + +/* temp files and io */ +extern int output; +extern int ioset; +extern struct ionod *iotemp; /* files to be deleted sometime */ +extern struct ionod *fiotemp; /* function files to be deleted sometime */ +extern struct ionod *iopend; /* documents waiting to be read at NL */ +extern struct fdsave fdmap[]; +extern int savpipe; + +/* substitution */ +extern int dolc; +extern unsigned char **dolv; +extern struct dolnod *argfor; +extern struct argnod *gchain; + +/* stak stuff */ +#include "stak.h" + +/* + * If non-ANSI C, make const go away. We bring it back + * at the end of the file to avoid side-effects. + */ +#ifndef __STDC__ +#define const +#endif + +/* string constants */ +extern const char atline[]; +extern const char readmsg[]; +extern const char colon[]; +extern const char minus[]; +extern const char nullstr[]; +extern const char sptbnl[]; +extern const char unexpected[]; +extern const char endoffile[]; +extern const char synmsg[]; + +/* name tree and words */ +extern const struct sysnod reserved[]; +extern const int no_reserved; +extern const struct sysnod commands[]; +extern const int no_commands; + +extern int wdval; +extern int wdnum; +extern int fndef; +extern int nohash; +extern struct argnod *wdarg; +extern int wdset; +extern BOOL reserv; + +/* prompting */ +extern const char stdprompt[]; +extern const char supprompt[]; +extern const char profile[]; +extern const char sysprofile[]; + +/* locale testing */ +extern const char localedir[]; +extern int localedir_exists; + +/* built in names */ +extern struct namnod fngnod; +extern struct namnod cdpnod; +extern struct namnod ifsnod; +extern struct namnod homenod; +extern struct namnod mailnod; +extern struct namnod pathnod; +extern struct namnod ps1nod; +extern struct namnod ps2nod; +extern struct namnod mchknod; +extern struct namnod acctnod; +extern struct namnod mailpnod; + +/* special names */ +extern unsigned char flagadr[]; +extern unsigned char *pcsadr; +extern unsigned char *pidadr; +extern unsigned char *cmdadr; + +/* names always present */ +extern const char defpath[]; +extern const char mailname[]; +extern const char homename[]; +extern const char pathname[]; +extern const char cdpname[]; +extern const char ifsname[]; +extern const char ps1name[]; +extern const char ps2name[]; +extern const char mchkname[]; +extern const char acctname[]; +extern const char mailpname[]; + +/* transput */ +extern unsigned char tmpout[]; +extern unsigned char *tmpname; +extern int serial; + +#define TMPNAM 7 + +extern struct fileblk *standin; + +#define input (standin->fdes) +#define eof (standin->feof) + +extern int peekc; +extern int peekn; +extern unsigned char *comdiv; +extern +#ifdef __STDC__ +const +#endif +char devnull[]; + +/* flags */ +#define noexec 01 +#define sysflg 01 +#define intflg 02 +#define prompt 04 +#define setflg 010 +#define errflg 020 +#define ttyflg 040 +#define forked 0100 +#define oneflg 0200 +#define rshflg 0400 +#define subsh 01000 +#define stdflg 02000 +#define STDFLG 's' +#define execpr 04000 +#define readpr 010000 +#define keyflg 020000 +#define hashflg 040000 +#define nofngflg 0200000 +#define exportflg 0400000 +#define monitorflg 01000000 +#define jcflg 02000000 +#define privflg 04000000 +#define forcexit 010000000 +#define jcoff 020000000 +#define pfshflg 040000000 + +extern long flags; +extern int rwait; /* flags read waiting */ + +/* error exits from various parts of shell */ +#include <setjmp.h> +extern jmp_buf subshell; +extern jmp_buf errshell; + +/* fault handling */ +#include "brkincr.h" + +extern unsigned brkincr; +#define MINTRAP 0 +#define MAXTRAP NSIG + +#define TRAPSET 2 +#define SIGSET 4 +#define SIGMOD 8 +#define SIGIGN 16 + +extern BOOL trapnote; + +/* name tree and words */ +extern unsigned char **environ; +extern unsigned char numbuf[]; +extern const char export[]; +extern const char duperr[]; +extern const char readonly[]; + +/* execflgs */ +extern int exitval; +extern int retval; +extern BOOL execbrk; +extern int loopcnt; +extern int breakcnt; +extern int funcnt; +extern int tried_to_exit; + +/* messages */ +extern const char mailmsg[]; +extern const char coredump[]; +extern const char badopt[]; +extern const char badparam[]; +extern const char unset[]; +extern const char badsub[]; +extern const char nospace[]; +extern const char nostack[]; +extern const char notfound[]; +extern const char badtrap[]; +extern const char baddir[]; +extern const char badshift[]; +extern const char restricted[]; +extern const char execpmsg[]; +extern const char notid[]; +extern const char badulimit[]; +extern const char badresource[]; +extern const char badscale[]; +extern const char ulimit[]; +extern const char wtfailed[]; +extern const char badcreate[]; +extern const char nofork[]; +extern const char noswap[]; +extern const char piperr[]; +extern const char badopen[]; +extern const char badnum[]; +extern const char badsig[]; +extern const char badid[]; +extern const char arglist[]; +extern const char txtbsy[]; +extern const char toobig[]; +extern const char badexec[]; +extern const char badfile[]; +extern const char badreturn[]; +extern const char badexport[]; +extern const char badunset[]; +extern const char nohome[]; +extern const char badperm[]; +extern const char mssgargn[]; +extern const char libacc[]; +extern const char libbad[]; +extern const char libscn[]; +extern const char libmax[]; +extern const char emultihop[]; +extern const char nulldir[]; +extern const char enotdir[]; +extern const char enoent[]; +extern const char eacces[]; +extern const char enolink[]; +extern const char exited[]; +extern const char running[]; +extern const char ambiguous[]; +extern const char nosuchjob[]; +extern const char nosuchpid[]; +extern const char nosuchpgid[]; +extern const char usage[]; +extern const char nojc[]; +extern const char killuse[]; +extern const char jobsuse[]; +extern const char stopuse[]; +extern const char ulimuse[]; +extern const char nocurjob[]; +extern const char loginsh[]; +extern const char jobsstopped[]; +extern const char jobsrunning[]; + +/* 'builtin' error messages */ + +extern const char btest[]; +extern const char badop[]; + +#ifndef __STDC__ +#undef const /* bring back const */ +#endif + +/* fork constant */ + +#define FORKLIM 32 + +extern address end[]; + +#include "ctype.h" +#include <ctype.h> +#include <locale.h> + +extern int eflag; +extern int ucb_builtins; + +/* + * Find out if it is time to go away. + * `trapnote' is set to SIGSET when fault is seen and + * no trap has been set. + */ + +#define sigchk() if (trapnote & SIGSET) \ + exitsh(exitval ? exitval : SIGFAIL) + +#define exitset() retval = exitval + +/* Multibyte characters */ +void setwidth(); +unsigned char *readw(); +#include <stdlib.h> +#include <limits.h> +#define MULTI_BYTE_MAX MB_LEN_MAX + + +#ifdef __cplusplus +} +#endif + +#endif /* _DEFS_H */ diff --git a/usr/src/cmd/sh/dup.h b/usr/src/cmd/sh/dup.h new file mode 100644 index 0000000000..e49efc6591 --- /dev/null +++ b/usr/src/cmd/sh/dup.h @@ -0,0 +1,32 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */ +# +/* + * UNIX shell + */ + +#define DUPFLG 0100 diff --git a/usr/src/cmd/sh/echo.c b/usr/src/cmd/sh/echo.c new file mode 100644 index 0000000000..84d1836a82 --- /dev/null +++ b/usr/src/cmd/sh/echo.c @@ -0,0 +1,174 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* Portions Copyright (c) 1988, Sun Microsystems, Inc. */ +/* All Rights Reserved. */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * UNIX shell + */ +#include "defs.h" + +#define exit(a) flushb(); return (a) + +extern int exitval; + +echo(argc, argv) +unsigned char **argv; +{ + register unsigned char *cp; + register int i, wd; + int nflg = 0; + int j; + int len; + wchar_t wc; + +#ifdef _iBCS2 /* SCO compatibility support */ + struct namnod *sysv3; + int do_sysv3 = 0; + + sysv3 = findnam("SYSV3"); + if (sysv3 && (sysv3->namflg & (N_EXPORT | N_ENVNAM))) + do_sysv3 = 1; + + /* Do the -n parsing if sysv3 is set or if ucb_builtsin is set */ + if (ucb_builtins && !do_sysv3) { +#else + if (ucb_builtins) { +#endif /* _iBCS2 */ + + nflg = 0; + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'n') { + nflg++; + argc--; + argv++; + } + + for (i = 1; i < argc; i++) { + sigchk(); + + for (cp = argv[i]; *cp; cp++) { + prc_buff(*cp); + } + + if (i < argc-1) + prc_buff(' '); + } + + if (nflg == 0) + prc_buff('\n'); + exit(0); + } else { + if (--argc == 0) { + prc_buff('\n'); + exit(0); + } +#ifdef _iBCS2 + if (do_sysv3) { + if (argc > 1 && argv[1][0] == '-' && + argv[1][1] == 'n') { + nflg++; + /* Step past the -n */ + argc--; + argv++; + } + } +#endif /* _iBCS2 */ + + for (i = 1; i <= argc; i++) + { + sigchk(); + for (cp = argv[i]; *cp; cp++) { + if ((len = mbtowc(&wc, (char *)cp, + MB_LEN_MAX)) <= 0) { + prc_buff(*cp); + continue; + } + + if (wc == '\\') { + switch (*++cp) { + case 'b': + prc_buff('\b'); + continue; + case 'c': + exit(0); + + case 'f': + prc_buff('\f'); + continue; + + case 'n': + prc_buff('\n'); + continue; + + case 'r': + prc_buff('\r'); + continue; + + case 't': + prc_buff('\t'); + continue; + + case 'v': + prc_buff('\v'); + continue; + + case '\\': + prc_buff('\\'); + continue; + case '0': + j = wd = 0; + while ((*++cp >= '0' && + *cp <= '7') && j++ < 3) { + wd <<= 3; + wd |= (*cp - '0'); + } + prc_buff(wd); + --cp; + continue; + + default: + cp--; + } + prc_buff(*cp); + continue; + } else { + for (; len > 0; len--) + prc_buff(*cp++); + cp--; + continue; + } + } +#ifdef _iBCS2 + /* Don't do if don't want newlines & out of args */ + if (!(nflg && i == argc)) +#endif /* _iBCS2 */ + prc_buff(i == argc? '\n': ' '); + } + exit(0); + } +} diff --git a/usr/src/cmd/sh/error.c b/usr/src/cmd/sh/error.c new file mode 100644 index 0000000000..e47544b7ea --- /dev/null +++ b/usr/src/cmd/sh/error.c @@ -0,0 +1,121 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9.5.1 */ +/* + * UNIX shell + */ + +#include "defs.h" + + +/* ======== error handling ======== */ + +extern void done(); + +failed(s1, s2) +unsigned char *s1, *s2; +{ + prp(); + prs_cntl(s1); + if (s2) + { + prs(colon); + prs(s2); + } + newline(); + exitsh(ERROR); +} + +error(s) +unsigned char *s; +{ + failed(s, NIL); +} + +exitsh(xno) +int xno; +{ + /* + * Arrive here from `FATAL' errors + * a) exit command, + * b) default trap, + * c) fault with no trap set. + * + * Action is to return to command level or exit. + */ + exitval = xno; + flags |= eflag; + if ((flags & (forcexit | forked | errflg | ttyflg)) != ttyflg) + done(0); + else + { + clearup(); + restore(0); + (void)setb(1); + execbrk = breakcnt = funcnt = 0; + longjmp(errshell, 1); + } +} + +rmtemp(base) +struct ionod *base; +{ + while (iotemp > base) + { + unlink(iotemp->ioname); + free(iotemp->iolink); + iotemp = iotemp->iolst; + } +} + +rmfunctmp() +{ + while (fiotemp) + { + unlink(fiotemp->ioname); + fiotemp = fiotemp->iolst; + } +} + +failure(s1, s2) +unsigned char *s1, *s2; +{ + prp(); + prs_cntl(s1); + if (s2) + { + prs(colon); + prs(s2); + } + newline(); + + if (flags & errflg) + exitsh(ERROR); + + flags |= eflag; + exitval = ERROR; + exitset(); +} diff --git a/usr/src/cmd/sh/expand.c b/usr/src/cmd/sh/expand.c new file mode 100644 index 0000000000..f5bfea5bd1 --- /dev/null +++ b/usr/src/cmd/sh/expand.c @@ -0,0 +1,292 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1995 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * UNIX shell + * + */ + +#include "defs.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> + + + +/* + * globals (file name generation) + * + * "*" in params matches r.e ".*" + * "?" in params matches r.e. "." + * "[...]" in params matches character class + * "[...a-z...]" in params matches a through z. + * + */ +static int addg(); + +expand(as, rcnt) + unsigned char *as; +{ + int count; + DIR *dirf; + BOOL dir = 0; + unsigned char *rescan = 0; + unsigned char *slashsav = 0; + register unsigned char *s, *cs; + unsigned char *s2 = 0; + struct argnod *schain = gchain; + BOOL slash; + int len; + wchar_t wc; + + if (trapnote & SIGSET) + return (0); + s = cs = as; + /* + * check for meta chars + */ + { + register BOOL open; + + slash = 0; + open = 0; + do + { + if ((len = mbtowc(&wc, (char *)cs, MB_LEN_MAX)) <= 0) { + len = 1; + wc = (unsigned char)*cs; + } + + cs += len; + switch (wc) { + case 0: + if (rcnt && slash) + break; + else + return (0); + + case '/': + slash++; + open = 0; + continue; + + case '[': + open++; + continue; + + case ']': + if (open == 0) + continue; + + case '?': + case '*': + if (rcnt > slash) + continue; + else + cs--; + break; + + case '\\': + cs++; + default: + continue; + } + break; + } while (TRUE); + } + + for (;;) + { + if (cs == s) + { + s = (unsigned char *)nullstr; + break; + } else if (*--cs == '/') + { + *cs = 0; + if (s == cs) + s = (unsigned char *)"/"; + else { + /* + * push trimmed copy of directory prefix + * onto stack + */ + s2 = cpystak(s); + trim(s2); + s = s2; + } + break; + } + } + + if ((dirf = opendir(*s ? (char *)s : (char *)".")) != 0) + dir++; + + /* Let s point to original string because it will be trimmed later */ + if (s2) + s = as; + count = 0; + if (*cs == 0) + slashsav = cs++; /* remember where first slash in as is */ + + /* check for rescan */ + if (dir) + { + register unsigned char *rs; + struct dirent *e; + + rs = cs; + do /* find next / in as */ + { + if (*rs == '/') + { + rescan = rs; + *rs = 0; + gchain = 0; + } + } while (*rs++); + + while ((e = readdir(dirf)) && (trapnote & SIGSET) == 0) + { + if (e->d_name[0] == '.' && *cs != '.') + continue; + + if (gmatch(e->d_name, cs)) + { + addg(s, e->d_name, rescan, slashsav); + count++; + } + } + (void) closedir(dirf); + + if (rescan) + { + register struct argnod *rchain; + + rchain = gchain; + gchain = schain; + if (count) + { + count = 0; + while (rchain) + { + count += expand(rchain->argval, + slash + 1); + rchain = rchain->argnxt; + } + } + *rescan = '/'; + } + } + + if (slashsav) + *slashsav = '/'; + return (count); +} + +static int +addg(as1, as2, as3, as4) +unsigned char *as1, *as2, *as3, *as4; +{ + register unsigned char *s1, *s2; + register int c; + int len; + wchar_t wc; + + s2 = locstak() + BYTESPERWORD; + s1 = as1; + if (as4) { + while (c = *s1++) + { + if (s2 >= brkend) + growstak(s2); + *s2++ = c; + } + /* + * Restore first slash before the first metacharacter + * if as1 is not "/" + */ + if (as4 + 1 == s1) { + if (s2 >= brkend) + growstak(s2); + *s2++ = '/'; + } + } +/* add matched entries, plus extra \\ to escape \\'s */ + s1 = as2; + for (;;) + { + if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { + len = 1; + wc = (unsigned char)*s1; + } + if (s2 >= brkend) + growstak(s2); + + if (wc == 0) { + *s2 = *s1++; + break; + } + + if (wc == '\\') { + *s2++ = '\\'; + if (s2 >= brkend) + growstak(s2); + *s2++ = '\\'; + s1++; + continue; + } + if ((s2 + len) >= brkend) + growstak(s2 + len); + memcpy(s2, s1, len); + s2 += len; + s1 += len; + } + if (s1 = as3) + { + if (s2 >= brkend) + growstak(s2); + *s2++ = '/'; + do + { + if (s2 >= brkend) + growstak(s2); + } + while (*s2++ = *++s1); + } + makearg(endstak(s2)); +} + +makearg(args) + register struct argnod *args; +{ + args->argnxt = gchain; + gchain = args; +} diff --git a/usr/src/cmd/sh/fault.c b/usr/src/cmd/sh/fault.c new file mode 100644 index 0000000000..cb944d5318 --- /dev/null +++ b/usr/src/cmd/sh/fault.c @@ -0,0 +1,509 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13.17.1 */ +/* + * UNIX shell + */ + +#include "defs.h" +#include <sys/procset.h> +#include <siginfo.h> +#include <ucontext.h> +#include <errno.h> +#include <string.h> + +static void (*psig0_func)() = SIG_ERR; /* previous signal handler for signal 0 */ +static char sigsegv_stack[SIGSTKSZ]; + +static void sigsegv(int sig, siginfo_t *sip, ucontext_t *uap); +static void fault(); +static BOOL sleeping = 0; +static unsigned char *trapcom[MAXTRAP]; /* array of actions, one per signal */ +static BOOL trapflg[MAXTRAP] = +{ + 0, + 0, /* hangup */ + 0, /* interrupt */ + 0, /* quit */ + 0, /* illegal instr */ + 0, /* trace trap */ + 0, /* IOT */ + 0, /* EMT */ + 0, /* float pt. exp */ + 0, /* kill */ + 0, /* bus error */ + 0, /* memory faults */ + 0, /* bad sys call */ + 0, /* bad pipe call */ + 0, /* alarm */ + 0, /* software termination */ + 0, /* unassigned */ + 0, /* unassigned */ + 0, /* death of child */ + 0, /* power fail */ + 0, /* window size change */ + 0, /* urgent IO condition */ + 0, /* pollable event occured */ + 0, /* stopped by signal */ + 0, /* stopped by user */ + 0, /* continued */ + 0, /* stopped by tty input */ + 0, /* stopped by tty output */ + 0, /* virtual timer expired */ + 0, /* profiling timer expired */ + 0, /* exceeded cpu limit */ + 0, /* exceeded file size limit */ + 0, /* process's lwps are blocked */ + 0, /* special signal used by thread library */ + 0, /* check point freeze */ + 0, /* check point thaw */ +}; + +static void (*( +sigval[MAXTRAP]))() = +{ + 0, + done, /* hangup */ + fault, /* interrupt */ + fault, /* quit */ + done, /* illegal instr */ + done, /* trace trap */ + done, /* IOT */ + done, /* EMT */ + done, /* floating pt. exp */ + 0, /* kill */ + done, /* bus error */ + sigsegv, /* memory faults */ + done, /* bad sys call */ + done, /* bad pipe call */ + done, /* alarm */ + fault, /* software termination */ + done, /* unassigned */ + done, /* unassigned */ + 0, /* death of child */ + done, /* power fail */ + 0, /* window size change */ + done, /* urgent IO condition */ + done, /* pollable event occured */ + 0, /* uncatchable stop */ + 0, /* foreground stop */ + 0, /* stopped process continued */ + 0, /* background tty read */ + 0, /* background tty write */ + done, /* virtual timer expired */ + done, /* profiling timer expired */ + done, /* exceeded cpu limit */ + done, /* exceeded file size limit */ + 0, /* process's lwps are blocked */ + 0, /* special signal used by thread library */ + 0, /* check point freeze */ + 0, /* check point thaw */ +}; + +static int +ignoring(i) +register int i; +{ + struct sigaction act; + if (trapflg[i] & SIGIGN) + return (1); + sigaction(i, 0, &act); + if (act.sa_handler == SIG_IGN) { + trapflg[i] |= SIGIGN; + return (1); + } + return (0); +} + +static void +clrsig(i) +int i; +{ + if (trapcom[i] != 0) { + free(trapcom[i]); + trapcom[i] = 0; + } + + + if (trapflg[i] & SIGMOD) { + /* + * If the signal has been set to SIGIGN and we are now + * clearing the disposition of the signal (restoring it + * back to its default value) then we need to clear this + * bit as well + * + */ + if (trapflg[i] & SIGIGN) + trapflg[i] &= ~SIGIGN; + + trapflg[i] &= ~SIGMOD; + handle(i, sigval[i]); + } +} + +void +done(sig) +{ + register unsigned char *t; + int savxit; + + if (t = trapcom[0]) + { + trapcom[0] = 0; + /* Save exit value so trap handler will not change its val */ + savxit = exitval; + execexp(t, 0); + exitval = savxit; /* Restore exit value */ + free(t); + } + else + chktrap(); + + rmtemp(0); + rmfunctmp(); + +#ifdef ACCT + doacct(); +#endif + if (flags & subsh) { + /* in a subshell, need to wait on foreground job */ + collect_fg_job(); + } + + (void) endjobs(0); + if (sig) { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, sig); + sigprocmask(SIG_UNBLOCK, &set, 0); + handle(sig, SIG_DFL); + kill(mypid, sig); + } + exit(exitval); +} + +static void +fault(sig) +register int sig; +{ + register int flag; + + switch (sig) { + case SIGALRM: + if (sleeping) + return; + break; + } + + if (trapcom[sig]) + flag = TRAPSET; + else if (flags & subsh) + done(sig); + else + flag = SIGSET; + + trapnote |= flag; + trapflg[sig] |= flag; +} + +int +handle(sig, func) + int sig; + void (*func)(); +{ + int ret; + struct sigaction act, oact; + + if (func == SIG_IGN && (trapflg[sig] & SIGIGN)) + return (0); + + /* + * Ensure that sigaction is only called with valid signal numbers, + * we can get random values back for oact.sa_handler if the signal + * number is invalid + * + */ + if (sig > MINTRAP && sig < MAXTRAP) { + sigemptyset(&act.sa_mask); + act.sa_flags = (sig == SIGSEGV) ? (SA_ONSTACK | SA_SIGINFO) : 0; + act.sa_handler = func; + sigaction(sig, &act, &oact); + } + + if (func == SIG_IGN) + trapflg[sig] |= SIGIGN; + + /* + * Special case for signal zero, we can not obtain the previos + * action by calling sigaction, instead we save it in the variable + * psig0_func, so we can test it next time through this code + * + */ + if (sig == 0) { + ret = (psig0_func != func); + psig0_func = func; + } else { + ret = (func != oact.sa_handler); + } + + return (ret); +} + +void +stdsigs() +{ + register int i; + stack_t ss; + int err = 0; + int rtmin = (int)SIGRTMIN; + int rtmax = (int)SIGRTMAX; + + ss.ss_size = SIGSTKSZ; + ss.ss_sp = sigsegv_stack; + ss.ss_flags = 0; + errno = 0; + if (sigaltstack(&ss, (stack_t *)NULL) == -1) { + err = errno; + failure("sigaltstack(2) failed with", strerror(err)); + } + + for (i = 1; i < MAXTRAP; i++) { + if (i == rtmin) { + i = rtmax; + continue; + } + if (sigval[i] == 0) + continue; + if (i != SIGSEGV && ignoring(i)) + continue; + handle(i, sigval[i]); + } + + /* + * handle all the realtime signals + * + */ + for (i = rtmin; i <= rtmax; i++) { + handle(i, done); + } +} + +void +oldsigs() +{ + register int i; + register unsigned char *t; + + i = MAXTRAP; + while (i--) + { + t = trapcom[i]; + if (t == 0 || *t) + clrsig(i); + trapflg[i] = 0; + } + trapnote = 0; +} + +/* + * check for traps + */ + +void +chktrap() +{ + register int i = MAXTRAP; + register unsigned char *t; + + trapnote &= ~TRAPSET; + while (--i) + { + if (trapflg[i] & TRAPSET) + { + trapflg[i] &= ~TRAPSET; + if (t = trapcom[i]) + { + int savxit = exitval; + execexp(t, 0); + exitval = savxit; + exitset(); + } + } + } +} + +systrap(argc, argv) +int argc; +char **argv; +{ + int sig; + + if (argc == 1) { + /* + * print out the current action associated with each signal + * handled by the shell + * + */ + for (sig = 0; sig < MAXTRAP; sig++) { + if (trapcom[sig]) { + prn_buff(sig); + prs_buff(colon); + prs_buff(trapcom[sig]); + prc_buff(NL); + } + } + } else { + /* + * set the action for the list of signals + * + */ + char *cmd = *argv, *a1 = *(argv+1); + BOOL noa1; + noa1 = (str2sig(a1, &sig) == 0); + if (noa1 == 0) + ++argv; + while (*++argv) { + if (str2sig(*argv, &sig) < 0 || + sig >= MAXTRAP || sig < MINTRAP || + sig == SIGSEGV) { + failure(cmd, badtrap); + } else if (noa1) { + /* + * no action specifed so reset the siganl + * to its default disposition + * + */ + clrsig(sig); + } else if (*a1) { + /* + * set the action associated with the signal + * to a1 + * + */ + if (trapflg[sig] & SIGMOD || sig == 0 || + !ignoring(sig)) { + handle(sig, fault); + trapflg[sig] |= SIGMOD; + replace(&trapcom[sig], a1); + } + } else if (handle(sig, SIG_IGN)) { + /* + * set the action associated with the signal + * to SIG_IGN + * + */ + trapflg[sig] |= SIGMOD; + replace(&trapcom[sig], a1); + } + } + } +} + +unsigned int +sleep(ticks) +unsigned int ticks; +{ + sigset_t set, oset; + struct sigaction act, oact; + + + /* + * add SIGALRM to mask + */ + + sigemptyset(&set); + sigaddset(&set, SIGALRM); + sigprocmask(SIG_BLOCK, &set, &oset); + + /* + * catch SIGALRM + */ + + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = fault; + sigaction(SIGALRM, &act, &oact); + + /* + * start alarm and wait for signal + */ + + alarm(ticks); + sleeping = 1; + sigsuspend(&oset); + sleeping = 0; + + /* + * reset alarm, catcher and mask + */ + + alarm(0); + sigaction(SIGALRM, &oact, NULL); + sigprocmask(SIG_SETMASK, &oset, 0); + +} + +void +sigsegv(int sig, siginfo_t *sip, ucontext_t *uap) +{ + if (sip == (siginfo_t *)NULL) { + /* + * This should never happen, but if it does this is all we + * can do. It can only happen if sigaction(2) for SIGSEGV + * has been called without SA_SIGINFO being set. + * + */ + + exit(ERROR); + } else { + if (sip->si_code <= 0) { + /* + * If we are here then SIGSEGV must have been sent to + * us from a user process NOT as a result of an + * internal error within the shell eg + * kill -SEGV $$ + * will bring us here. So do the normal thing. + * + */ + fault(sig); + } else { + /* + * If we are here then there must have been an internal + * error within the shell to generate SIGSEGV eg + * the stack is full and we cannot call any more + * functions (Remeber this signal handler is running + * on an alternate stack). So we just exit cleanly + * with an error status (no core file). + */ + exit(ERROR); + } + } +} diff --git a/usr/src/cmd/sh/func.c b/usr/src/cmd/sh/func.c new file mode 100644 index 0000000000..de7196380f --- /dev/null +++ b/usr/src/cmd/sh/func.c @@ -0,0 +1,453 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4.1.3 */ +/* + * UNIX shell + */ + +#include "defs.h" + +freefunc(n) + struct namnod *n; +{ + freetree((struct trenod *)(n->namenv)); +} + + +freetree(t) + register struct trenod *t; +{ + if (t) + { + register int type; + + if (t->tretyp & CNTMSK) + { + t->tretyp--; + return; + } + + type = t->tretyp & COMMSK; + + switch (type) + { + case TFND: + free(fndptr(t)->fndnam); + freetree(fndptr(t)->fndval); + break; + + case TCOM: + freeio(comptr(t)->comio); + free_arg(comptr(t)->comarg); + free_arg(comptr(t)->comset); + break; + + case TFORK: + freeio(forkptr(t)->forkio); + freetree(forkptr(t)->forktre); + break; + + case TPAR: + freetree(parptr(t)->partre); + break; + + case TFIL: + case TLST: + case TAND: + case TORF: + freetree(lstptr(t)->lstlef); + freetree(lstptr(t)->lstrit); + break; + + case TFOR: + { + struct fornod *f = (struct fornod *)t; + + free(f->fornam); + freetree(f->fortre); + if (f->forlst) + { + freeio(f->forlst->comio); + free_arg(f->forlst->comarg); + free_arg(f->forlst->comset); + free(f->forlst); + } + } + break; + + case TWH: + case TUN: + freetree(whptr(t)->whtre); + freetree(whptr(t)->dotre); + break; + + case TIF: + freetree(ifptr(t)->iftre); + freetree(ifptr(t)->thtre); + freetree(ifptr(t)->eltre); + break; + + case TSW: + free(swptr(t)->swarg); + freereg(swptr(t)->swlst); + break; + } + free(t); + } +} + +free_arg(argp) + register struct argnod *argp; +{ + register struct argnod *sav; + + while (argp) + { + sav = argp->argnxt; + free(argp); + argp = sav; + } +} + + +freeio(iop) + register struct ionod *iop; +{ + register struct ionod *sav; + + while (iop) + { + if (iop->iofile & IODOC) + { + +#ifdef DEBUG + prs("unlinking "); + prs(iop->ioname); + newline(); +#endif + + unlink(iop->ioname); + + if (fiotemp == iop) + fiotemp = iop->iolst; + else + { + struct ionod *fiop = fiotemp; + + while (fiop->iolst != iop) + fiop = fiop->iolst; + + fiop->iolst = iop->iolst; + } + } + free(iop->ioname); + free(iop->iolink); + sav = iop->ionxt; + free(iop); + iop = sav; + } +} + + +freereg(regp) + register struct regnod *regp; +{ + register struct regnod *sav; + + while (regp) + { + free_arg(regp->regptr); + freetree(regp->regcom); + sav = regp->regnxt; + free(regp); + regp = sav; + } +} + + +static nonl = 0; + +prbgnlst() +{ + if (nonl) + prc_buff(SPACE); + else + prc_buff(NL); +} + +prendlst() +{ + if (nonl) { + prc_buff(';'); + prc_buff(SPACE); + } + else + prc_buff(NL); +} + +prcmd(t) +{ + nonl++; + prf(t); + nonl = 0; +} + +prf(t) + register struct trenod *t; +{ + sigchk(); + + if (t) + { + register int type; + + type = t->tretyp & COMMSK; + + switch(type) + { + case TFND: + { + register struct fndnod *f = (struct fndnod *)t; + + prs_buff(f->fndnam); + prs_buff("(){"); + prbgnlst(); + prf(f->fndval); + prbgnlst(); + prs_buff("}"); + break; + } + + case TCOM: + if (comptr(t)->comset) { + prarg(comptr(t)->comset); + prc_buff(SPACE); + } + prarg(comptr(t)->comarg); + prio(comptr(t)->comio); + break; + + case TFORK: + prf(forkptr(t)->forktre); + prio(forkptr(t)->forkio); + if (forkptr(t)->forktyp & FAMP) + prs_buff(" &"); + break; + + case TPAR: + prs_buff("("); + prf(parptr(t)->partre); + prs_buff(")"); + break; + + case TFIL: + prf(lstptr(t)->lstlef); + prs_buff(" | "); + prf(lstptr(t)->lstrit); + break; + + case TLST: + prf(lstptr(t)->lstlef); + prendlst(); + prf(lstptr(t)->lstrit); + break; + + case TAND: + prf(lstptr(t)->lstlef); + prs_buff(" && "); + prf(lstptr(t)->lstrit); + break; + + case TORF: + prf(lstptr(t)->lstlef); + prs_buff(" || "); + prf(lstptr(t)->lstrit); + break; + + case TFOR: + { + register struct argnod *arg; + register struct fornod *f = (struct fornod *)t; + + prs_buff("for "); + prs_buff(f->fornam); + + if (f->forlst) + { + arg = f->forlst->comarg; + prs_buff(" in"); + + while(arg != ENDARGS) + { + prc_buff(SPACE); + prs_buff(arg->argval); + arg = arg->argnxt; + } + } + + prendlst(); + prs_buff("do"); + prbgnlst(); + prf(f->fortre); + prendlst(); + prs_buff("done"); + } + break; + + case TWH: + case TUN: + if (type == TWH) + prs_buff("while "); + else + prs_buff("until "); + prf(whptr(t)->whtre); + prendlst(); + prs_buff("do"); + prbgnlst(); + prf(whptr(t)->dotre); + prendlst(); + prs_buff("done"); + break; + + case TIF: + { + struct ifnod *f = (struct ifnod *)t; + + prs_buff("if "); + prf(f->iftre); + prendlst(); + prs_buff("then"); + prendlst(); + prf(f->thtre); + + if (f->eltre) + { + prendlst(); + prs_buff("else"); + prendlst(); + prf(f->eltre); + } + + prendlst(); + prs_buff("fi"); + break; + } + + case TSW: + { + register struct regnod *swl; + + prs_buff("case "); + prs_buff(swptr(t)->swarg); + + swl = swptr(t)->swlst; + while(swl) + { + struct argnod *arg = swl->regptr; + + if (arg) + { + prs_buff(arg->argval); + arg = arg->argnxt; + } + + while(arg) + { + prs_buff(" | "); + prs_buff(arg->argval); + arg = arg->argnxt; + } + + prs_buff(")"); + prf(swl->regcom); + prs_buff(";;"); + swl = swl->regnxt; + } + } + break; + } + } + + sigchk(); +} + +prarg(argp) + register struct argnod *argp; +{ + while (argp) + { + prs_buff(argp->argval); + argp=argp->argnxt; + if (argp) + prc_buff(SPACE); + } +} + + +prio(iop) + register struct ionod *iop; +{ + register int iof; + register unsigned char *ion; + + while (iop) + { + iof = iop->iofile; + ion = (unsigned char *) iop->ioname; + + if (*ion) + { + prc_buff(SPACE); + + prn_buff(iof & IOUFD); + + if (iof & IODOC) + prs_buff("<<"); + else if (iof & IOMOV) + { + if (iof & IOPUT) + prs_buff(">&"); + else + prs_buff("<&"); + + } + else if ((iof & IOPUT) == 0) + prc_buff('<'); + else if (iof & IOAPP) + prs_buff(">>"); + else + prc_buff('>'); + + prs_buff(ion); + } + iop = iop->ionxt; + } +} diff --git a/usr/src/cmd/sh/hash.c b/usr/src/cmd/sh/hash.c new file mode 100644 index 0000000000..206583a846 --- /dev/null +++ b/usr/src/cmd/sh/hash.c @@ -0,0 +1,166 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3.2.1 */ + +#include "hash.h" +#include "defs.h" + +#define STRCMP(A, B) (cf(A, B) != 0) +#define FACTOR 035761254233 /* Magic multiplication factor */ +#define TABLENGTH 64 /* must be multiple of 2 */ +#define LOG2LEN 6 /* log2 of TABLENGTH */ + +/* + NOTE: The following algorithm only works on machines where + the results of multiplying two integers is the least + significant part of the double word integer required to hold + the result. It is adapted from Knuth, Volume 3, section 6.4. +*/ + +#define hash(str) (int)(((unsigned)(crunch(str) * FACTOR)) >> shift) +struct node +{ + ENTRY item; + struct node *next; +}; + +static struct node **last; +static struct node *next; +static struct node **table; + +static unsigned int bitsper; /* Bits per byte */ +static unsigned int shift; + +static unsigned int crunch(); + +hcreate() +{ + unsigned char c = (unsigned char)~0; /* A byte full of 1's */ + int j; + + table = (struct node **)alloc(TABLENGTH * sizeof(struct node *)); + + for (j=0; j < TABLENGTH; ++j) + { + table[j] = 0; + } + + bitsper = 0; + + while (c) + { + c = (unsigned int)c >> 1; + bitsper++; + } + + shift = (bitsper * sizeof(int)) - LOG2LEN; +} + + +void hscan(uscan) + void (*uscan)(); +{ + struct node *p, *nxt; + int j; + + for (j=0; j < TABLENGTH; ++j) + { + p = table[j]; + while (p) + { + nxt = p->next; + (*uscan)(&p->item); + p = nxt; + } + } +} + + + +ENTRY * +hfind(str) + unsigned char *str; +{ + struct node *p; + struct node **q; + unsigned int i; + int res; + + i = hash(str); + + if(table[i] == 0) + { + last = &table[i]; + next = 0; + return(0); + } + else + { + q = &table[i]; + p = table[i]; + while (p != 0 && (res = STRCMP(str, p->item.key))) + { + q = &(p->next); + p = p->next; + } + + if (p != 0 && res == 0) + return(&(p->item)); + else + { + last = q; + next = p; + return(0); + } + } +} + +ENTRY * +henter(item) + ENTRY item; +{ + struct node *p = (struct node *)alloc(sizeof(struct node)); + + p->item = item; + *last = p; + p->next = next; + return(&(p->item)); +} + + +static unsigned int +crunch(key) + unsigned char *key; +{ + unsigned int sum = 0; + int s; + + for (s = 0; *key; s++) /* Simply add up the bytes */ + sum += *key++; + + return(sum + s); +} + diff --git a/usr/src/cmd/sh/hash.h b/usr/src/cmd/sh/hash.h new file mode 100644 index 0000000000..2fb6d2e05f --- /dev/null +++ b/usr/src/cmd/sh/hash.h @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4.1.1 */ +/* + * UNIX shell + */ + +#define HASHZAP 0x03FF +#define CDMARK 0x8000 + +#define NOTFOUND 0x0000 +#define BUILTIN 0x0100 +#define FUNCTION 0x0200 +#define COMMAND 0x0400 +#define REL_COMMAND 0x0800 +#define PATH_COMMAND 0x1000 +#define DOT_COMMAND 0x8800 /* CDMARK | REL_COMMAND */ + +#define hashtype(x) (x & 0x1F00) +#define hashdata(x) (x & 0x00FF) + + +typedef struct entry +{ + unsigned char *key; + short data; + unsigned char hits; + unsigned char cost; + struct entry *next; +} ENTRY; + +extern ENTRY *hfind(); +extern ENTRY *henter(); +extern int hcreate(); diff --git a/usr/src/cmd/sh/hashserv.c b/usr/src/cmd/sh/hashserv.c new file mode 100644 index 0000000000..da80d3a2a9 --- /dev/null +++ b/usr/src/cmd/sh/hashserv.c @@ -0,0 +1,539 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* Portions Copyright(c) 1988, Sun Microsystems, Inc. */ +/* All Rights Reserved. */ + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10.5.1 */ +/* + * UNIX shell + */ + +#include "hash.h" +#include "defs.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> + +#define EXECUTE 01 + +static unsigned char cost; +static int dotpath; +static int multrel; +static struct entry relcmd; + +static int argpath(); + +short +pathlook(com, flg, arg) + unsigned char *com; + int flg; + register struct argnod *arg; +{ + register unsigned char *name = com; + register ENTRY *h; + + ENTRY hentry; + int count = 0; + int i; + int pathset = 0; + int oldpath = 0; + struct namnod *n; + + + + hentry.data = 0; + + if (any('/', name)) + return(COMMAND); + + h = hfind(name); + + + if (h) + { + if (h->data & (BUILTIN | FUNCTION)) + { + if (flg) + h->hits++; + return(h->data); + } + + if (arg && (pathset = argpath(arg))) + return(PATH_COMMAND); + + if ((h->data & DOT_COMMAND) == DOT_COMMAND) + { + if (multrel == 0 && hashdata(h->data) > dotpath) + oldpath = hashdata(h->data); + else + oldpath = dotpath; + + h->data = 0; + goto pathsrch; + } + + if (h->data & (COMMAND | REL_COMMAND)) + { + if (flg) + h->hits++; + return(h->data); + } + + h->data = 0; + h->cost = 0; + } + + if (i = syslook(name, commands, no_commands)) + { + hentry.data = (BUILTIN | i); + count = 1; + } + else + { + if (arg && (pathset = argpath(arg))) + return(PATH_COMMAND); +pathsrch: + count = findpath(name, oldpath); + } + + if (count > 0) + { + if (h == 0) + { + hentry.cost = 0; + hentry.key = make(name); + h = henter(hentry); + } + + if (h->data == 0) + { + if (count < dotpath) + h->data = COMMAND | count; + else + { + h->data = REL_COMMAND | count; + h->next = relcmd.next; + relcmd.next = h; + } + } + + + h->hits = flg; + h->cost += cost; + return(h->data); + } + else + { + return(-count); + } +} + + +static void +zapentry(h) + ENTRY *h; +{ + h->data &= HASHZAP; +} + +void +zaphash() +{ + hscan(zapentry); + relcmd.next = 0; +} + +void +zapcd() +{ + ENTRY *ptr = relcmd.next; + + while (ptr) + { + ptr->data |= CDMARK; + ptr = ptr->next; + } + relcmd.next = 0; +} + + +static void +hashout(h) + ENTRY *h; +{ + sigchk(); + + if (hashtype(h->data) == NOTFOUND) + return; + + if (h->data & (BUILTIN | FUNCTION)) + return; + + prn_buff(h->hits); + + if (h->data & REL_COMMAND) + prc_buff('*'); + + + prc_buff(TAB); + prn_buff(h->cost); + prc_buff(TAB); + + pr_path(h->key, hashdata(h->data)); + prc_buff(NL); +} + +void +hashpr() +{ + prs_buff("hits cost command\n"); + hscan(hashout); +} + + +set_dotpath() +{ + register unsigned char *path; + register int cnt = 1; + + dotpath = 10000; + path = getpath(""); + + while (path && *path) + { + if (*path == '/') + cnt++; + else + { + if (dotpath == 10000) + dotpath = cnt; + else + { + multrel = 1; + return; + } + } + + path = nextpath(path); + } + + multrel = 0; +} + + +hash_func(name) + unsigned char *name; +{ + ENTRY *h; + ENTRY hentry; + + h = hfind(name); + + if (h) + h->data = FUNCTION; + else + { + hentry.data = FUNCTION; + hentry.key = make(name); + hentry.cost = 0; + hentry.hits = 0; + henter(hentry); + } +} + +func_unhash(name) + unsigned char *name; +{ + ENTRY *h; + int i; + + h = hfind(name); + + if (h && (h->data & FUNCTION)) { + if(i = syslook(name, commands, no_commands)) + h->data = (BUILTIN|i); + else + h->data = NOTFOUND; + } +} + + +short +hash_cmd(name) + unsigned char *name; +{ + ENTRY *h; + + if (any('/', name)) + return(COMMAND); + + h = hfind(name); + + if (h) + { + if (h->data & (BUILTIN | FUNCTION)) + return(h->data); + else if ((h->data & REL_COMMAND) == REL_COMMAND) + { /* unlink h from relative command list */ + ENTRY *ptr = &relcmd; + while(ptr-> next != h) + ptr = ptr->next; + ptr->next = h->next; + } + zapentry(h); + } + + return(pathlook(name, 0, 0)); +} + + +/* + * Return 0 if found, 1 if not. + */ +what_is_path(name) + register unsigned char *name; +{ + register ENTRY *h; + int cnt; + short hashval; + + h = hfind(name); + + prs_buff(name); + if (h) + { + hashval = hashdata(h->data); + + switch (hashtype(h->data)) + { + case BUILTIN: + prs_buff(" is a shell builtin\n"); + return (0); + + case FUNCTION: + { + struct namnod *n = lookup(name); + + prs_buff(" is a function\n"); + prs_buff(name); + prs_buff("(){\n"); + prf(n->namenv); + prs_buff("\n}\n"); + return (0); + } + + case REL_COMMAND: + { + short hash; + + if ((h->data & DOT_COMMAND) == DOT_COMMAND) + { + hash = pathlook(name, 0, 0); + if (hashtype(hash) == NOTFOUND) + { + prs_buff(" not found\n"); + return (1); + } + else + hashval = hashdata(hash); + } + } + + case COMMAND: + prs_buff(" is hashed ("); + pr_path(name, hashval); + prs_buff(")\n"); + return (0); + } + } + + if (syslook(name, commands, no_commands)) + { + prs_buff(" is a shell builtin\n"); + return (0); + } + + if ((cnt = findpath(name, 0)) > 0) + { + prs_buff(" is "); + pr_path(name, cnt); + prc_buff(NL); + return (0); + } + else + { + prs_buff(" not found\n"); + return (1); + } +} + + +findpath(name, oldpath) + register unsigned char *name; + int oldpath; +{ + register unsigned char *path; + register int count = 1; + + unsigned char *p; + int ok = 1; + int e_code = 1; + + cost = 0; + path = getpath(name); + + if (oldpath) + { + count = dotpath; + while (--count) + path = nextpath(path); + + if (oldpath > dotpath) + { + catpath(path, name); + p = curstak(); + cost = 1; + + if ((ok = chk_access(p, S_IEXEC, 1)) == 0) + return(dotpath); + else + return(oldpath); + } + else + count = dotpath; + } + + while (path) + { + path = catpath(path, name); + cost++; + p = curstak(); + + if ((ok = chk_access(p, S_IEXEC, 1)) == 0) + break; + else + e_code = max(e_code, ok); + + count++; + } + + return(ok ? -e_code : count); +} + +/* + * Determine if file given by name is accessible with permissions + * given by mode. + * Regflag argument non-zero means not to consider + * a non-regular file as executable. + */ + +chk_access(name, mode, regflag) +register unsigned char *name; +mode_t mode; +int regflag; +{ + static int flag; + static uid_t euid; + struct stat statb; + mode_t ftype; + + if(flag == 0) { + euid = geteuid(); + flag = 1; + } + ftype = statb.st_mode & S_IFMT; + if (stat((char *)name, &statb) == 0) { + ftype = statb.st_mode & S_IFMT; + if(mode == S_IEXEC && regflag && ftype != S_IFREG) + return(2); + if(access((char *)name, 010|(mode>>6)) == 0) { + if(euid == 0) { + if (ftype != S_IFREG || mode != S_IEXEC) + return(0); + /* root can execute file as long as it has execute + permission for someone */ + if (statb.st_mode & (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))) + return(0); + return(3); + } + return(0); + } + } + return(errno == EACCES ? 3 : 1); +} + + +pr_path(name, count) + register unsigned char *name; + int count; +{ + register unsigned char *path; + + path = getpath(name); + + while (--count && path) + path = nextpath(path, name); + + catpath(path, name); + prs_buff(curstak()); +} + + +static +argpath(arg) + register struct argnod *arg; +{ + register unsigned char *s; + register unsigned char *start; + + while (arg) + { + s = arg->argval; + start = s; + + if (letter(*s)) + { + while (alphanum(*s)) + s++; + + if (*s == '=') + { + *s = 0; + + if (eq(start, pathname)) + { + *s = '='; + return(1); + } + else + *s = '='; + } + } + arg = arg->argnxt; + } + + return(0); +} diff --git a/usr/src/cmd/sh/io.c b/usr/src/cmd/sh/io.c new file mode 100644 index 0000000000..d6443f405b --- /dev/null +++ b/usr/src/cmd/sh/io.c @@ -0,0 +1,399 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, 2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10.2.1 */ +/* + * UNIX shell + */ + +#include "defs.h" +#include "dup.h" +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> + +short topfd; + +/* ======== input output and file copying ======== */ + +initf(fd) +int fd; +{ + register struct fileblk *f = standin; + + f->fdes = fd; + f->fsiz = ((flags & oneflg) == 0 ? BUFFERSIZE : 1); + f->fnxt = f->fend = f->fbuf; + f->nxtoff = f->endoff = 0; + f->feval = 0; + f->flin = 1; + f->feof = FALSE; +} + +estabf(s) +register unsigned char *s; +{ + register struct fileblk *f; + + (f = standin)->fdes = -1; + f->fend = length(s) + (f->fnxt = s); + f->nxtoff = 0; + f->endoff = length(s); + f->flin = 1; + return (f->feof = (s == 0)); +} + +push(af) +struct fileblk *af; +{ + register struct fileblk *f; + + (f = af)->fstak = standin; + f->feof = 0; + f->feval = 0; + standin = f; +} + +pop() +{ + register struct fileblk *f; + + if ((f = standin)->fstak) + { + if (f->fdes >= 0) + close(f->fdes); + standin = f->fstak; + return (TRUE); + }else + return (FALSE); +} + +struct tempblk *tmpfptr; + +pushtemp(fd, tb) + int fd; + struct tempblk *tb; +{ + tb->fdes = fd; + tb->fstak = tmpfptr; + tmpfptr = tb; +} + +poptemp() +{ + if (tmpfptr){ + close(tmpfptr->fdes); + tmpfptr = tmpfptr->fstak; + return (TRUE); + }else + return (FALSE); +} + +chkpipe(pv) +int *pv; +{ + if (pipe(pv) < 0 || pv[INPIPE] < 0 || pv[OTPIPE] < 0) + error(piperr); +} + +chkopen(idf, mode) +unsigned char *idf; +int mode; +{ + register int rc; + + if ((rc = open((char *)idf, mode, 0666)) < 0) + failed(idf, badopen); + else + return (rc); +} + +/* + * Make f2 be a synonym (including the close-on-exec flag) for f1, which is + * then closed. If f2 is descriptor 0, modify the global ioset variable + * accordingly. + */ +renamef(f1, f2) +register int f1, f2; +{ +#ifdef RES + if (f1 != f2) + { + dup(f1 | DUPFLG, f2); + close(f1); + if (f2 == 0) + ioset |= 1; + } +#else + int fs; + + if (f1 != f2) + { + fs = fcntl(f2, 1, 0); + close(f2); + fcntl(f1, 0, f2); + close(f1); + if (fs == 1) + fcntl(f2, 2, 1); + if (f2 == 0) + ioset |= 1; + } +#endif +} + +create(s) +unsigned char *s; +{ + register int rc; + + if ((rc = creat((char *)s, 0666)) < 0) + failed(s, badcreate); + else + return (rc); +} + + +tmpfil(tb) + struct tempblk *tb; +{ + int fd; + + /* make sure tmp file does not already exist. */ + do { + itos(serial++); + movstr(numbuf, tmpname); + fd = open((char *)tmpout, O_RDWR|O_CREAT|O_EXCL, 0666); + } while ((fd == -1) && (errno == EEXIST)); + if (fd != -1) { + pushtemp(fd, tb); + return (fd); + } + else + failed(tmpout, badcreate); + +} + +/* + * set by trim + */ +extern BOOL nosubst; +#define CPYSIZ 512 + +copy(ioparg) +struct ionod *ioparg; +{ + register unsigned char *cline; + register unsigned char *clinep; + register struct ionod *iop; + unsigned int c; + unsigned char *ends; + unsigned char *start; + int fd; + int i; + int stripflg; + unsigned char *pc; + + + if (iop = ioparg) + { + struct tempblk tb; + copy(iop->iolst); + ends = mactrim(iop->ioname); + stripflg = iop->iofile & IOSTRIP; + if (nosubst) + iop->iofile &= ~IODOC; + fd = tmpfil(&tb); + + if (fndef) + iop->ioname = (char *) make(tmpout); + else + iop->ioname = (char *) cpystak(tmpout); + + iop->iolst = iotemp; + iotemp = iop; + + cline = clinep = start = locstak(); + if (stripflg) + { + iop->iofile &= ~IOSTRIP; + while (*ends == '\t') + ends++; + } + for (;;) + { + chkpr(); + if (nosubst) + { + c = readwc(); + if (stripflg) + while (c == '\t') + c = readwc(); + + while (!eolchar(c)) + { + pc = readw(c); + while (*pc) { + if (clinep >= brkend) + growstak(clinep); + *clinep++ = *pc++; + } + c = readwc(); + } + }else{ + c = nextwc(); + if (stripflg) + while (c == '\t') + c = nextwc(); + + while (!eolchar(c)) + { + pc = readw(c); + while (*pc) { + if (clinep >= brkend) + growstak(clinep); + *clinep++ = *pc++; + } + if (c == '\\') + { + pc = readw(readwc()); + /* *pc might be NULL */ + if (*pc) { + while (*pc) { + if (clinep >= brkend) + growstak(clinep); + *clinep++ = *pc++; + } + } else { + if (clinep >= brkend) + growstak(clinep); + *clinep++ = *pc; + } + } + c = nextwc(); + } + } + + if (clinep >= brkend) + growstak(clinep); + *clinep = 0; + if (eof || eq(cline, ends)) + { + if ((i = cline - start) > 0) + write(fd, start, i); + break; + }else{ + if (clinep >= brkend) + growstak(clinep); + *clinep++ = NL; + } + + if ((i = clinep - start) < CPYSIZ) + cline = clinep; + else + { + write(fd, start, i); + cline = clinep = start; + } + } + + poptemp(); /* + * pushed in tmpfil -- bug fix for problem + * deleting in-line scripts + */ + } +} + + +link_iodocs(i) + struct ionod *i; +{ + int r; + + while (i) + { + free(i->iolink); + + /* make sure tmp file does not already exist. */ + do { + itos(serial++); + movstr(numbuf, tmpname); + r = link(i->ioname, (char *)tmpout); + } while (r == -1 && errno == EEXIST); + + if (r != -1) { + i->iolink = (char *)make(tmpout); + i = i->iolst; + } else + failed(tmpout, badcreate); + + } +} + + +swap_iodoc_nm(i) + struct ionod *i; +{ + while (i) + { + free(i->ioname); + i->ioname = i->iolink; + i->iolink = 0; + + i = i->iolst; + } +} + + +savefd(fd) + int fd; +{ + register int f; + + f = fcntl(fd, F_DUPFD, 10); + return (f); +} + + +restore(last) + register int last; +{ + register int i; + register int dupfd; + + for (i = topfd - 1; i >= last; i--) + { + if ((dupfd = fdmap[i].dup_fd) > 0) + renamef(dupfd, fdmap[i].org_fd); + else + close(fdmap[i].org_fd); + } + topfd = last; +} diff --git a/usr/src/cmd/sh/jobs.c b/usr/src/cmd/sh/jobs.c new file mode 100644 index 0000000000..0ed3f1a171 --- /dev/null +++ b/usr/src/cmd/sh/jobs.c @@ -0,0 +1,1077 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Job control for UNIX Shell + */ + +#include <sys/termio.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/param.h> +#include <fcntl.h> +#include <errno.h> +#include "defs.h" + +/* + * one of these for each active job + */ + +struct job +{ + struct job *j_nxtp; /* next job in job ID order */ + struct job *j_curp; /* next job in job currency order */ + struct termios j_stty; /* termio save area when job stops */ + pid_t j_pid; /* job leader's process ID */ + pid_t j_pgid; /* job's process group ID */ + pid_t j_tgid; /* job's foreground process group ID */ + uint j_jid; /* job ID */ + ushort j_xval; /* exit code, or exit or stop signal */ + ushort j_flag; /* various status flags defined below */ + char *j_pwd; /* job's working directory */ + char *j_cmd; /* cmd used to invoke this job */ +}; + +/* defines for j_flag */ + +#define J_DUMPED 0001 /* job has core dumped */ +#define J_NOTIFY 0002 /* job has changed status */ +#define J_SAVETTY 0004 /* job was stopped in foreground, and its */ + /* termio settings were saved */ +#define J_STOPPED 0010 /* job has been stopped */ +#define J_SIGNALED 0020 /* job has received signal; j_xval has it */ +#define J_DONE 0040 /* job has finished */ +#define J_RUNNING 0100 /* job is currently running */ +#define J_FOREGND 0200 /* job was put in foreground by shell */ + +/* options to the printjob() function defined below */ + +#define PR_CUR 00001 /* print job currency ('+', '-', or ' ') */ +#define PR_JID 00002 /* print job ID */ +#define PR_PGID 00004 /* print job's process group ID */ +#define PR_STAT 00010 /* print status obtained from wait */ +#define PR_CMD 00020 /* print cmd that invoked job */ +#define PR_AMP 00040 /* print a '&' if in the background */ +#define PR_PWD 00100 /* print jobs present working directory */ + +#define PR_DFL (PR_CUR|PR_JID|PR_STAT|PR_CMD) /* default options */ +#define PR_LONG (PR_DFL|PR_PGID|PR_PWD) /* long options */ + +static struct termios mystty; /* default termio settings */ +static int eofflg, + jobcnt, /* number of active jobs */ + jobdone, /* number of active but finished jobs */ + jobnote; /* jobs requiring notification */ +static pid_t svpgid, /* saved process group ID */ + svtgid; /* saved foreground process group ID */ +static struct job *jobcur, /* active jobs listed in currency order */ + **nextjob, + *thisjob, + *joblst; /* active jobs listed in job ID order */ + +pid_t +tcgetpgrp(fd) +{ + pid_t pgid; + if (ioctl(fd, TIOCGPGRP, &pgid) == 0) + return (pgid); + return ((pid_t)-1); +} + +int +tcsetpgrp(fd, pgid) +int fd; +pid_t pgid; +{ + return (ioctl(fd, TIOCSPGRP, &pgid)); +} + +static struct job * +pgid2job(pgid) +register pid_t pgid; +{ + register struct job *jp; + + for (jp = joblst; jp != 0 && jp->j_pid != pgid; jp = jp->j_nxtp) + continue; + + return (jp); +} + +static struct job * +str2job(cmd, job, mustbejob) +register char *cmd; +register char *job; +int mustbejob; +{ + register struct job *jp, *njp; + register i; + + if (*job != '%') + jp = pgid2job(stoi(job)); + else if (*++job == 0 || *job == '+' || *job == '%' || *job == '-') { + jp = jobcur; + if (*job == '-' && jp) + jp = jp->j_curp; + } else if (*job >= '0' && *job <= '9') { + i = stoi(job); + for (jp = joblst; jp && jp->j_jid != i; jp = jp->j_nxtp) + continue; + } else if (*job == '?') { + register j; + register char *p; + i = strlen(++job); + jp = 0; + for (njp = jobcur; njp; njp = njp->j_curp) { + if (njp->j_jid == 0) + continue; + for (p = njp->j_cmd, j = strlen(p); j >= i; p++, j--) { + if (strncmp(job, p, i) == 0) { + if (jp != 0) + failed(cmd, ambiguous); + jp = njp; + break; + } + } + } + } else { + i = strlen(job); + jp = 0; + for (njp = jobcur; njp; njp = njp->j_curp) { + if (njp->j_jid == 0) + continue; + if (strncmp(job, njp->j_cmd, i) == 0) { + if (jp != 0) + failed(cmd, ambiguous); + jp = njp; + } + } + } + + if (mustbejob && (jp == 0 || jp->j_jid == 0)) + failed(cmd, nosuchjob); + + return (jp); +} + +static void +freejob(jp) +register struct job *jp; +{ + register struct job **njp; + register struct job **cjp; + + for (njp = &joblst; *njp != jp; njp = &(*njp)->j_nxtp) + continue; + + for (cjp = &jobcur; *cjp != jp; cjp = &(*cjp)->j_curp) + continue; + + *njp = jp->j_nxtp; + *cjp = jp->j_curp; + free(jp); + jobcnt--; + jobdone--; +} + +/* + * Collect the foreground job. + * Used in the case where the subshell wants + * to exit, but needs to wait until the fg job + * is done. + */ +collect_fg_job() +{ + register struct job *jp; + register pid_t pid; + int stat; + + for (jp = joblst; jp; jp = jp->j_nxtp) + if (jp->j_flag & J_FOREGND) + break; + + if (!jp) + /* no foreground job */ + return; + + /* + * Wait on fg job until wait succeeds + * or it fails due to no waitable children. + */ + + while (1) { + errno = 0; + pid = waitpid(jp->j_pid, &stat, 0); + if (pid == jp->j_pid || (pid == -1 && errno == ECHILD)) + break; + } +} + +/* + * analyze the status of a job + */ + +static int +statjob(jp, stat, fg, rc) +register struct job *jp; +register stat; +int fg; +int rc; +{ + pid_t tgid; + int done = 0; + + if (WIFCONTINUED(stat)) { + if (jp->j_flag & J_STOPPED) { + jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY); + jp->j_flag |= J_RUNNING; + if (!fg && jp->j_jid) { + jp->j_flag |= J_NOTIFY; + jobnote++; + } + } + } else if (WIFSTOPPED(stat)) { + jp->j_xval = WSTOPSIG(stat); + jp->j_flag &= ~J_RUNNING; + jp->j_flag |= (J_SIGNALED|J_STOPPED); + jp->j_pgid = getpgid(jp->j_pid); + jp->j_tgid = jp->j_pgid; + if (fg) { + if (tgid = settgid(mypgid, jp->j_pgid)) + jp->j_tgid = tgid; + else { + jp->j_flag |= J_SAVETTY; + tcgetattr(0, &jp->j_stty); + (void) tcsetattr(0, TCSANOW, &mystty); + } + } + if (jp->j_jid) { + jp->j_flag |= J_NOTIFY; + jobnote++; + } + } else { + jp->j_flag &= ~J_RUNNING; + jp->j_flag |= J_DONE; + done++; + jobdone++; + if (WIFSIGNALED(stat)) { + jp->j_xval = WTERMSIG(stat); + jp->j_flag |= J_SIGNALED; + if (WCOREDUMP(stat)) + jp->j_flag |= J_DUMPED; + if (!fg || jp->j_xval != SIGINT) { + jp->j_flag |= J_NOTIFY; + jobnote++; + } + } else { /* WIFEXITED */ + jp->j_xval = WEXITSTATUS(stat); + jp->j_flag &= ~J_SIGNALED; + if (!fg && jp->j_jid) { + jp->j_flag |= J_NOTIFY; + jobnote++; + } + } + if (fg) { + if (!settgid(mypgid, jp->j_pgid) || + !settgid(mypgid, getpgid(jp->j_pid))) + tcgetattr(0, &mystty); + } + } + if (rc) { + exitval = jp->j_xval; + if (jp->j_flag & J_SIGNALED) + exitval |= SIGFLG; + exitset(); + } + if (done && !(jp->j_flag & J_NOTIFY)) + freejob(jp); + return (done); +} + +/* + * collect the status of jobs that have recently exited or stopped - + * if wnohang == WNOHANG, wait until error, or all jobs are accounted for; + * + * called after each command is executed, with wnohang == 0, and as part + * of "wait" builtin with wnohang == WNOHANG + * + * We do not need to call chktrap here if waitpid(2) is called with + * wnohang == 0, because that only happens from syswait() which is called + * from builtin() where chktrap() is already called. + */ + +static void +collectjobs(wnohang) +{ + pid_t pid; + register struct job *jp; + int stat, n; + int wflags; + + if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) + wflags = WUNTRACED|WCONTINUED; + else + wflags = 0; + + for (n = jobcnt - jobdone; n > 0; n--) { + if ((pid = waitpid(-1, &stat, wnohang|wflags)) <= 0) + break; + if (jp = pgid2job(pid)) + (void) statjob(jp, stat, 0, 0); + } + +} + +void +freejobs() +{ + register struct job *jp; + + collectjobs(WNOHANG); + + if (jobnote) { + register int savefd = setb(2); + for (jp = joblst; jp; jp = jp->j_nxtp) { + if (jp->j_flag & J_NOTIFY) { + if (jp->j_jid) + printjob(jp, PR_DFL); + else if (jp->j_flag & J_FOREGND) + printjob(jp, PR_STAT); + else + printjob(jp, PR_STAT|PR_PGID); + } + } + (void) setb(savefd); + } + + if (jobdone) { + for (jp = joblst; jp; jp = jp->j_nxtp) { + if (jp->j_flag & J_DONE) + freejob(jp); + } + } +} + +static void +waitjob(jp) +register struct job *jp; +{ + int stat; + int done; + pid_t pid = jp->j_pid; + int wflags; + int ret = 0; + int err = 0; + + if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) + wflags = WUNTRACED; + else + wflags = 0; + do { + errno = 0; + ret = waitpid(pid, &stat, wflags|WNOWAIT); + err = errno; + if (ret == -1 && err == ECHILD) { + stat = 0; + break; + } + } while (ret != pid); + + done = statjob(jp, stat, 1, 1); + waitpid(pid, 0, wflags); + if (done && exitval && (flags & errflg)) + exitsh(exitval); + flags |= eflag; +} + +/* + * modify the foreground process group to *new* only if the + * current foreground process group is equal to *expected* + */ + +int +settgid(new, expected) +pid_t new, expected; +{ + register pid_t current = tcgetpgrp(0); + + if (current != expected) + return (current); + + if (new != current) + tcsetpgrp(0, new); + + return (0); +} + +static void +restartjob(jp, fg) +register struct job *jp; +{ + if (jp != jobcur) { + register struct job *t; + for (t = jobcur; t->j_curp != jp; t = t->j_curp); + t->j_curp = jp->j_curp; + jp->j_curp = jobcur; + jobcur = jp; + } + if (fg) { + if (jp->j_flag & J_SAVETTY) { + jp->j_stty.c_lflag &= ~TOSTOP; + jp->j_stty.c_lflag |= (mystty.c_lflag&TOSTOP); + jp->j_stty.c_cc[VSUSP] = mystty.c_cc[VSUSP]; + jp->j_stty.c_cc[VDSUSP] = mystty.c_cc[VDSUSP]; + (void) tcsetattr(0, TCSADRAIN, &jp->j_stty); + } + (void) settgid(jp->j_tgid, mypgid); + } + (void) kill(-(jp->j_pgid), SIGCONT); + if (jp->j_tgid != jp->j_pgid) + (void) kill(-(jp->j_tgid), SIGCONT); + jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY); + jp->j_flag |= J_RUNNING; + if (fg) { + jp->j_flag |= J_FOREGND; + printjob(jp, PR_JID|PR_CMD); + waitjob(jp); + } else { + jp->j_flag &= ~J_FOREGND; + printjob(jp, PR_JID|PR_CMD|PR_AMP); + } +} + +static +printjob(jp, propts) +register struct job *jp; +{ + int sp = 0; + + if (jp->j_flag & J_NOTIFY) { + jobnote--; + jp->j_flag &= ~J_NOTIFY; + } + + if (propts & PR_JID) { + prc_buff('['); + prn_buff(jp->j_jid); + prc_buff(']'); + sp = 1; + } + + if (propts & PR_CUR) { + while (sp-- > 0) + prc_buff(SPACE); + sp = 1; + if (jobcur == jp) + prc_buff('+'); + else if (jobcur != 0 && jobcur->j_curp == jp) + prc_buff('-'); + else + sp++; + } + + if (propts & PR_PGID) { + while (sp-- > 0) + prc_buff(SPACE); + prn_buff(jp->j_pid); + sp = 1; + } + + if (propts & PR_STAT) { + while (sp-- > 0) + prc_buff(SPACE); + sp = 28; + if (jp->j_flag & J_SIGNALED) { + char *sigstr, *strsignal(); + if ((sigstr = strsignal(jp->j_xval)) != NULL) { + sp -= strlen(sigstr); + prs_buff(sigstr); + } else { + itos(jp->j_xval); + sp -= strlen(numbuf) + 7; + prs_buff("Signal "); + prs_buff(numbuf); + } + if (jp->j_flag & J_DUMPED) { + sp -= strlen(coredump); + prs_buff(coredump); + } + } else if (jp->j_flag & J_DONE) { + itos(jp->j_xval); + sp -= strlen(exited) + strlen(numbuf) + 2; + prs_buff(exited); + prc_buff('('); + itos(jp->j_xval); + prs_buff(numbuf); + prc_buff(')'); + } else { + sp -= strlen(running); + prs_buff(running); + } + if (sp < 1) + sp = 1; + } + + if (propts & PR_CMD) { + while (sp-- > 0) + prc_buff(SPACE); + prs_buff(jp->j_cmd); + sp = 1; + } + + if (propts & PR_AMP) { + while (sp-- > 0) + prc_buff(SPACE); + prc_buff('&'); + sp = 1; + } + + if (propts & PR_PWD) { + while (sp-- > 0) + prc_buff(SPACE); + prs_buff("(wd: "); + prs_buff(jp->j_pwd); + prc_buff(')'); + } + + prc_buff(NL); + flushb(); + +} + + +/* + * called to initialize job control for each new input file to the shell, + * and after the "exec" builtin + */ + +void +startjobs() +{ + svpgid = mypgid; + + if (tcgetattr(0, &mystty) == -1 || (svtgid = tcgetpgrp(0)) == -1) { + flags &= ~jcflg; + return; + } + + flags |= jcflg; + + handle(SIGTTOU, SIG_IGN); + handle(SIGTSTP, SIG_DFL); + + if (mysid != mypgid) { + setpgid(0, 0); + mypgid = mypid; + (void) settgid(mypgid, svpgid); + } + +} + +int +endjobs(check_if) +int check_if; +{ + if ((flags & (jcoff|jcflg)) != jcflg) + return (1); + + if (check_if && jobcnt && eofflg++ == 0) { + register struct job *jp; + if (check_if & JOB_STOPPED) { + for (jp = joblst; jp; jp = jp->j_nxtp) { + if (jp->j_jid && (jp->j_flag & J_STOPPED)) { + prs(jobsstopped); + prc(NL); + return (0); + } + } + } + if (check_if & JOB_RUNNING) { + for (jp = joblst; jp; jp = jp->j_nxtp) { + if (jp->j_jid && (jp->j_flag & J_RUNNING)) { + prs(jobsrunning); + prc(NL); + return (0); + } + } + } + } + + if (svpgid != mypgid) { + (void) settgid(svtgid, mypgid); + setpgid(0, svpgid); + } + + return (1); +} + + +/* + * called by the shell to reserve a job slot for a job about to be spawned + */ + +void +deallocjob() +{ + free(thisjob); + jobcnt--; +} + +allocjob(cmd, cwd, monitor) +register char *cmd; +register unchar *cwd; +int monitor; +{ + register struct job *jp, **jpp; + register int jid, cmdlen, cwdlen; + + cmdlen = strlen(cmd) + 1; + if (cmd[cmdlen-2] == '&') { + cmd[cmdlen-3] = 0; + cmdlen -= 2; + } + cwdlen = strlen(cwd) + 1; + jp = (struct job *) alloc(sizeof (struct job) + cmdlen + cwdlen); + if (jp == 0) + error(nostack); + jobcnt++; + jp->j_cmd = ((char *)jp) + sizeof (struct job); + strcpy(jp->j_cmd, cmd); + jp->j_pwd = jp->j_cmd + cmdlen; + strcpy(jp->j_pwd, cwd); + + jpp = &joblst; + + if (monitor) { + for (; *jpp; jpp = &(*jpp)->j_nxtp) + if ((*jpp)->j_jid != 0) + break; + for (jid = 1; *jpp; jpp = &(*jpp)->j_nxtp, jid++) + if ((*jpp)->j_jid != jid) + break; + } else + jid = 0; + + jp->j_jid = jid; + nextjob = jpp; + thisjob = jp; +} + +clearjobs() +{ + register struct job *jp, *sjp; + + for (jp = joblst; jp; jp = sjp) { + sjp = jp->j_nxtp; + free(jp); + } + joblst = NULL; + jobcnt = 0; + jobnote = 0; + jobdone = 0; + +} + +makejob(monitor, fg) +int monitor, fg; +{ + if (monitor) { + mypgid = mypid; + setpgid(0, 0); + if (fg) + tcsetpgrp(0, mypid); + handle(SIGTTOU, SIG_DFL); + handle(SIGTSTP, SIG_DFL); + } else if (!fg) { +#ifdef NICE + nice(NICE); +#endif + handle(SIGTTIN, SIG_IGN); + handle(SIGINT, SIG_IGN); + handle(SIGQUIT, SIG_IGN); + if (!ioset) + renamef(chkopen(devnull, 0), 0); + } +} + +/* + * called by the shell after job has been spawned, to fill in the + * job slot, and wait for the job if in the foreground + */ + +void +postjob(pid, fg) +pid_t pid; +int fg; +{ + + register propts; + + thisjob->j_nxtp = *nextjob; + *nextjob = thisjob; + thisjob->j_curp = jobcur; + jobcur = thisjob; + + if (thisjob->j_jid) { + thisjob->j_pgid = pid; + propts = PR_JID|PR_PGID; + } else { + thisjob->j_pgid = mypgid; + propts = PR_PGID; + } + + thisjob->j_flag = J_RUNNING; + thisjob->j_tgid = thisjob->j_pgid; + thisjob->j_pid = pid; + eofflg = 0; + + if (fg) { + thisjob->j_flag |= J_FOREGND; + waitjob(thisjob); + } else { + if (flags & ttyflg) + printjob(thisjob, propts); + assnum(&pcsadr, (long)pid); + } +} + +/* + * the builtin "jobs" command + */ + +void +sysjobs(argc, argv) +int argc; +char *argv[]; +{ + register char *cmd = *argv; + register struct job *jp; + register propts, c; + extern int opterr, i; + int savoptind = optind; + int loptind = -1; + int savopterr = opterr; + int savsp = _sp; + char *savoptarg = optarg; + optind = 1; + opterr = 0; + _sp = 1; + propts = 0; + + if ((flags & jcflg) == 0) + failed(cmd, nojc); + + while ((c = getopt(argc, argv, "lpx")) != -1) { + if (propts) { + failure(usage, jobsuse); + goto err; + } + switch (c) { + case 'x': + propts = -1; + break; + case 'p': + propts = PR_PGID; + break; + case 'l': + propts = PR_LONG; + break; + case '?': + failure(usage, jobsuse); + goto err; + } + } + + loptind = optind; +err: + optind = savoptind; + optarg = savoptarg; + opterr = savopterr; + _sp = savsp; + if (loptind == -1) + return; + + if (propts == -1) { + register unsigned char *bp; + register char *cp; + unsigned char *savebp; + for (savebp = bp = locstak(); loptind < argc; loptind++) { + cp = argv[loptind]; + if (*cp == '%') { + jp = str2job(cmd, cp, 1); + itos(jp->j_pid); + cp = (char *)numbuf; + } + while (*cp) { + if (bp >= brkend) + growstak(bp); + *bp++ = *cp++; + } + if (bp >= brkend) + growstak(bp); + *bp++ = SPACE; + } + endstak(bp); + execexp(savebp, 0); + return; + } + + collectjobs(WNOHANG); + + if (propts == 0) + propts = PR_DFL; + + if (loptind == argc) { + for (jp = joblst; jp; jp = jp->j_nxtp) { + if (jp->j_jid) + printjob(jp, propts); + } + } else do + printjob(str2job(cmd, argv[loptind++], 1), propts); + while (loptind < argc); + +} + +/* + * the builtin "fg" and "bg" commands + */ + +sysfgbg(argc, argv) +int argc; +char *argv[]; +{ + register char *cmd = *argv; + register fg; + + if ((flags & jcflg) == 0) + failed(cmd, nojc); + + fg = eq("fg", cmd); + + if (*++argv == 0) { + struct job *jp; + for (jp = jobcur; ; jp = jp->j_curp) { + if (jp == 0) + failed(cmd, nocurjob); + if (jp->j_jid) + break; + } + restartjob(jp, fg); + } + + else do + restartjob(str2job(cmd, *argv, 1), fg); + while (*++argv); + +} + +/* + * the builtin "wait" commands + */ + +void +syswait(argc, argv) +int argc; +char *argv[]; +{ + register char *cmd = *argv; + register struct job *jp; + int stat; + int wflags; + + if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) + wflags = WUNTRACED; + else + wflags = 0; + + if (argc == 1) + collectjobs(0); + else while (--argc) { + if ((jp = str2job(cmd, *++argv, 0)) == 0) + continue; + if (!(jp->j_flag & J_RUNNING)) + continue; + if (waitpid(jp->j_pid, &stat, wflags) <= 0) + break; + (void) statjob(jp, stat, 0, 1); + } +} + +static +sigv(cmd, sig, args) + char *cmd; + int sig; + char *args; +{ + int pgrp = 0; + int stopme = 0; + pid_t id; + + if (*args == '%') { + register struct job *jp; + jp = str2job(cmd, args, 1); + id = jp->j_pgid; + pgrp++; + } else { + if (*args == '-') { + pgrp++; + args++; + } + id = 0; + do { + if (*args < '0' || *args > '9') { + failure(cmd, badid); + return; + } + id = (id * 10) + (*args - '0'); + } while (*++args); + if (id == 0) { + id = mypgid; + pgrp++; + } + } + + if (sig == SIGSTOP) { + if (id == mysid || id == mypid && mypgid == mysid) { + failure(cmd, loginsh); + return; + } + if (id == mypgid && mypgid != svpgid) { + (void) settgid(svtgid, mypgid); + setpgid(0, svpgid); + stopme++; + } + } + + if (pgrp) + id = -id; + + if (kill(id, sig) < 0) { + + switch (errno) { + case EPERM: + failure(cmd, eacces); + break; + + case EINVAL: + failure(cmd, badsig); + break; + + default: + if (pgrp) + failure(cmd, nosuchpgid); + else + failure(cmd, nosuchpid); + break; + } + + } else if (sig == SIGTERM && pgrp) + (void) kill(id, SIGCONT); + + if (stopme) { + setpgid(0, mypgid); + (void) settgid(mypgid, svpgid); + } + +} + +sysstop(argc, argv) +int argc; +char *argv[]; +{ + char *cmd = *argv; + if (argc <= 1) + failed(usage, stopuse); + while (*++argv) + sigv(cmd, SIGSTOP, *argv); +} + +syskill(argc, argv) +int argc; +char *argv[]; +{ + char *cmd = *argv; + int sig = SIGTERM; + + if (argc == 1) { + failure(usage, killuse); + return; + } + + if (argv[1][0] == '-') { + + if (argc == 2) { + + register i; + register cnt = 0; + register char sep = 0; + char buf[12]; + + if (!eq(argv[1], "-l")) { + failure(usage, killuse); + return; + } + + for (i = 1; i < MAXTRAP; i++) { + if (sig2str(i, buf) < 0) + continue; + if (sep) + prc_buff(sep); + prs_buff(buf); + if ((flags & ttyflg) && (++cnt % 10)) + sep = TAB; + else + sep = NL; + } + prc_buff(NL); + return; + } + + if (str2sig(&argv[1][1], &sig)) { + failure(cmd, badsig); + return; + } + argv++; + } + + while (*++argv) + sigv(cmd, sig, *argv); + +} + +syssusp(argc, argv) +int argc; +char *argv[]; +{ + if (argc != 1) + failed(argv[0], badopt); + sigv(argv[0], SIGSTOP, "0"); +} diff --git a/usr/src/cmd/sh/mac.h b/usr/src/cmd/sh/mac.h new file mode 100644 index 0000000000..3985bfae26 --- /dev/null +++ b/usr/src/cmd/sh/mac.h @@ -0,0 +1,51 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */ +/* + * UNIX shell + */ + +#define TRUE (-1) +#define FALSE 0 +#define LOBYTE 0377 +#define QUOTE 0200 + +#define EOF 0 +#define NL '\n' +#define SPACE ' ' +#define LQ '`' +#define RQ '\'' +#define MINUS '-' +#define COLON ':' +#define TAB '\t' + + +#define MAX(a,b) ((a)>(b)?(a):(b)) + +#define blank() prc(SPACE) +#define tab() prc(TAB) +#define newline() prc(NL) + diff --git a/usr/src/cmd/sh/macro.c b/usr/src/cmd/sh/macro.c new file mode 100644 index 0000000000..4b495a108e --- /dev/null +++ b/usr/src/cmd/sh/macro.c @@ -0,0 +1,627 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1995 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * UNIX shell + */ + +#include "defs.h" +#include "sym.h" +#include <wait.h> + +static unsigned char quote; /* used locally */ +static unsigned char quoted; /* used locally */ +static int getch(); + +static void +copyto(endch, trimflag) +int trimflag; /* flag to check if argument will be trimmed */ +register unsigned char endch; +{ + register unsigned int c; + register unsigned int d; + register unsigned char *pc; + + while ((c = getch(endch, trimflag)) != endch && c) + if (quote) { + if(c == '\\') { /* don't interpret next character */ + if (staktop >= brkend) + growstak(staktop); + pushstak(c); + d = readwc(); + if(!escchar(d)) { /* both \ and following + character are quoted if next + character is not $, `, ", or \*/ + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + pc = readw(d); + /* push entire multibyte char */ + while(*pc) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc++); + } + } else { + pc = readw(d); + /* d might be NULL */ + /* Evenif d is NULL, we have to save it */ + if (*pc) { + while (*pc) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc++); + } + } else { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc); + } + } + } else { /* push escapes onto stack to quote characters */ + pc = readw(c); + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + while(*pc) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc++); + } + } + } else if(c == '\\') { + c = readwc(); /* get character to be escaped */ + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + pc = readw(c); + /* c might be NULL */ + /* Evenif c is NULL, we have to save it */ + if (*pc) { + while (*pc) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc++); + } + } else { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc); + } + } else { + pc = readw(c); + while (*pc) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc++); + } + } + if (staktop >= brkend) + growstak(staktop); + zerostak(); + if (c != endch) + error(badsub); +} + +static +skipto(endch) +register unsigned char endch; +{ + /* + * skip chars up to } + */ + register unsigned int c; + + while ((c = readwc()) && c != endch) + { + switch (c) + { + case SQUOTE: + skipto(SQUOTE); + break; + + case DQUOTE: + skipto(DQUOTE); + break; + + case DOLLAR: + if (readwc() == BRACE) + skipto('}'); + } + } + if (c != endch) + error(badsub); +} + +static +int getch(endch, trimflag) +unsigned char endch; +int trimflag; /* flag to check if an argument is going to be trimmed, here document + output is never trimmed + */ +{ + register unsigned int d; + int atflag; /* flag to check if $@ has already been seen within double + quotes */ +retry: + d = readwc(); + if (!subchar(d)) + return(d); + + if (d == DOLLAR) + { + unsigned int c; + + if ((c = readwc(), dolchar(c))) + { + struct namnod *n = (struct namnod *)NIL; + int dolg = 0; + BOOL bra; + BOOL nulflg; + register unsigned char *argp, *v; + unsigned char idb[2]; + unsigned char *id = idb; + + if (bra = (c == BRACE)) + c = readwc(); + if (letter(c)) + { + argp = (unsigned char *)relstak(); + while (alphanum(c)) + { + if (staktop >= brkend) + growstak(staktop); + pushstak(c); + c = readwc(); + } + if (staktop >= brkend) + growstak(staktop); + zerostak(); + n = lookup(absstak(argp)); + setstak(argp); + if (n->namflg & N_FUNCTN) + error(badsub); + v = n->namval; + id = (unsigned char *)n->namid; + peekc = c | MARK; + } + else if (digchar(c)) + { + *id = c; + idb[1] = 0; + if (astchar(c)) + { + if(c == '@' && !atflag && quote) { + quoted--; + atflag = 1; + } + dolg = 1; + c = '1'; + } + c -= '0'; + v = ((c == 0) ? cmdadr : ((int)c <= dolc) ? dolv[c] : (unsigned char *)(dolg = 0)); + } + else if (c == '$') + v = pidadr; + else if (c == '!') + v = pcsadr; + else if (c == '#') + { + itos(dolc); + v = numbuf; + } + else if (c == '?') + { + itos(retval); + v = numbuf; + } + else if (c == '-') + v = flagadr; + else if (bra) + error(badsub); + else + goto retry; + c = readwc(); + if (c == ':' && bra) /* null and unset fix */ + { + nulflg = 1; + c = readwc(); + } + else + nulflg = 0; + if (!defchar(c) && bra) + error(badsub); + argp = 0; + if (bra) + { + if (c != '}') + { + argp = (unsigned char *)relstak(); + if ((v == 0 || (nulflg && *v == 0)) ^ (setchar(c))) + copyto('}', trimflag); + else + skipto('}'); + argp = absstak(argp); + } + } + else + { + peekc = c | MARK; + c = 0; + } + if (v && (!nulflg || *v)) + { + + if (c != '+') + { + for (;;) + { + if (*v == 0 && quote) { + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + if (staktop >= brkend) + growstak(staktop); + pushstak('\0'); + } else { + while (c = *v) { + wchar_t wc; + register int length; + if ((length = mbtowc(&wc, (char *)v, MB_LEN_MAX)) <= 0) + length = 1; + + if(quote || (c == '\\' && trimflag)) { + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + } + while(length-- > 0) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*v++); + } + } + } + + if (dolg == 0 || (++dolg > dolc)) + break; + else /* $* and $@ expansion */ + { + v = dolv[dolg]; + if(*id == '*' && quote) { +/* push quoted space so that " $* " will not be broken into separate arguments */ + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + } + if (staktop >= brkend) + growstak(staktop); + pushstak(' '); + } + } + } + } + else if (argp) + { + if (c == '?') { + if(trimflag) + trim(argp); + failed(id, *argp ? argp : (unsigned char *)badparam); + } + else if (c == '=') + { + if (n) + { + int strlngth = staktop - stakbot; + unsigned char *savptr = fixstak(); + unsigned char *newargp; + /* + * copy word onto stack, trim it, and then + * do assignment + */ + usestak(); + while(c = *argp) { + wchar_t wc; + register int len; + + if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0) + len = 1; + + if(c == '\\' && trimflag) { + argp++; + if (*argp == 0) { + argp++; + continue; + } + if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0) + len = 1; + } + while(len-- > 0) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*argp++); + } + } + newargp = fixstak(); + assign(n, newargp); + tdystak(savptr); + memcpy(stakbot, savptr, strlngth); + staktop = stakbot + strlngth; + } + else + error(badsub); + } + } + else if (flags & setflg) + failed(id, unset); + goto retry; + } + else + peekc = c | MARK; + } + else if (d == endch) + return(d); + else if (d == SQUOTE) + { + comsubst(trimflag); + goto retry; + } + else if (d == DQUOTE && trimflag) + { + if(!quote) { + atflag = 0; + quoted++; + } + quote ^= QUOTE; + goto retry; + } + return(d); +} + +unsigned char * +macro(as) +unsigned char *as; +{ + /* + * Strip "" and do $ substitution + * Leaves result on top of stack + */ + register BOOL savqu = quoted; + register unsigned char savq = quote; + struct filehdr fb; + + push(&fb); + estabf(as); + usestak(); + quote = 0; + quoted = 0; + copyto(0, 1); + pop(); + if (quoted && (stakbot == staktop)) { + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + if (staktop >= brkend) + growstak(staktop); + pushstak('\0'); +/* + * above is the fix for *'.c' bug + */ + } + quote = savq; + quoted = savqu; + return(fixstak()); +} +/* Save file descriptor for command substitution */ +int savpipe = -1; + +comsubst(trimflag) +int trimflag; /* used to determine if argument will later be trimmed */ +{ + /* + * command substn + */ + struct fileblk cb; + register unsigned int d; + int strlngth = staktop - stakbot; + register unsigned char *oldstaktop; + unsigned char *savptr = fixstak(); + unsigned char *pc; + + usestak(); + while ((d = readwc()) != SQUOTE && d) { + if(d == '\\') { + d = readwc(); + if(!escchar(d) || (d == '"' && !quote)) { + /* trim quotes for `, \, or " if command substitution is within + double quotes */ + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + } + } + pc = readw(d); + /* d might be NULL */ + if (*pc) { + while (*pc) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc++); + } + } else { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc); + } + } + { + register unsigned char *argc; + + argc = fixstak(); + push(&cb); + estabf(argc); /* read from string */ + } + { + register struct trenod *t; + int pv[2]; + + /* + * this is done like this so that the pipe + * is open only when needed + */ + t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG )); + chkpipe(pv); + savpipe = pv[OTPIPE]; + initf(pv[INPIPE]); /* read from pipe */ + execute(t, XEC_NOSTOP, (int)(flags & errflg), 0, pv); + close(pv[OTPIPE]); + savpipe = -1; + } + tdystak(savptr); + memcpy(stakbot, savptr, strlngth); + oldstaktop = staktop = stakbot + strlngth; + while (d = readwc()) { + if(quote || (d == '\\' && trimflag)) { + register unsigned char *rest; + /* quote output from command subst. if within double + quotes or backslash part of output */ + rest = readw(d); + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + while(d = *rest++) { + /* Pick up all of multibyte character */ + if (staktop >= brkend) + growstak(staktop); + pushstak(d); + } + } + else { + pc = readw(d); + while (*pc) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc++); + } + } + } + { + extern pid_t parent; + int stat; + register rc; + int ret = 0; + + while ((ret = waitpid(parent,&stat,0)) != parent) { + /* break out if waitpid(2) has failed */ + if (ret == -1) + break; + } + if (WIFEXITED(stat)) + rc = WEXITSTATUS(stat); + else + rc = (WTERMSIG(stat) | SIGFLG); + if (rc && (flags & errflg)) + exitsh(rc); + exitval = rc; + flags |= eflag; + exitset(); + } + while (oldstaktop != staktop) + { /* strip off trailing newlines from command substitution only */ + if ((*--staktop) != NL) + { + ++staktop; + break; + } else if(quote) + staktop--; /* skip past backslashes if quoting */ + } + pop(); +} + +#define CPYSIZ 512 + +subst(in, ot) +int in, ot; +{ + register unsigned int c; + struct fileblk fb; + register int count = CPYSIZ; + unsigned char *pc; + + push(&fb); + initf(in); + /* + * DQUOTE used to stop it from quoting + */ + while (c = (getch(DQUOTE, 0))) /* read characters from here document + and interpret them */ + { + if(c == '\\') { + c = readwc(); /* check if character in here document is + escaped */ + if(!escchar(c) || c == '"') { + if (staktop >= brkend) + growstak(staktop); + pushstak('\\'); + } + } + pc = readw(c); + /* c might be NULL */ + if (*pc) { + while (*pc) { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc++); + } + } else { + if (staktop >= brkend) + growstak(staktop); + pushstak(*pc); + } + if (--count == 0) + { + flush(ot); + count = CPYSIZ; + } + } + flush(ot); + pop(); +} + +flush(ot) +{ + write(ot, stakbot, staktop - stakbot); + if (flags & execpr) + write(output, stakbot, staktop - stakbot); + staktop = stakbot; +} diff --git a/usr/src/cmd/sh/main.c b/usr/src/cmd/sh/main.c new file mode 100644 index 0000000000..bf896289b3 --- /dev/null +++ b/usr/src/cmd/sh/main.c @@ -0,0 +1,647 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * UNIX shell + */ + +#include "defs.h" +#include "sym.h" +#include "timeout.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include "dup.h" +#include "sh_policy.h" + +#ifdef RES +#include <sgtty.h> +#endif + +pid_t mypid, mypgid, mysid; + +static BOOL beenhere = FALSE; +unsigned char tmpout[20] = "/tmp/sh-"; +struct fileblk stdfile; +struct fileblk *standin = &stdfile; +int mailchk = 0; + +static unsigned char *mailp; +static long *mod_time = 0; +static BOOL login_shell = FALSE; + +#if vax +char **execargs = (char **)(0x7ffffffc); +#endif + +#if pdp11 +char **execargs = (char **)(-2); +#endif + + +static int exfile(); +extern unsigned char *simple(); + + +main(c, v, e) +int c; +char *v[]; +char *e[]; +{ + register int rflag = ttyflg; + int rsflag = 1; /* local restricted flag */ + register unsigned char *flagc = flagadr; + struct namnod *n; + + mypid = getpid(); + mypgid = getpgid(mypid); + mysid = getsid(mypid); + + /* + * Do locale processing only if /usr is mounted. + */ + localedir_exists = (access(localedir, F_OK) == 0); + + /* + * initialize storage allocation + */ + + if (stakbot == 0) { + addblok((unsigned)0); + } + + /* + * If the first character of the last path element of v[0] is "-" + * (ex. -sh, or /bin/-sh), this is a login shell + */ + if (*simple(v[0]) == '-') { + signal(SIGXCPU, SIG_DFL); + signal(SIGXFSZ, SIG_DFL); + + /* + * As the previous comment states, this is a login shell. + * Therefore, we set the login_shell flag to explicitly + * indicate this condition. + */ + login_shell = TRUE; + } + + stdsigs(); + + /* + * set names from userenv + */ + + setup_env(); + + /* + * LC_MESSAGES is set here so that early error messages will + * come out in the right style. + * Note that LC_CTYPE is done later on and is *not* + * taken from the previous environ + */ + + /* + * Do locale processing only if /usr is mounted. + */ + if (localedir_exists) + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ +#endif + (void) textdomain(TEXT_DOMAIN); + + /* + * This is a profile shell if the simple name of argv[0] is + * pfsh or -pfsh + */ + if (c > 0 && (eq("pfsh", simple(*v)) || eq("-pfsh", simple(*v)))) { + flags |= pfshflg; + secpolicy_init(); + } + + /* + * 'rsflag' is zero if SHELL variable is + * set in environment and + * the simple file part of the value. + * is rsh + */ + if (n = findnam("SHELL")) + { + if (eq("rsh", simple(n->namval))) + rsflag = 0; + } + + /* + * a shell is also restricted if the simple name of argv(0) is + * rsh or -rsh in its simple name + */ + +#ifndef RES + + if (c > 0 && (eq("rsh", simple(*v)) || eq("-rsh", simple(*v)))) + rflag = 0; + +#endif + + if (eq("jsh", simple(*v)) || eq("-jsh", simple(*v))) + flags |= monitorflg; + + hcreate(); + set_dotpath(); + + + /* + * look for options + * dolc is $# + */ + dolc = options(c, v); + + if (dolc < 2) + { + flags |= stdflg; + { + + while (*flagc) + flagc++; + *flagc++ = STDFLG; + *flagc = 0; + } + } + if ((flags & stdflg) == 0) + dolc--; + + if ((flags & privflg) == 0) { + register uid_t euid; + register gid_t egid; + register uid_t ruid; + register gid_t rgid; + + /* + * Determine all of the user's id #'s for this process and + * then decide if this shell is being entered as a result + * of a fork/exec. + * If the effective uid/gid do NOT match and the euid/egid + * is < 100 and the egid is NOT 1, reset the uid and gid to + * the user originally calling this process. + */ + euid = geteuid(); + ruid = getuid(); + egid = getegid(); + rgid = getgid(); + if ((euid != ruid) && (euid < 100)) + setuid(ruid); /* reset the uid to the orig user */ + if ((egid != rgid) && ((egid < 100) && (egid != 1))) + setgid(rgid); /* reset the gid to the orig user */ + } + + dolv = (unsigned char **)v + c - dolc; + dolc--; + + /* + * return here for shell file execution + * but not for parenthesis subshells + */ + if (setjmp(subshell)) { + freejobs(); + flags |= subsh; + } + + /* + * number of positional parameters + */ + replace(&cmdadr, dolv[0]); /* cmdadr is $0 */ + + /* + * set pidname '$$' + */ + assnum(&pidadr, (long)mypid); + + /* + * set up temp file names + */ + settmp(); + + /* + * default internal field separators + * Do not allow importing of IFS from parent shell. + * setup_env() may have set anything from parent shell to IFS. + * Always set the default ifs to IFS. + */ + assign(&ifsnod, sptbnl); + + dfault(&mchknod, MAILCHECK); + mailchk = stoi(mchknod.namval); + + /* initialize OPTIND for getopt */ + + n = lookup("OPTIND"); + assign(n, "1"); + /* + * make sure that option parsing starts + * at first character + */ + _sp = 1; + + /* initialize multibyte information */ + setwidth(); + + if ((beenhere++) == FALSE) /* ? profile */ + { + if ((login_shell == TRUE) && (flags & privflg) == 0) { + + /* system profile */ + +#ifndef RES + + if ((input = pathopen(nullstr, sysprofile)) >= 0) + exfile(rflag); /* file exists */ + +#endif + /* user profile */ + + if ((input = pathopen(homenod.namval, profile)) >= 0) + { + exfile(rflag); + flags &= ~ttyflg; + } + } + if (rsflag == 0 || rflag == 0) { + if ((flags & rshflg) == 0) { + while (*flagc) + flagc++; + *flagc++ = 'r'; + *flagc = '\0'; + } + flags |= rshflg; + } + + /* + * open input file if specified + */ + if (comdiv) + { + estabf(comdiv); + input = -1; + } + else + { + if (flags & stdflg) { + input = 0; + } else { + /* + * If the command file specified by 'cmdadr' + * doesn't exist, chkopen() will fail calling + * exitsh(). If this is a login shell and + * the $HOME/.profile file does not exist, the + * above statement "flags &= ~ttyflg" does not + * get executed and this makes exitsh() call + * longjmp() instead of exiting. longjmp() will + * return to the location specified by the last + * active jmpbuffer, which is the one set up in + * the function exfile() called after the system + * profile file is executed (see lines above). + * This would cause an infinite loop, because + * chkopen() will continue to fail and exitsh() + * to call longjmp(). To make exitsh() exit instead + * of calling longjmp(), we then set the flag forcexit + * at this stage. + */ + + flags |= forcexit; + input = chkopen(cmdadr, 0); + flags &= ~forcexit; + } + +#ifdef ACCT + if (input != 0) + preacct(cmdadr); +#endif + comdiv--; + } + } +#ifdef pdp11 + else + *execargs = (char *)dolv; /* for `ps' cmd */ +#endif + + + exfile(0); + done(0); +} + +static int +exfile(prof) +BOOL prof; +{ + time_t mailtime = 0; /* Must not be a register variable */ + time_t curtime = 0; + + /* + * move input + */ + if (input > 0) + { + Ldup(input, INIO); + input = INIO; + } + + + setmode(prof); + + if (setjmp(errshell) && prof) + { + close(input); + (void) endjobs(0); + return; + } + /* + * error return here + */ + + loopcnt = peekc = peekn = 0; + fndef = 0; + nohash = 0; + iopend = 0; + + if (input >= 0) + initf(input); + /* + * command loop + */ + for (;;) + { + tdystak(0); + stakchk(); /* may reduce sbrk */ + exitset(); + + if ((flags & prompt) && standin->fstak == 0 && !eof) + { + + if (mailp) + { + time(&curtime); + + if ((curtime - mailtime) >= mailchk) + { + chkmail(); + mailtime = curtime; + } + } + + /* necessary to print jobs in a timely manner */ + if (trapnote & TRAPSET) + chktrap(); + + prs(ps1nod.namval); + +#ifdef TIME_OUT + alarm(TIMEOUT); +#endif + + } + + trapnote = 0; + peekc = readwc(); + if (eof) { + if (endjobs(JOB_STOPPED)) + return; + eof = 0; + } + +#ifdef TIME_OUT + alarm(0); +#endif + + { + register struct trenod *t; + t = cmd(NL, MTFLG); + if (t == NULL && flags & ttyflg) + freejobs(); + else + execute(t, 0, eflag); + } + + eof |= (flags & oneflg); + + } +} + +chkpr() +{ + if ((flags & prompt) && standin->fstak == 0) + prs(ps2nod.namval); +} + +settmp() +{ + int i; + i = ltos(mypid); + serial = 0; + tmpname = movstr(numbuf + i, &tmpout[TMPNAM]); +} + +Ldup(fa, fb) +register int fa, fb; +{ +#ifdef RES + + dup(fa | DUPFLG, fb); + close(fa); + ioctl(fb, FIOCLEX, 0); + +#else + + if (fa >= 0) { + if (fa != fb) + { + close(fb); + fcntl(fa, 0, fb); /* normal dup */ + close(fa); + } + fcntl(fb, 2, 1); /* autoclose for fb */ + } + +#endif +} + + +chkmail() +{ + register unsigned char *s = mailp; + register unsigned char *save; + + long *ptr = mod_time; + unsigned char *start; + BOOL flg; + struct stat statb; + + while (*s) { + start = s; + save = 0; + flg = 0; + + while (*s) { + if (*s != COLON) { + if (*s == '%' && save == 0) + save = s; + + s++; + } else { + flg = 1; + *s = 0; + } + } + + if (save) + *save = 0; + + if (*start && stat((const char *)start, &statb) >= 0) { + if (statb.st_size && *ptr && + statb.st_mtime != *ptr) { + if (save) { + prs(save+1); + newline(); + } + else + prs(mailmsg); + } + *ptr = statb.st_mtime; + } else if (*ptr == 0) + *ptr = 1; + + if (save) + *save = '%'; + + if (flg) + *s++ = COLON; + + ptr++; + } +} + + +setmail(mailpath) + unsigned char *mailpath; +{ + register unsigned char *s = mailpath; + register int cnt = 1; + + long *ptr; + + free(mod_time); + if (mailp = mailpath) + { + while (*s) + { + if (*s == COLON) + cnt += 1; + + s++; + } + + ptr = mod_time = (long *)alloc(sizeof (long) * cnt); + + while (cnt) + { + *ptr = 0; + ptr++; + cnt--; + } + } +} + +void +setwidth() +{ + unsigned char *name = lookup("LC_CTYPE")->namval; + if (!name || !*name) + name = lookup("LANG")->namval; + /* + * Do locale processing only if /usr is mounted. + */ + if (localedir_exists) { + if (!name || !*name) + (void) setlocale(LC_CTYPE, "C"); + else + (void) setlocale(LC_CTYPE, (const char *)name); + } +} + +setmode(prof) +{ + /* + * decide whether interactive + */ + + if ((flags & intflg) || + ((flags&oneflg) == 0 && + isatty(output) && + isatty(input))) + + { + dfault(&ps1nod, (geteuid() ? stdprompt : supprompt)); + dfault(&ps2nod, readmsg); + flags |= ttyflg | prompt; + if (mailpnod.namflg != N_DEFAULT) + setmail(mailpnod.namval); + else + setmail(mailnod.namval); + startjobs(); + } + else + { + flags |= prof; + flags &= ~prompt; + } +} + +/* + * A generic call back routine to output error messages from the + * policy backing functions called by pfsh. + * + * msg must contain '\n' if a new line is to be printed. + */ +void +secpolicy_print(int level, const char *msg) +{ + switch (level) { + case SECPOLICY_WARN: + default: + prs(msg); /* prs() does gettext() */ + return; + case SECPOLICY_ERROR: + error(msg); + break; + } +} diff --git a/usr/src/cmd/sh/mode.h b/usr/src/cmd/sh/mode.h new file mode 100644 index 0000000000..43ad7db9a6 --- /dev/null +++ b/usr/src/cmd/sh/mode.h @@ -0,0 +1,253 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8.1.2 */ +/* + * UNIX shell + */ + +#include <unistd.h> + +#ifdef pdp11 +typedef char BOOL; +#else +typedef short BOOL; +#endif + +#define BYTESPERWORD (sizeof (char *)) +#define NIL ((char*)0) + + +/* the following nonsense is required + * because casts turn an Lvalue + * into an Rvalue so two cheats + * are necessary, one for each context. + */ +#define Rcheat(a) ((int)(a)) + + +/* address puns for storage allocation */ +typedef union +{ + struct forknod *_forkptr; + struct comnod *_comptr; + struct fndnod *_fndptr; + struct parnod *_parptr; + struct ifnod *_ifptr; + struct whnod *_whptr; + struct fornod *_forptr; + struct lstnod *_lstptr; + struct blk *_blkptr; + struct namnod *_namptr; + char *_bytptr; +} address; + + +/* heap storage */ +struct blk +{ + struct blk *word; +}; + +/* + * largefile converson hack note. + * the shell uses the *fnxt and *fend pointers when + * parsing a script. However, it was also using the + * difference between them when doing lseeks. Because + * that doesn't work in the largefile world, I have + * added a parallel set of offset counters that need to + * be updated whenever the "buffer" offsets the shell + * uses get changed. Most of this code is in word.c. + * If you change it, have fun... + */ + +#define BUFFERSIZE 128 +struct fileblk +{ + int fdes; + unsigned flin; + BOOL feof; + unsigned char fsiz; + unsigned char *fnxt; + unsigned char *fend; + off_t nxtoff; /* file offset */ + off_t endoff; /* file offset */ + unsigned char **feval; + struct fileblk *fstak; + unsigned char fbuf[BUFFERSIZE]; +}; + +struct tempblk +{ + int fdes; + struct tempblk *fstak; +}; + + +/* for files not used with file descriptors */ +struct filehdr +{ + int fdes; + unsigned flin; + BOOL feof; + unsigned char fsiz; + unsigned char *fnxt; + unsigned char *fend; + off_t nxtoff; /* file offset */ + off_t endoff; /* file offset */ + unsigned char **feval; + struct fileblk *fstak; + unsigned char _fbuf[1]; +}; + +struct sysnod +{ + char *sysnam; + int sysval; +}; + +/* this node is a proforma for those that follow */ +struct trenod +{ + int tretyp; + struct ionod *treio; +}; + +/* dummy for access only */ +struct argnod +{ + struct argnod *argnxt; + unsigned char argval[1]; +}; + +struct dolnod +{ + struct dolnod *dolnxt; + int doluse; + unsigned char **dolarg; +}; + +struct forknod +{ + int forktyp; + struct ionod *forkio; + struct trenod *forktre; +}; + +struct comnod +{ + int comtyp; + struct ionod *comio; + struct argnod *comarg; + struct argnod *comset; +}; + +struct fndnod +{ + int fndtyp; + unsigned char *fndnam; + struct trenod *fndval; +}; + +struct ifnod +{ + int iftyp; + struct trenod *iftre; + struct trenod *thtre; + struct trenod *eltre; +}; + +struct whnod +{ + int whtyp; + struct trenod *whtre; + struct trenod *dotre; +}; + +struct fornod +{ + int fortyp; + struct trenod *fortre; + unsigned char *fornam; + struct comnod *forlst; +}; + +struct swnod +{ + int swtyp; + unsigned char *swarg; + struct regnod *swlst; +}; + +struct regnod +{ + struct argnod *regptr; + struct trenod *regcom; + struct regnod *regnxt; +}; + +struct parnod +{ + int partyp; + struct trenod *partre; +}; + +struct lstnod +{ + int lsttyp; + struct trenod *lstlef; + struct trenod *lstrit; +}; + +struct ionod +{ + int iofile; + char *ioname; + char *iolink; + struct ionod *ionxt; + struct ionod *iolst; +}; + +struct fdsave +{ + int org_fd; + int dup_fd; +}; + + +#define fndptr(x) ((struct fndnod *)x) +#define comptr(x) ((struct comnod *)x) +#define forkptr(x) ((struct forknod *)x) +#define parptr(x) ((struct parnod *)x) +#define lstptr(x) ((struct lstnod *)x) +#define forptr(x) ((struct fornod *)x) +#define whptr(x) ((struct whnod *)x) +#define ifptr(x) ((struct ifnod *)x) +#define swptr(x) ((struct swnod *)x) diff --git a/usr/src/cmd/sh/msg.c b/usr/src/cmd/sh/msg.c new file mode 100644 index 0000000000..8b4bb57dad --- /dev/null +++ b/usr/src/cmd/sh/msg.c @@ -0,0 +1,266 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * UNIX shell + */ + + +#include "defs.h" +#include "sym.h" + +/* + * error messages + */ +#ifndef __STDC__ +#define const +#endif + +const char badopt[] = "bad option(s)"; +const char mailmsg[] = "you have mail\n"; +const char nospace[] = "no space"; +const char nostack[] = "no stack space"; +const char synmsg[] = "syntax error"; + +const char badnum[] = "bad number"; +const char badsig[] = "bad signal"; +const char badid[] = "invalid id"; +const char badparam[] = "parameter null or not set"; +const char unset[] = "parameter not set"; +const char badsub[] = "bad substitution"; +const char badcreate[] = "cannot create"; +const char nofork[] = "fork failed - too many processes"; +const char noswap[] = "cannot fork: no swap space"; +const char restricted[] = "restricted"; +const char piperr[] = "cannot make pipe"; +const char badopen[] = "cannot open"; +const char coredump[] = " - core dumped"; +const char arglist[] = "arg list too long"; +const char txtbsy[] = "text busy"; +const char toobig[] = "too big"; +const char badexec[] = "cannot execute"; +const char notfound[] = "not found"; +const char badfile[] = "bad file number"; +const char badshift[] = "cannot shift"; +const char baddir[] = "bad directory"; +const char badtrap[] = "bad trap"; +const char wtfailed[] = "is read only"; +const char notid[] = "is not an identifier"; +const char badulimit[] = "bad ulimit"; +const char badresource[] = "no such resource"; +const char badreturn[] = "cannot return when not in function"; +const char badexport[] = "cannot export functions"; +const char badunset[] = "cannot unset"; +const char nohome[] = "no home directory"; +const char badperm[] = "execute permission denied"; +const char longpwd[] = "sh error: pwd too long"; +const char mssgargn[] = "missing arguments"; +const char libacc[] = "can't access a needed shared library"; +const char libbad[] = "accessing a corrupted shared library"; +const char libscn[] = ".lib section in a.out corrupted"; +const char libmax[] = "attempting to link in too many libs"; +const char emultihop[] = "Multihop attempted"; +const char nulldir[] = "null directory"; +const char enotdir[] = "not a directory"; +const char enoent[] = "does not exist"; +const char eacces[] = "permission denied"; +const char enolink[] = "remote link inactive"; +const char badscale[] = "bad scaling"; +const char exited[] = "Done"; +const char running[] = "Running"; +const char ambiguous[] = "ambiguous"; +const char usage[] = "usage"; +const char nojc[] = "no job control"; +const char stopuse[] = "stop id ..."; +const char ulimuse[] = "ulimit [ -HSacdfnstv ] [ limit ]"; +const char killuse[] = "kill [ [ -sig ] id ... | -l ]"; +const char jobsuse[] = "jobs [ [ -l | -p ] [ id ... ] | -x cmd ]"; +const char nosuchjob[] = "no such job"; +const char nosuchpid[] = "no such process"; +const char nosuchpgid[] = "no such process group"; +const char nocurjob[] = "no current job"; +const char jobsstopped[] = "there are stopped jobs"; +const char jobsrunning[] = "there are running jobs"; +const char loginsh[] = "cannot stop login shell"; + +/* + * messages for 'builtin' functions + */ +const char btest[] = "test"; +const char badop[] = "unknown operator "; +/* + * built in names + */ +const char pathname[] = "PATH"; +const char cdpname[] = "CDPATH"; +const char homename[] = "HOME"; +const char mailname[] = "MAIL"; +const char ifsname[] = "IFS"; +const char ps1name[] = "PS1"; +const char ps2name[] = "PS2"; +const char mchkname[] = "MAILCHECK"; +const char acctname[] = "SHACCT"; +const char mailpname[] = "MAILPATH"; + +/* + * string constants + */ +const char nullstr[] = ""; +const char sptbnl[] = " \t\n"; +const char defpath[] = "/usr/bin:"; +const char colon[] = ": "; +const char minus[] = "-"; +const char endoffile[] = "end of file"; +const char unexpected[] = " unexpected"; +const char atline[] = " at line "; +const char devnull[] = "/dev/null"; +const char execpmsg[] = "+ "; +const char readmsg[] = "> "; +const char stdprompt[] = "$ "; +const char supprompt[] = "# "; +const char profile[] = ".profile"; +const char sysprofile[] = "/etc/profile"; + +/* + * locale testing + */ +const char localedir[] = "/usr/lib/locale"; +int localedir_exists; + +/* + * tables + */ + +const struct sysnod reserved[] = +{ + { "case", CASYM }, + { "do", DOSYM }, + { "done", ODSYM }, + { "elif", EFSYM }, + { "else", ELSYM }, + { "esac", ESSYM }, + { "fi", FISYM }, + { "for", FORSYM }, + { "if", IFSYM }, + { "in", INSYM }, + { "then", THSYM }, + { "until", UNSYM }, + { "while", WHSYM }, + { "{", BRSYM }, + { "}", KTSYM } +}; + +const int no_reserved = sizeof(reserved)/sizeof(struct sysnod); + +const char *sysmsg[] = +{ + 0, + "Hangup", + 0, /* Interrupt */ + "Quit", + "Illegal instruction", + "Trace/BPT trap", + "abort", + "EMT trap", + "Floating exception", + "Killed", + "Bus error", + "Memory fault", + "Bad system call", + 0, /* Broken pipe */ + "Alarm call", + "Terminated", + "Signal 16", + "Signal 17", + "Child death", + "Power Fail" +}; + +const char export[] = "export"; +const char duperr[] = "cannot dup"; +const char readonly[] = "readonly"; + + +const struct sysnod commands[] = +{ + { ".", SYSDOT }, + { ":", SYSNULL }, + +#ifndef RES + { "[", SYSTST }, +#endif + { "bg", SYSFGBG }, + { "break", SYSBREAK }, + { "cd", SYSCD }, + { "chdir", SYSCD }, + { "continue", SYSCONT }, + { "echo", SYSECHO }, + { "eval", SYSEVAL }, + { "exec", SYSEXEC }, + { "exit", SYSEXIT }, + { "export", SYSXPORT }, + { "fg", SYSFGBG }, + { "getopts", SYSGETOPT }, + { "hash", SYSHASH }, + { "jobs", SYSJOBS }, + { "kill", SYSKILL }, +#ifdef RES + { "login", SYSLOGIN }, + { "newgrp", SYSLOGIN }, +#else + { "newgrp", SYSNEWGRP }, +#endif + + { "pwd", SYSPWD }, + { "read", SYSREAD }, + { "readonly", SYSRDONLY }, + { "return", SYSRETURN }, + { "set", SYSSET }, + { "shift", SYSSHFT }, + { "stop", SYSSTOP }, + { "suspend", SYSSUSP}, + { "test", SYSTST }, + { "times", SYSTIMES }, + { "trap", SYSTRAP }, + { "type", SYSTYPE }, + + +#ifndef RES + { "ulimit", SYSULIMIT }, + { "umask", SYSUMASK }, +#endif + + { "unset", SYSUNS }, + { "wait", SYSWAIT } +}; + +const int no_commands = sizeof(commands)/sizeof(struct sysnod); + diff --git a/usr/src/cmd/sh/name.c b/usr/src/cmd/sh/name.c new file mode 100644 index 0000000000..c76b80f48e --- /dev/null +++ b/usr/src/cmd/sh/name.c @@ -0,0 +1,892 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * UNIX shell + */ + +#include "defs.h" +#include <stropts.h> + +extern BOOL chkid(); +extern unsigned char *simple(); +extern int mailchk; +static void namwalk(); + +static void set_builtins_path(); +static int patheq(); +static void dolocale(); + +struct namnod ps2nod = +{ + (struct namnod *)NIL, + &acctnod, + (unsigned char *)ps2name +}; +struct namnod cdpnod = +{ + (struct namnod *)NIL, + (struct namnod *)NIL, + (unsigned char *)cdpname +}; +struct namnod pathnod = +{ + &mailpnod, + (struct namnod *)NIL, + (unsigned char *)pathname +}; +struct namnod ifsnod = +{ + &homenod, + &mailnod, + (unsigned char *)ifsname +}; +struct namnod ps1nod = +{ + &pathnod, + &ps2nod, + (unsigned char *)ps1name +}; +struct namnod homenod = +{ + &cdpnod, + (struct namnod *)NIL, + (unsigned char *)homename +}; +struct namnod mailnod = +{ + (struct namnod *)NIL, + (struct namnod *)NIL, + (unsigned char *)mailname +}; +struct namnod mchknod = +{ + &ifsnod, + &ps1nod, + (unsigned char *)mchkname +}; +struct namnod acctnod = +{ + (struct namnod *)NIL, + (struct namnod *)NIL, + (unsigned char *)acctname +}; +struct namnod mailpnod = +{ + (struct namnod *)NIL, + (struct namnod *)NIL, + (unsigned char *)mailpname +}; + + +struct namnod *namep = &mchknod; + +/* ======== variable and string handling ======== */ + +syslook(w, syswds, n) + register unsigned char *w; + register struct sysnod syswds[]; + int n; +{ + int low; + int high; + int mid; + register int cond; + + if (w == 0 || *w == 0) + return(0); + + low = 0; + high = n - 1; + + while (low <= high) + { + mid = (low + high) / 2; + + if ((cond = cf(w, syswds[mid].sysnam)) < 0) + high = mid - 1; + else if (cond > 0) + low = mid + 1; + else + return(syswds[mid].sysval); + } + return(0); +} + +setlist(arg, xp) +register struct argnod *arg; +int xp; +{ + if (flags & exportflg) + xp |= N_EXPORT; + + while (arg) + { + register unsigned char *s = mactrim(arg->argval); + setname(s, xp); + arg = arg->argnxt; + if (flags & execpr) + { + prs(s); + if (arg) + blank(); + else + newline(); + } + } +} + + +setname(argi, xp) /* does parameter assignments */ +unsigned char *argi; +int xp; +{ + register unsigned char *argscan = argi; + register struct namnod *n; + + if (letter(*argscan)) + { + while (alphanum(*argscan)) + argscan++; + + if (*argscan == '=') + { + *argscan = 0; /* make name a cohesive string */ + + n = lookup(argi); + *argscan++ = '='; + attrib(n, xp); + if (xp & N_ENVNAM) + { + n->namenv = n->namval = argscan; + if (n == &pathnod) + set_builtins_path(); + } + else + assign(n, argscan); + + dolocale(n->namid); + return; + } + } +} + +replace(a, v) +register unsigned char **a; +unsigned char *v; +{ + free(*a); + *a = make(v); +} + +dfault(n, v) +struct namnod *n; +unsigned char *v; +{ + if (n->namval == 0) + assign(n, v); +} + +assign(n, v) +struct namnod *n; +unsigned char *v; +{ + if (n->namflg & N_RDONLY) + failed(n->namid, wtfailed); + +#ifndef RES + + else if (flags & rshflg) + { + if (n == &pathnod || eq(n->namid,"SHELL")) + failed(n->namid, restricted); + } +#endif + + else if (n->namflg & N_FUNCTN) + { + func_unhash(n->namid); + freefunc(n); + + n->namenv = 0; + n->namflg = N_DEFAULT; + } + + if (n == &mchknod) + { + mailchk = stoi(v); + } + + replace(&n->namval, v); + attrib(n, N_ENVCHG); + + if (n == &pathnod) + { + zaphash(); + set_dotpath(); + set_builtins_path(); + return; + } + + if (flags & prompt) + { + if ((n == &mailpnod) || (n == &mailnod && mailpnod.namflg == N_DEFAULT)) + setmail(n->namval); + } +} + +static void +set_builtins_path() +{ + register unsigned char *path; + + ucb_builtins = 0; + path = getpath(""); + while (path && *path) + { + if (patheq(path, "/usr/ucb")) + { + ucb_builtins++; + break; + } + else if (patheq(path, "/usr/bin")) + break; + else if (patheq(path, "/bin")) + break; + else if (patheq(path, "/usr/5bin")) + break; + path = nextpath(path); + } +} + +static int +patheq(component, dir) +register unsigned char *component; +register char *dir; +{ + register unsigned char c; + + for (;;) + { + c = *component++; + if (c == COLON) + c = '\0'; /* end of component of path */ + if (c != *dir++) + return(0); + if (c == '\0') + return(1); + } +} + +readvar(names) +unsigned char **names; +{ + struct fileblk fb; + register struct fileblk *f = &fb; + unsigned char c[MULTI_BYTE_MAX+1]; + register int rc = 0; + struct namnod *n = lookup(*names++); /* done now to avoid storage mess */ + unsigned char *rel = (unsigned char *)relstak(); + unsigned char *oldstak; + register unsigned char *pc, *rest; + int d; + + push(f); + initf(dup(0)); + + /* + * If stdin is a pipe then this lseek(2) will fail with ESPIPE, so + * the read buffer size is set to 1 because we will not be able + * lseek(2) back towards the beginning of the file, so we have + * to read a byte at a time instead + * + */ + if (lseek(0, (off_t)0, SEEK_CUR) == -1) + f->fsiz = 1; + + /* + * If stdin is a socket then this isastream(3C) will return 1, so + * the read buffer size is set to 1 because we will not be able + * lseek(2) back towards the beginning of the file, so we have + * to read a byte at a time instead + * + */ + if (isastream(0) == 1) + f->fsiz = 1; + + /* + * strip leading IFS characters + */ + for (;;) + { + d = nextwc(); + if(eolchar(d)) + break; + rest = readw(d); + pc = c; + while(*pc++ = *rest++); + if(!anys(c, ifsnod.namval)) + break; + } + + oldstak = curstak(); + for (;;) + { + if ((*names && anys(c, ifsnod.namval)) || eolchar(d)) + { + if (staktop >= brkend) + growstak(staktop); + zerostak(); + assign(n, absstak(rel)); + setstak(rel); + if (*names) + n = lookup(*names++); + else + n = 0; + if (eolchar(d)) + { + break; + } + else /* strip imbedded IFS characters */ + while(1) { + d = nextwc(); + if(eolchar(d)) + break; + rest = readw(d); + pc = c; + while(*pc++ = *rest++); + if(!anys(c, ifsnod.namval)) + break; + } + } + else + { + if(d == '\\') { + d = readwc(); + rest = readw(d); + while(d = *rest++) { + if (staktop >= brkend) + growstak(staktop); + pushstak(d); + } + oldstak = staktop; + } + else + { + pc = c; + while(d = *pc++) { + if (staktop >= brkend) + growstak(staktop); + pushstak(d); + } + if(!anys(c, ifsnod.namval)) + oldstak = staktop; + } + d = nextwc(); + + if (eolchar(d)) + staktop = oldstak; + else + { + rest = readw(d); + pc = c; + while(*pc++ = *rest++); + } + } + } + while (n) + { + assign(n, nullstr); + if (*names) + n = lookup(*names++); + else + n = 0; + } + + if (eof) + rc = 1; + + if (isastream(0) != 1) + /* + * If we are reading on a stream do not attempt to + * lseek(2) back towards the start because this is + * logically meaningless, but there is nothing in + * the standards to pervent the stream implementation + * from attempting it and breaking our code here + * + */ + lseek(0, (off_t)(f->nxtoff - f->endoff), SEEK_CUR); + + pop(); + return(rc); +} + +assnum(p, i) +unsigned char **p; +long i; +{ + int j = ltos(i); + replace(p, &numbuf[j]); +} + +unsigned char * +make(v) +unsigned char *v; +{ + register unsigned char *p; + + if (v) + { + movstr(v, p = (unsigned char *)alloc(length(v))); + return(p); + } + else + return(0); +} + + +struct namnod * +lookup(nam) + register unsigned char *nam; +{ + register struct namnod *nscan = namep; + register struct namnod **prev; + int LR; + + if (!chkid(nam)) + failed(nam, notid); + + while (nscan) + { + if ((LR = cf(nam, nscan->namid)) == 0) + return(nscan); + + else if (LR < 0) + prev = &(nscan->namlft); + else + prev = &(nscan->namrgt); + nscan = *prev; + } + /* + * add name node + */ + nscan = (struct namnod *)alloc(sizeof *nscan); + nscan->namlft = nscan->namrgt = (struct namnod *)NIL; + nscan->namid = make(nam); + nscan->namval = 0; + nscan->namflg = N_DEFAULT; + nscan->namenv = 0; + + return(*prev = nscan); +} + +BOOL +chkid(nam) +unsigned char *nam; +{ + register unsigned char *cp = nam; + + if (!letter(*cp)) + return(FALSE); + else + { + while (*++cp) + { + if (!alphanum(*cp)) + return(FALSE); + } + } + return(TRUE); +} + +static int (*namfn)(); +namscan(fn) + int (*fn)(); +{ + namfn = fn; + namwalk(namep); +} + +static void +namwalk(np) +register struct namnod *np; +{ + if (np) + { + namwalk(np->namlft); + (*namfn)(np); + namwalk(np->namrgt); + } +} + +printnam(n) +struct namnod *n; +{ + register unsigned char *s; + + sigchk(); + + if (n->namflg & N_FUNCTN) + { + prs_buff(n->namid); + prs_buff("(){\n"); + prf(n->namenv); + prs_buff("\n}\n"); + } + else if (s = n->namval) + { + prs_buff(n->namid); + prc_buff('='); + prs_buff(s); + prc_buff(NL); + } +} + +static unsigned char * +staknam(n) +register struct namnod *n; +{ + register unsigned char *p; + + p = movstrstak(n->namid, staktop); + p = movstrstak("=", p); + p = movstrstak(n->namval, p); + return(getstak(p + 1 - (unsigned char *)(stakbot))); +} + +static int namec; + +exname(n) + register struct namnod *n; +{ + register int flg = n->namflg; + + if (flg & N_ENVCHG) + { + + if (flg & N_EXPORT) + { + free(n->namenv); + n->namenv = make(n->namval); + } + else + { + free(n->namval); + n->namval = make(n->namenv); + } + } + + + if (!(flg & N_FUNCTN)) + n->namflg = N_DEFAULT; + + if (n->namval) + namec++; + +} + +printro(n) +register struct namnod *n; +{ + if (n->namflg & N_RDONLY) + { + prs_buff(readonly); + prc_buff(SPACE); + prs_buff(n->namid); + prc_buff(NL); + } +} + +printexp(n) +register struct namnod *n; +{ + if (n->namflg & N_EXPORT) + { + prs_buff(export); + prc_buff(SPACE); + prs_buff(n->namid); + prc_buff(NL); + } +} + +setup_env() +{ + register unsigned char **e = environ; + + while (*e) + setname(*e++, N_ENVNAM); +} + + +static unsigned char **argnam; + +static +countnam(n) +struct namnod *n; +{ + if (n->namval) + namec++; +} + +static +pushnam(n) + register struct namnod *n; +{ + register int flg = n->namflg; + register unsigned char *p; + register unsigned char *namval; + + if (((flg & N_ENVCHG) && (flg & N_EXPORT)) || (flg & N_FUNCTN)) + namval = n->namval; + else { + /* Discard Local variable in child process */ + if (!(flg & ~N_ENVCHG)) { + n->namflg = 0; + n->namenv = 0; + if (n->namval) { + /* Release for re-use */ + free(n->namval); + n->namval = (unsigned char *)NIL; + } + } + namval = n->namenv; + } + + if (namval) + { + p = movstrstak(n->namid, staktop); + p = movstrstak("=", p); + p = movstrstak(namval, p); + *argnam++ = getstak(p + 1 - (unsigned char *)(stakbot)); + } +} + +unsigned char ** +local_setenv() +{ + register unsigned char **er; + + namec = 0; + namscan(countnam); + + argnam = er = (unsigned char **)getstak(namec * BYTESPERWORD + BYTESPERWORD); + namscan(pushnam); + *argnam++ = 0; + return(er); +} + +void +setvars() +{ + namscan(exname); +} + +struct namnod * +findnam(nam) + register unsigned char *nam; +{ + register struct namnod *nscan = namep; + int LR; + + if (!chkid(nam)) + return(0); + while (nscan) + { + if ((LR = cf(nam, nscan->namid)) == 0) + return(nscan); + else if (LR < 0) + nscan = nscan->namlft; + else + nscan = nscan->namrgt; + } + return(0); +} + + +unset_name(name) + register unsigned char *name; +{ + register struct namnod *n; + register unsigned char call_dolocale = 0; + + if (n = findnam(name)) + { + if (n->namflg & N_RDONLY) + failed(name, wtfailed); + + if (n == &pathnod || + n == &ifsnod || + n == &ps1nod || + n == &ps2nod || + n == &mchknod) + { + failed(name, badunset); + } + +#ifndef RES + + if ((flags & rshflg) && eq(name, "SHELL")) + failed(name, restricted); + +#endif + + if (n->namflg & N_FUNCTN) + { + func_unhash(name); + freefunc(n); + } + else + { + call_dolocale++; + free(n->namval); + free(n->namenv); + } + + n->namval = n->namenv = 0; + n->namflg = N_DEFAULT; + + if (call_dolocale) + dolocale(name); + + if (flags & prompt) + { + if (n == &mailpnod) + setmail(mailnod.namval); + else if (n == &mailnod && mailpnod.namflg == N_DEFAULT) + setmail(0); + } + } +} + +/* + * The environment variables which affect locale. + * Note: if all names in this list do not begin with 'L', + * you MUST modify dolocale(). Also, be sure that the + * fake_env has the same number of elements as localevar. + */ +static char *localevar[] = { + "LC_ALL", + "LC_CTYPE", + "LC_MESSAGES", + "LANG", + 0 +}; + +static char *fake_env[] = { + 0, + 0, + 0, + 0, + 0 +}; + +/* + * If name is one of several special variables which affect the locale, + * do a setlocale(). + */ +static void +dolocale(nm) + char *nm; +{ + char **real_env; + struct namnod *n; + int lv, fe; + int i; + + /* + * Take advantage of fact that names of these vars all start + * with 'L' to avoid unnecessary work. + * Do locale processing only if /usr is mounted. + */ + if ((*nm != 'L') || !localedir_exists || + (!(eq(nm, "LC_ALL") || eq(nm, "LC_CTYPE") || + eq(nm, "LANG") || eq(nm, "LC_MESSAGES")))) + return; + + /* + * setlocale() has all the smarts built into it, but + * it works by examining the environment. Unfortunately, + * when you set an environment variable, the shell does + * not modify its own environment; it just remembers that the + * variable needs to be exported to any children. We hack around + * this by consing up a fake environment for the use of setlocale() + * and substituting it for the real env before calling setlocale(). + */ + + /* + * Build the fake environment. + * Look up the value of each of the special environment + * variables, and put their value into the fake environment, + * if they are exported. + */ + for (lv = 0, fe = 0; localevar[lv]; lv++) { + if ((n = findnam(localevar[lv]))) { + register char *p, *q; + + if (!n->namval) + continue; + + fake_env[fe++] = p = alloc(length(localevar[lv]) + + length(n->namval) + 2); + /* copy name */ + q = localevar[lv]; + while (*q) + *p++ = *q++; + + *p++ = '='; + + /* copy value */ + q = (char*)(n->namval); + while (*q) + *p++ = *q++; + *p++ = '\0'; + } + } + fake_env[fe] = (char *)0; + + /* + * Switch fake env for real and call setlocale(). + */ + real_env = (char **)environ; + environ = (unsigned char **)fake_env; + + if (setlocale(LC_ALL, "") == NULL) + prs("couldn't set locale correctly\n"); + + /* + * Switch back and tear down the fake env. + */ + environ = (unsigned char **)real_env; + for (i = 0; i < fe; i++) { + free(fake_env[i]); + fake_env[i] = (char *)0; + } +} diff --git a/usr/src/cmd/sh/name.h b/usr/src/cmd/sh/name.h new file mode 100644 index 0000000000..8a1a6cd8cc --- /dev/null +++ b/usr/src/cmd/sh/name.h @@ -0,0 +1,49 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7.1.1 */ +/* + * UNIX shell + */ + + +#define N_ENVCHG 0020 +#define N_RDONLY 0010 +#define N_EXPORT 0004 +#define N_ENVNAM 0002 +#define N_FUNCTN 0001 + +#define N_DEFAULT 0 + +struct namnod +{ + struct namnod *namlft; + struct namnod *namrgt; + unsigned char *namid; + unsigned char *namval; + unsigned char *namenv; + int namflg; +}; + diff --git a/usr/src/cmd/sh/print.c b/usr/src/cmd/sh/print.c new file mode 100644 index 0000000000..0bac00915b --- /dev/null +++ b/usr/src/cmd/sh/print.c @@ -0,0 +1,379 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, 1997 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.12.6.1 */ +/* + * UNIX shell + * + */ + +#include "defs.h" +#include <sys/param.h> +#include <locale.h> +#include <wctype.h> /* iswprint() */ + +#define BUFLEN 256 + +unsigned char numbuf[21]; + +static unsigned char buffer[BUFLEN]; +static unsigned char *bufp = buffer; +static int index = 0; +static int buffd = 1; + +void prc_buff(unsigned char c); +void prs_buff(unsigned char *s); +void prn_buff(int n); +void prs_cntl(unsigned char *s); +void prs(unsigned char *as); +void itos(int n); + +/* + * printing and io conversion + */ +void +prp() +{ + if ((flags & prompt) == 0 && cmdadr) { + prs_cntl(cmdadr); + prs((unsigned char *)colon); + } +} + +void +prs(unsigned char *as) +{ + char *s; + + if ((s = gettext((char *)as)) != 0) { + write(output, s, length(s) - 1); + } +} + +void +prc(unsigned char c) +{ + if (c) { + write(output, &c, 1); + } +} + +void +prwc(wchar_t c) +{ + char mb[MB_LEN_MAX + 1]; + int len; + + if (c == 0) { + return; + } + if ((len = wctomb(mb, c)) < 0) { + mb[0] = (unsigned char)c; + len = 1; + } + write(output, mb, len); +} + +void +prt(long t) +{ + int hr, min, sec; + + t += HZ / 2; + t /= HZ; + sec = t % 60; + t /= 60; + min = t % 60; + + if ((hr = t / 60) != 0) { + prn_buff(hr); + prc_buff('h'); + } + + prn_buff(min); + prc_buff('m'); + prn_buff(sec); + prc_buff('s'); +} + +void +prn(int n) +{ + itos(n); + + prs(numbuf); +} + +void +itos(int n) +{ + unsigned char buf[21]; + unsigned char *abuf = &buf[20]; + int d; + + *--abuf = (unsigned char)'\0'; + + do { + *--abuf = (unsigned char)('0' + n - 10 * (d = n / 10)); + } while ((n = d) != 0); + + strncpy(numbuf, abuf, sizeof (numbuf)); +} + +int +stoi(unsigned char *icp) +{ + unsigned char *cp = icp; + int r = 0; + unsigned char c; + + while ((c = *cp, digit(c)) && c && r >= 0) { + r = r * 10 + c - '0'; + cp++; + } + if (r < 0 || cp == icp) { + failed(icp, badnum); + } else { + return (r); + } +} + +int +ltos(long n) +{ + int i; + + numbuf[20] = '\0'; + for (i = 19; i >= 0; i--) { + numbuf[i] = n % 10 + '0'; + if ((n /= 10) == 0) { + break; + } + } + return (i); +} + +void +prl(long n) +{ + int i; + i = ltos(n); + prs_buff(&numbuf[i]); +} + + +int +ulltos(u_longlong_t n) +{ + int i; + + /* The max unsigned long long is 20 characters (+1 for '\0') */ + numbuf[20] = '\0'; + for (i = 19; i >= 0; i--) { + numbuf[i] = n % 10 + '0'; + if ((n /= 10) == 0) { + break; + } + } + return (i); +} + +void +prull(u_longlong_t n) +{ + int i; + i = ulltos(n); + prs_buff(&numbuf[i]); +} + +void +flushb() +{ + if (index) { + bufp[index] = '\0'; + write(buffd, bufp, length(bufp) - 1); + index = 0; + } +} + +void +prc_buff(unsigned char c) +{ + if (c) { + if (buffd != -1 && index + 1 >= BUFLEN) { + flushb(); + } + + bufp[index++] = c; + } else { + flushb(); + write(buffd, &c, 1); + } +} + +void +prs_buff(unsigned char *s) +{ + int len = length(gettext((char *)s)) - 1; + + if (buffd != -1 && index + len >= BUFLEN) { + flushb(); + } + + if (buffd != -1 && len >= BUFLEN) { + write(buffd, gettext((char *)s), len); + } else { + movstr(gettext((char *)s), &bufp[index]); + index += len; + } +} + +unsigned char * +octal(unsigned char c, unsigned char *ptr) +{ + *ptr++ = '\\'; + *ptr++ = ((unsigned int)c >> 6) + '0'; + *ptr++ = (((unsigned int)c >> 3) & 07) + '0'; + *ptr++ = (c & 07) + '0'; + return (ptr); +} + +void +prs_cntl(unsigned char *s) +{ + int n; + wchar_t wc; + unsigned char *olds = s; + unsigned char *ptr = bufp; + wchar_t c; + + if ((n = mbtowc(&wc, (const char *)s, MB_LEN_MAX)) <= 0) { + n = 0; + } + while (n != 0) { + if (n < 0) { + ptr = octal(*s++, ptr); + } else { + c = wc; + s += n; + if (!iswprint(c)) { + if (c < '\040' && c > 0) { + /* + * assumes ASCII char + * translate a control character + * into a printable sequence + */ + *ptr++ = '^'; + *ptr++ = (c + 0100); + } else if (c == 0177) { + /* '\0177' does not work */ + *ptr++ = '^'; + *ptr++ = '?'; + } else { + /* + * unprintable 8-bit byte sequence + * assumes all legal multibyte + * sequences are + * printable + */ + ptr = octal(*olds, ptr); + } + } else { + while (n--) { + *ptr++ = *olds++; + } + } + } + if (buffd != -1 && ptr >= &bufp[BUFLEN-4]) { + *ptr = '\0'; + prs(bufp); + ptr = bufp; + } + olds = s; + if ((n = mbtowc(&wc, (const char *)s, MB_LEN_MAX)) <= 0) { + n = 0; + } + } + *ptr = '\0'; + prs(bufp); +} + +void +prl_buff(long lc) +{ + prs_buff(&numbuf[ltos(lc)]); +} + +void +prull_buff(u_longlong_t lc) +{ + prs_buff(&numbuf[ulltos(lc)]); +} + +void +prn_buff(int n) +{ + itos(n); + + prs_buff(numbuf); +} + +void +prsp_buff(int cnt) +{ + while (cnt--) { + prc_buff(SPACE); + } +} + +int +setb(int fd) +{ + int ofd; + + if ((ofd = buffd) == -1) { + if (bufp+index+1 >= brkend) { + growstak(bufp+index+1); + } + if (bufp[index-1]) { + bufp[index++] = 0; + } + endstak(bufp+index); + } else { + flushb(); + } + if ((buffd = fd) == -1) { + bufp = locstak(); + } else { + bufp = buffer; + } + index = 0; + return (ofd); +} diff --git a/usr/src/cmd/sh/pwd.c b/usr/src/cmd/sh/pwd.c new file mode 100644 index 0000000000..517f1341c8 --- /dev/null +++ b/usr/src/cmd/sh/pwd.c @@ -0,0 +1,299 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.14.6.1 */ +/* + * UNIX shell + */ + +#include "mac.h" +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <limits.h> + +#define DOT '.' +#define NULL 0 +#define SLASH '/' +#define PARTLY 2 + +static void rmslash(); +#ifdef __STDC__ +extern const char longpwd[]; +#else +extern char longpwd[]; +#endif +extern char *getcwd(); + +unsigned char cwdname[PATH_MAX+1]; + +static int didpwd = FALSE; + +cwd(dir) + register unsigned char *dir; +{ + register unsigned char *pcwd; + register unsigned char *pdir; + + /* First remove extra /'s */ + + rmslash(dir); + + /* Now remove any .'s */ + + pdir = dir; + if(*dir == SLASH) + pdir++; + while(*pdir) /* remove /./ by itself */ + { + if((*pdir==DOT) && (*(pdir+1)==SLASH)) + { + movstr(pdir+2, pdir); + continue; + } + pdir++; + while ((*pdir) && (*pdir != SLASH)) + pdir++; + if (*pdir) + pdir++; + } + /* take care of trailing /. */ + if(*(--pdir)==DOT && pdir > dir && *(--pdir)==SLASH) { + if(pdir > dir) { + *pdir = NULL; + } else { + *(pdir+1) = NULL; + } + + } + + /* Remove extra /'s */ + + rmslash(dir); + + /* Now that the dir is canonicalized, process it */ + + if(*dir==DOT && *(dir+1)==NULL) + { + return; + } + + + if(*dir==SLASH) + { + /* Absolute path */ + + pcwd = cwdname; + *pcwd++ = *dir++; + didpwd = PARTLY; + } + else + { + /* Relative path */ + + if (didpwd == FALSE) + return; + didpwd = PARTLY; + pcwd = cwdname + length(cwdname) - 1; + if(pcwd != cwdname+1) + *pcwd++ = SLASH; + } + while(*dir) + { + if(*dir==DOT && + *(dir+1)==DOT && + (*(dir+2)==SLASH || *(dir+2)==NULL)) + { + /* Parent directory, so backup one */ + + if( pcwd > cwdname+2 ) + --pcwd; + while(*(--pcwd) != SLASH) + ; + pcwd++; + dir += 2; + if(*dir==SLASH) + { + dir++; + } + continue; + } + if (pcwd >= &cwdname[PATH_MAX+1]) + { + didpwd=FALSE; + return; + } + *pcwd++ = *dir++; + while((*dir) && (*dir != SLASH)) + { + if (pcwd >= &cwdname[PATH_MAX+1]) + { + didpwd=FALSE; + return; + } + *pcwd++ = *dir++; + } + if (*dir) + { + if (pcwd >= &cwdname[PATH_MAX+1]) + { + didpwd=FALSE; + return; + } + *pcwd++ = *dir++; + } + } + if (pcwd >= &cwdname[PATH_MAX+1]) + { + didpwd=FALSE; + return; + } + *pcwd = NULL; + + --pcwd; + if(pcwd>cwdname && *pcwd==SLASH) + { + /* Remove trailing / */ + + *pcwd = NULL; + } + return; +} + +void +cwd2() +{ + struct stat stat1, stat2; + unsigned char *pcwd; + /* check if there are any symbolic links in pathname */ + + if(didpwd == FALSE) + return; + pcwd = cwdname + 1; + if(didpwd == PARTLY) { + while (*pcwd) + { + char c; + while((c = *pcwd++) != SLASH && c != '\0'); + *--pcwd = '\0'; + if (lstat((char *)cwdname, &stat1) == -1 + || (stat1.st_mode & S_IFMT) == S_IFLNK) { + didpwd = FALSE; + *pcwd = c; + return; + } + *pcwd = c; + if(c) + pcwd++; + } + didpwd = TRUE; + } else + if (stat((char *)cwdname, &stat1) == -1) { + didpwd = FALSE; + return; + } + /* + * check if ino's and dev's match; pathname could + * consist of symbolic links with ".." + */ + + if (stat(".", &stat2) == -1 + || stat1.st_dev != stat2.st_dev + || stat1.st_ino != stat2.st_ino) + didpwd = FALSE; + return; +} + +unsigned char * +cwdget() +{ + cwd2(); + if (didpwd == FALSE) { + if(getcwd(cwdname, PATH_MAX+1) == (char *)0) + *cwdname = 0; + didpwd = TRUE; + } + return (cwdname); +} + +/* + * Print the current working directory. + */ + +cwdprint() +{ + register unsigned char *cp; + + cwd2(); + if (didpwd == FALSE) { + if(getcwd(cwdname, PATH_MAX+1) == (char *)0) { + if(errno && errno != ERANGE) + error("cannot determine current directory"); + else + error(longpwd); + } + didpwd = TRUE; + } + + for (cp = cwdname; *cp; cp++) { + prc_buff(*cp); + } + + prc_buff(NL); + return; +} + +/* + * This routine will remove repeated slashes from string. + */ + +static void +rmslash(string) + unsigned char *string; +{ + register unsigned char *pstring; + + pstring = string; + while(*pstring) + { + if(*pstring==SLASH && *(pstring+1)==SLASH) + { + /* Remove repeated SLASH's */ + + movstr(pstring+1, pstring); + continue; + } + pstring++; + } + + --pstring; + if(pstring>string && *pstring==SLASH) + { + /* Remove trailing / */ + + *pstring = NULL; + } + return; +} diff --git a/usr/src/cmd/sh/service.c b/usr/src/cmd/sh/service.c new file mode 100644 index 0000000000..a39967a882 --- /dev/null +++ b/usr/src/cmd/sh/service.c @@ -0,0 +1,730 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.22.5.1 */ + +/* + * UNIX shell + */ + +#include "defs.h" +#include <errno.h> +#include <fcntl.h> +#include "sh_policy.h" + +#define ARGMK 01 + +static unsigned char *execs(); +static int gsort(); +static int split(); +extern const char *sysmsg[]; +extern short topfd; + + + +/* + * service routines for `execute' + */ +initio(iop, save) + struct ionod *iop; + int save; +{ + register unsigned char *ion; + register int iof, fd; + int ioufd; + short lastfd; + int newmode; + + lastfd = topfd; + while (iop) { + iof = iop->iofile; + ion = mactrim(iop->ioname); + ioufd = iof & IOUFD; + + if (*ion && (flags&noexec) == 0) { + if (save) { + fdmap[topfd].org_fd = ioufd; + fdmap[topfd++].dup_fd = savefd(ioufd); + } + + if (iof & IODOC) { + struct tempblk tb; + + subst(chkopen(ion, 0), (fd = tmpfil(&tb))); + + /* + * pushed in tmpfil() -- + * bug fix for problem with + * in-line scripts + */ + poptemp(); + + fd = chkopen(tmpout, 0); + unlink((const char *)tmpout); + } else if (iof & IOMOV) { + if (eq(minus, ion)) { + fd = -1; + close(ioufd); + } else if ((fd = stoi(ion)) >= USERIO) { + failed(ion, badfile); + } + else + fd = dup(fd); + } else if (((iof & IOPUT) == 0) && ((iof & IORDW) == 0)) + fd = chkopen(ion, 0); + else if (iof & IORDW) /* For <> */ { + newmode = O_RDWR|O_CREAT; + fd = chkopen(ion, newmode); + } else if (flags & rshflg) { + failed(ion, restricted); + } else if (iof & IOAPP && + (fd = open((char *)ion, 1)) >= 0) { + lseek(fd, (off_t)0, SEEK_END); + } else { + fd = create(ion); + } + if (fd >= 0) + renamef(fd, ioufd); + } + + iop = iop->ionxt; + } + return (lastfd); +} + +unsigned char * +simple(s) +unsigned char *s; +{ + unsigned char *sname; + + sname = s; + while (1) { + if (any('/', sname)) + while (*sname++ != '/') + ; + else + return (sname); + } +} + +unsigned char * +getpath(s) + unsigned char *s; +{ + register unsigned char *path, *newpath; + register int pathlen; + + if (any('/', s)) + { + if (flags & rshflg) + failed(s, restricted); + else + return ((unsigned char *)nullstr); + } else if ((path = pathnod.namval) == 0) + return ((unsigned char *)defpath); + else { + pathlen = length(path)-1; + /* Add extra ':' if PATH variable ends in ':' */ + if (pathlen > 2 && path[pathlen - 1] == ':' && + path[pathlen - 2] != ':') { + newpath = locstak(); + (void) memcpystak(newpath, path, pathlen); + newpath[pathlen] = ':'; + endstak(newpath + pathlen + 1); + return (newpath); + } else + return (cpystak(path)); + } +} + +pathopen(path, name) +register unsigned char *path, *name; +{ + register int f; + + do + { + path = catpath(path, name); + } while ((f = open((char *)curstak(), 0)) < 0 && path); + return (f); +} + +unsigned char * +catpath(path, name) +register unsigned char *path; +unsigned char *name; +{ + /* + * leaves result on top of stack + */ + register unsigned char *scanp = path; + register unsigned char *argp = locstak(); + + while (*scanp && *scanp != COLON) + { + if (argp >= brkend) + growstak(argp); + *argp++ = *scanp++; + } + if (scanp != path) + { + if (argp >= brkend) + growstak(argp); + *argp++ = '/'; + } + if (*scanp == COLON) + scanp++; + path = (*scanp ? scanp : 0); + scanp = name; + do + { + if (argp >= brkend) + growstak(argp); + } + while (*argp++ = *scanp++); + return (path); +} + +unsigned char * +nextpath(path) + register unsigned char *path; +{ + register unsigned char *scanp = path; + + while (*scanp && *scanp != COLON) + scanp++; + + if (*scanp == COLON) + scanp++; + + return (*scanp ? scanp : 0); +} + +static unsigned char *xecmsg; +static unsigned char **xecenv; + +int +execa(at, pos) + unsigned char *at[]; + short pos; +{ + register unsigned char *path; + register unsigned char **t = at; + int cnt; + + if ((flags & noexec) == 0) + { + xecmsg = (unsigned char *)notfound; + path = getpath(*t); + xecenv = local_setenv(); + + if (pos > 0) + { + cnt = 1; + while (cnt != pos) + { + ++cnt; + path = nextpath(path); + } + execs(path, t); + path = getpath(*t); + } + while (path = execs(path, t)) + ; + failed(*t, xecmsg); + } +} + +static unsigned char * +execs(ap, t) +unsigned char *ap; +register unsigned char *t[]; +{ + register int pfstatus = NOATTRS; + register unsigned char *p, *prefix; + unsigned char *savptr; + + prefix = catpath(ap, t[0]); + trim(p = curstak()); + sigchk(); + + if (flags & pfshflg) { + /* + * Need to save the stack information, or the + * first memory allocation in secpolicy_profile_lookup() + * will clobber it. + */ + savptr = endstak(p + strlen((const char *)p) + 1); + + pfstatus = secpolicy_pfexec((const char *)p, + (char **)t, (const char **)xecenv); + + if (pfstatus != NOATTRS) { + errno = pfstatus; + } + + tdystak(savptr); + } + + if (pfstatus == NOATTRS) { + execve((const char *)p, (char *const *)&t[0], + (char *const *)xecenv); + } + + switch (errno) + { + case ENOEXEC: /* could be a shell script */ + funcnt = 0; + flags = 0; + *flagadr = 0; + comdiv = 0; + ioset = 0; + clearup(); /* remove open files and for loop junk */ + if (input) + close(input); + input = chkopen(p, 0); + +#ifdef ACCT + preacct(p); /* reset accounting */ +#endif + + /* + * set up new args + */ + + setargs(t); + longjmp(subshell, 1); + + case ENOMEM: + failed(p, toobig); + + case E2BIG: + failed(p, arglist); + + case ETXTBSY: + failed(p, txtbsy); + + case ELIBACC: + failed(p, libacc); + + case ELIBBAD: + failed(p, libbad); + + case ELIBSCN: + failed(p, libscn); + + case ELIBMAX: + failed(p, libmax); + + default: + xecmsg = (unsigned char *)badexec; + case ENOENT: + return (prefix); + } +} + +BOOL nosubst; + +trim(at) +unsigned char *at; +{ + register unsigned char *last; + register unsigned char *current; + register unsigned char c; + int len; + wchar_t wc; + + nosubst = 0; + if (current = at) + { + last = at; + while (c = *current) { + if ((len = mbtowc(&wc, (char *)current, + MB_LEN_MAX)) <= 0) { + *last++ = c; + current++; + continue; + } + + if (wc != '\\') { + memcpy(last, current, len); + last += len; + current += len; + continue; + } + + /* remove \ and quoted nulls */ + nosubst = 1; + current++; + if (c = *current) { + if ((len = mbtowc(&wc, (char *)current, + MB_LEN_MAX)) <= 0) { + *last++ = c; + current++; + continue; + } + memcpy(last, current, len); + last += len; + current += len; + } else + current++; + } + + *last = 0; + } +} + +/* Same as trim, but only removes backlashes before slashes */ +trims(at) +unsigned char *at; +{ + register unsigned char *last; + register unsigned char *current; + register unsigned char c; + int len; + wchar_t wc; + + if (current = at) + { + last = at; + while (c = *current) { + if ((len = mbtowc(&wc, (char *)current, + MB_LEN_MAX)) <= 0) { + *last++ = c; + current++; + continue; + } + + if (wc != '\\') { + memcpy(last, current, len); + last += len; current += len; + continue; + } + + /* remove \ and quoted nulls */ + current++; + if (!(c = *current)) { + current++; + continue; + } + + if (c == '/') { + *last++ = c; + current++; + continue; + } + + *last++ = '\\'; + if ((len = mbtowc(&wc, (char *)current, + MB_LEN_MAX)) <= 0) { + *last++ = c; + current++; + continue; + } + memcpy(last, current, len); + last += len; current += len; + } + *last = 0; + } +} + +unsigned char * +mactrim(s) +unsigned char *s; +{ + register unsigned char *t = macro(s); + + trim(t); + return (t); +} + +unsigned char ** +scan(argn) +int argn; +{ + register struct argnod *argp = + (struct argnod *)(Rcheat(gchain) & ~ARGMK); + register unsigned char **comargn, **comargm; + + comargn = (unsigned char **)getstak(BYTESPERWORD * argn + BYTESPERWORD); + comargm = comargn += argn; + *comargn = ENDARGS; + while (argp) + { + *--comargn = argp->argval; + + trim(*comargn); + argp = argp->argnxt; + + if (argp == 0 || Rcheat(argp) & ARGMK) + { + gsort(comargn, comargm); + comargm = comargn; + } + argp = (struct argnod *)(Rcheat(argp) & ~ARGMK); + } + return (comargn); +} + +static int +gsort(from, to) +unsigned char *from[], *to[]; +{ + int k, m, n; + register int i, j; + + if ((n = to - from) <= 1) + return; + for (j = 1; j <= n; j *= 2) + ; + for (m = 2 * j - 1; m /= 2; ) + { + k = n - m; + for (j = 0; j < k; j++) + { + for (i = j; i >= 0; i -= m) + { + register unsigned char **fromi; + + fromi = &from[i]; + if (cf(fromi[m], fromi[0]) > 0) + { + break; + } + else + { + unsigned char *s; + + s = fromi[m]; + fromi[m] = fromi[0]; + fromi[0] = s; + } + } + } + } +} + +/* + * Argument list generation + */ +getarg(ac) +struct comnod *ac; +{ + register struct argnod *argp; + register int count = 0; + register struct comnod *c; + + if (c = ac) + { + argp = c->comarg; + while (argp) + { + count += split(macro(argp->argval), 1); + argp = argp->argnxt; + } + } + return (count); +} + +static int +split(s) /* blank interpretation routine */ +unsigned char *s; +{ + register unsigned char *argp; + register int c; + int count = 0; + for (;;) + { + register int length; + sigchk(); + argp = locstak() + BYTESPERWORD; + while (c = *s) { + wchar_t wc; + if ((length = mbtowc(&wc, (char *)s, + MB_LEN_MAX)) <= 0) { + wc = (unsigned char)*s; + length = 1; + } + + if (c == '\\') { /* skip over quoted characters */ + if (argp >= brkend) + growstak(argp); + *argp++ = c; + s++; + /* get rest of multibyte character */ + if ((length = mbtowc(&wc, (char *)s, + MB_LEN_MAX)) <= 0) { + wc = (unsigned char)*s; + length = 1; + } + if (argp >= brkend) + growstak(argp); + *argp++ = *s++; + while (--length > 0) { + if (argp >= brkend) + growstak(argp); + *argp++ = *s++; + } + continue; + } + + if (anys(s, ifsnod.namval)) { + /* skip to next character position */ + s += length; + break; + } + + if (argp >= brkend) + growstak(argp); + *argp++ = c; + s++; + while (--length > 0) { + if (argp >= brkend) + growstak(argp); + *argp++ = *s++; + } + } + if (argp == staktop + BYTESPERWORD) + { + if (c) + { + continue; + } + else + { + return (count); + } + } + /* + * file name generation + */ + + argp = endstak(argp); + trims(((struct argnod *)argp)->argval); + if ((flags & nofngflg) == 0 && + (c = expand(((struct argnod *)argp)->argval, 0))) + count += c; + else + { + makearg(argp); + count++; + } + gchain = (struct argnod *)((int)gchain | ARGMK); + } +} + +#ifdef ACCT +#include <sys/types.h> +#include <sys/acct.h> +#include <sys/times.h> + +struct acct sabuf; +struct tms buffer; +static clock_t before; +static int shaccton; /* 0 implies do not write record on exit */ + /* 1 implies write acct record on exit */ + + +/* + * suspend accounting until turned on by preacct() + */ + +suspacct() +{ + shaccton = 0; +} + +preacct(cmdadr) + unsigned char *cmdadr; +{ + unsigned char *simple(); + + if (acctnod.namval && *acctnod.namval) + { + sabuf.ac_btime = time((time_t *)0); + before = times(&buffer); + sabuf.ac_uid = getuid(); + sabuf.ac_gid = getgid(); + movstrn(simple(cmdadr), sabuf.ac_comm, sizeof (sabuf.ac_comm)); + shaccton = 1; + } +} + + +doacct() +{ + int fd; + clock_t after; + + if (shaccton) { + after = times(&buffer); + sabuf.ac_utime = compress(buffer.tms_utime + buffer.tms_cutime); + sabuf.ac_stime = compress(buffer.tms_stime + buffer.tms_cstime); + sabuf.ac_etime = compress(after - before); + + if ((fd = open((char *)acctnod.namval, + O_WRONLY | O_APPEND | O_CREAT, 0666)) != -1) { + write(fd, &sabuf, sizeof (sabuf)); + close(fd); + } + } +} + +/* + * Produce a pseudo-floating point representation + * with 3 bits base-8 exponent, 13 bits fraction + */ + +compress(t) + register clock_t t; +{ + register exp = 0; + register rund = 0; + + while (t >= 8192) + { + exp++; + rund = t & 04; + t >>= 3; + } + + if (rund) + { + t++; + if (t >= 8192) + { + t >>= 3; + exp++; + } + } + return ((exp << 13) + t); +} +#endif diff --git a/usr/src/cmd/sh/setbrk.c b/usr/src/cmd/sh/setbrk.c new file mode 100644 index 0000000000..79ebf8cc72 --- /dev/null +++ b/usr/src/cmd/sh/setbrk.c @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8.1.1 */ +/* + * UNIX shell + */ + +#include "defs.h" + + +unsigned char* +setbrk(incr) +int incr; +{ + + register unsigned char *a = (unsigned char *)sbrk(incr); + + brkend = a + incr; + return(a); +} diff --git a/usr/src/cmd/sh/sh.xcl b/usr/src/cmd/sh/sh.xcl new file mode 100644 index 0000000000..0bb8e336d9 --- /dev/null +++ b/usr/src/cmd/sh/sh.xcl @@ -0,0 +1,191 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +msgid "/tmp/sh-" +msgid "" +msgid "SHELL" +msgid "rsh" +msgid "-rsh" +msgid "jsh" +msgid "-jsh" +msgid "600" +msgid "OPTIND" +msgid "1" +msgid "LC_CTYPE" +msgid "LANG" +msgid "C" +msgid "set" +msgid "sicrp" +msgid "" +msgid "(){\n" +msgid "\n}\n" +msgid "PATH" +msgid "CDPATH" +msgid "HOME" +msgid "MAIL" +msgid "IFS" +msgid "PS1" +msgid "PS2" +msgid "MAILCHECK" +msgid "SHACCT" +msgid "MAILPATH" +msgid "" +msgid " \t\n" +msgid "/usr/bin:" +msgid ": " +msgid "-" +msgid "/dev/null" +msgid "+ " +msgid "> " +msgid "$ " +msgid " +msgid ".profile" +msgid "/etc/profile" +msgid "case" +msgid "do" +msgid "done" +msgid "elif" +msgid "else" +msgid "esac" +msgid "fi" +msgid "for" +msgid "if" +msgid "in" +msgid "then" +msgid "until" +msgid "while" +msgid "{" +msgid "}" +# msgid "export" +# msgid "cannot dup" +# msgid "readonly" +msgid "." +msgid ":" +msgid "[" +msgid "bg" +msgid "break" +msgid "cd" +msgid "chdir" +msgid "continue" +msgid "echo" +msgid "eval" +msgid "exec" +msgid "exit" +msgid "fg" +msgid "getopts" +msgid "hash" +msgid "jobs" +msgid "kill" +msgid "newgrp" +msgid "pwd" +msgid "read" +msgid "return" +msgid "set" +msgid "shift" +msgid "stop" +msgid "suspend" +msgid "times" +msgid "trap" +msgid "type" +msgid "ulimit" +msgid "umask" +msgid "unset" +msgid "wait" +msgid "SHELL" +msgid "" +msgid "/usr/ucb" +msgid "/usr/bin" +msgid "(){\n" +msgid "\n}\n" +msgid "=" +msgid "SHELL" +msgid "" +msgid "/" +msgid "." +msgid "(){" +msgid "}" +msgid " &" +msgid "(" +msgid ")" +msgid " | " +msgid " && " +msgid " || " +msgid "for " +msgid " in" +msgid "do" +msgid "done" +msgid "while " +msgid "until " +msgid "if " +msgid "then" +msgid "else" +msgid "fi" +msgid "case " +msgid ";;" +msgid "<<" +msgid ">&" +msgid "<&" +msgid ">>" +msgid "." +msgid "[" +msgid "]" +msgid "test" +msgid "-o" +msgid "-a" +msgid "!" +msgid "(" +msgid ")" +msgid "=" +msgid "!=" +msgid "-r" +msgid "-w" +msgid "-x" +msgid "-d" +msgid "-c" +msgid "-b" +msgid "-f" +msgid "-u" +msgid "-g" +msgid "-k" +msgid "-p" +msgid "-h" +msgid "-s" +msgid "-t" +msgid "-n" +msgid "" +msgid "-z" +msgid "-eq" +msgid "-ne" +msgid "-gt" +msgid "-lt" +msgid "-ge" +msgid "-le" +msgid "." +msgid ".." +msgid "OPTIND" +msgid "OPTARG" +# msgid "Signal " +msgid "(wd: " +msgid "lpx" +msgid "fg" +msgid "-l" +msgid "0" +msgid "HSacdfnstv" diff --git a/usr/src/cmd/sh/sh_policy.c b/usr/src/cmd/sh/sh_policy.c new file mode 100644 index 0000000000..41a0c8d4bc --- /dev/null +++ b/usr/src/cmd/sh/sh_policy.c @@ -0,0 +1,198 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + * + * Policy backing functions for kpolicy=suser,profiles=yes + * + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <grp.h> +#include <pwd.h> +#include <strings.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include "sh_policy.h" + + +static const char *username; + +/* + * get the ruid and passwd name + */ +void +secpolicy_init(void) +{ + uid_t ruid; + struct passwd *passwd_ent; + + ruid = getuid(); + + if ((passwd_ent = getpwuid(ruid)) == NULL) { + secpolicy_print(SECPOLICY_ERROR, ERR_PASSWD); + } else if ((username = strdup(passwd_ent->pw_name)) == NULL) { + secpolicy_print(SECPOLICY_ERROR, ERR_MEM); + } +} + + +/* + * stuff pfexec full path at the begining of the argument vector + * for the command to be pfexec'd + * + * return newly allocated argv on success, else return NULL. + */ +static char ** +secpolicy_set_argv(char **arg_v) +{ + register int i, j; + register int arglen = 0; + char **pfarg_v = (char **)NULL; + + if (*arg_v == NULL) { + return (pfarg_v); + } + for (i = 0; arg_v[i] != 0; i++) { + arglen += strlen(arg_v[i]); + } + arglen += strlen(PFEXEC); + arglen++; /* for null termination */ + if ((pfarg_v = (char **)calloc(1, arglen)) == NULL) { + return (pfarg_v); + } + pfarg_v[0] = (char *)PFEXEC; + for (i = 0, j = 1; arg_v[i] != 0; i++, j++) { + pfarg_v[j] = arg_v[i]; + } + pfarg_v[j] = 0; + + return (pfarg_v); +} + + +/* + * gets realpath for cmd. + * return 0 on success, else return ENOENT. + */ +static int +secpolicy_getrealpath(const char *cmd, char *cmd_realpath) +{ + register char *mover; + char cwd[MAXPATHLEN]; + + /* + * What about relative paths? Were we passed one? + */ + mover = (char *)cmd; + if (*mover != '/') { + /* + * Everything in here will be considered a relative + * path, and therefore we need to prepend cwd to it. + */ + if (getcwd(cwd, MAXPATHLEN) == NULL) { + secpolicy_print(SECPOLICY_ERROR, ERR_CWD); + } + strcat(cwd, "/"); + if (strlcat(cwd, cmd, MAXPATHLEN) >= MAXPATHLEN) { + return (ENOENT); + } + mover = cwd; + } + /* + * Resolve ".." and other such nonsense. + * Now, is there *REALLY* a file there? + */ + if (realpath(mover, cmd_realpath) == NULL) { + return (ENOENT); + } + + return (0); +} + + +/* + * check if the command has execution attributes + * return - + * - NOATTRS : command in profile but has no execution attributes + * - ENOMEM : memory allocation errors + * - ENOENT : command not in profile + */ + +int +secpolicy_pfexec(const char *command, char **arg_v, const char **xecenv) +{ + register int status = NOATTRS; + char **pfarg_v = (char **)NULL; + char cmd_realpath[MAXPATHLEN + 1]; + execattr_t *exec; + + if ((status = secpolicy_getrealpath(command, cmd_realpath)) != 0) { + return (status); + } + if ((exec = getexecuser(username, KV_COMMAND, + (const char *)cmd_realpath, GET_ONE)) == NULL) { + /* + * command not in profile + */ + return (ENOENT); + } + /* + * In case of "All" profile, we'd go through pfexec + * if it had any attributes. + */ + if ((exec->attr != NULL) && (exec->attr->length != 0)) { + /* + * command in profile and has attributes + */ + free_execattr(exec); + arg_v[0] = (char *)command; + pfarg_v = secpolicy_set_argv(arg_v); + if (pfarg_v != NULL) { + errno = 0; + if (xecenv == NULL) { + execv(PFEXEC, (char *const *)pfarg_v); + } else { + execve(PFEXEC, (char *const *)pfarg_v, + (char *const *)xecenv); + } + free(pfarg_v); + status = errno; + } else { + status = ENOMEM; + } + } else { + /* + * command in profile, but has no attributes + */ + free_execattr(exec); + status = NOATTRS; + } + + + return (status); +} diff --git a/usr/src/cmd/sh/sh_policy.h b/usr/src/cmd/sh/sh_policy.h new file mode 100644 index 0000000000..6efd47ca52 --- /dev/null +++ b/usr/src/cmd/sh/sh_policy.h @@ -0,0 +1,65 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _SH_POLICY_H +#define _SH_POLICY_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <exec_attr.h> + +#define PFEXEC "/usr/bin/pfexec" +#define ALL_PROFILE "All" + +#define ERR_PASSWD "can't get passwd entry" +#define ERR_MEM "can't allocate memory" +#define ERR_CWD "can't get current working directory" +#define ERR_PATH "resolved pathname too large" +#define ERR_PROFILE "not in profile" +#define ERR_REALPATH "can't get real path" + +#define NOATTRS 0 /* command in profile but w'out attributes */ + +#define SECPOLICY_WARN 1 +#define SECPOLICY_ERROR 2 + +/* + * Shell Policy Interface Functions + */ +extern void secpolicy_init(void); +extern int secpolicy_pfexec(const char *, char **, const char **); +extern void secpolicy_print(int, const char *); + + +#ifdef __cplusplus +} +#endif + +#endif /* _SH_POLICY_H */ diff --git a/usr/src/cmd/sh/stak.c b/usr/src/cmd/sh/stak.c new file mode 100644 index 0000000000..6e1f90eb5f --- /dev/null +++ b/usr/src/cmd/sh/stak.c @@ -0,0 +1,163 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1992 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * UNIX shell + */ + +#include "defs.h" + + +/* ======== storage allocation ======== */ + +unsigned char * +getstak(asize) /* allocate requested stack */ +int asize; +{ + register unsigned char *oldstak; + register int size; + + size = round(asize, BYTESPERWORD); + oldstak = stakbot; + staktop = stakbot += size; + if (staktop >= brkend) + growstak(staktop); + return(oldstak); +} + +/* + * set up stack for local use + * should be followed by `endstak' + */ +unsigned char * +locstak() +{ + if (brkend - stakbot < BRKINCR) + { + if (setbrk(brkincr) == -1) + error(nostack); + if (brkincr < BRKMAX) + brkincr += 256; + } + return(stakbot); +} + +void +growstak(newtop) +unsigned char *newtop; +{ + register unsigned incr; + + incr = (unsigned)round(newtop - brkend + 1, BYTESPERWORD); + if (brkincr > incr) + incr = brkincr; + if (setbrk(incr) == -1) + error(nospace); +} + +unsigned char * +savstak() +{ + assert(staktop == stakbot); + return(stakbot); +} + +unsigned char * +endstak(argp) /* tidy up after `locstak' */ +register unsigned char *argp; +{ + register unsigned char *oldstak; + + if (argp >= brkend) + growstak(argp); + *argp++ = 0; + oldstak = stakbot; + stakbot = staktop = (unsigned char *)round(argp, BYTESPERWORD); + if (staktop >= brkend) + growstak(staktop); + return(oldstak); +} + +tdystak(x) /* try to bring stack back to x */ +register unsigned char *x; +{ + while ((unsigned char *)stakbsy > x) + { + free(stakbsy); + stakbsy = stakbsy->word; + } + staktop = stakbot = max(x, stakbas); + rmtemp(x); +} + +stakchk() +{ + if ((brkend - stakbas) > BRKINCR + BRKINCR) + setbrk(-BRKINCR); +} + +unsigned char * +cpystak(x) +unsigned char *x; +{ + return(endstak(movstrstak(x, locstak()))); +} + +unsigned char * +movstrstak(a, b) +register unsigned char *a, *b; +{ + do + { + if (b >= brkend) + growstak(b); + } + while (*b++ = *a++); + return(--b); +} + +/* + * Copy s2 to s1, always copy n bytes. + * Return s1 + */ +unsigned char * +memcpystak(s1, s2, n) +register unsigned char *s1, *s2; +register int n; +{ + register unsigned char *os1 = s1; + + while (--n >= 0) { + if (s1 >= brkend) + growstak(s1); + *s1++ = *s2++; + } + return (os1); +} diff --git a/usr/src/cmd/sh/stak.h b/usr/src/cmd/sh/stak.h new file mode 100644 index 0000000000..f667f32c4c --- /dev/null +++ b/usr/src/cmd/sh/stak.h @@ -0,0 +1,115 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * UNIX shell + */ + +/* To use stack as temporary workspace across + * possible storage allocation (eg name lookup) + * a) get ptr from `relstak' + * b) can now use `pushstak' + * c) then reset with `setstak' + * d) `absstak' gives real address if needed + */ +#define relstak() (staktop-stakbot) +#define absstak(x) (stakbot+Rcheat(x)) +#define setstak(x) (staktop=absstak(x)) +#define pushstak(c) (*staktop++=(c)) +#define zerostak() (*staktop=0) + +/* Used to address an item left on the top of + * the stack (very temporary) + */ +#define curstak() (staktop) + +/* `usestak' before `pushstak' then `fixstak' + * These routines are safe against heap + * being allocated. + */ +#define usestak() {locstak();} + +/* for local use only since it hands + * out a real address for the stack top + */ +extern unsigned char *locstak(); + +/* Will allocate the item being used and return its + * address (safe now). + */ +#define fixstak() endstak(staktop) + +/* For use after `locstak' to hand back + * new stack top and then allocate item + */ +extern unsigned char *endstak(); + +/* Copy a string onto the stack and + * allocate the space. + */ +extern unsigned char *cpystak(); + +/* Copy a string onto the stack, checking for stack overflow + * as the copy is done. Same calling sequence as "movstr". + */ +extern unsigned char *movstrstak(); + +/* Move bytes onto the stack, checking for stack overflow + * as the copy is done. Same calling sequence as the C + * library routine "memcpy". + */ +extern unsigned char *memcpystak(); + +/* Allocate given ammount of stack space */ +extern unsigned char *getstak(); + +/* Grow the data segment to include a given location */ +extern void growstak(); + +/* A chain of ptrs of stack blocks that + * have become covered by heap allocation. + * `tdystak' will return them to the heap. + */ +extern struct blk *stakbsy; + +/* Base of the entire stack */ +extern unsigned char *stakbas; + +/* Top of entire stack */ +extern unsigned char *brkend; + +/* Base of current item */ +extern unsigned char *stakbot; + +/* Top of current item */ +extern unsigned char *staktop; + +/* Used with tdystak */ +extern unsigned char *savstak(); diff --git a/usr/src/cmd/sh/string.c b/usr/src/cmd/sh/string.c new file mode 100644 index 0000000000..f046a3607f --- /dev/null +++ b/usr/src/cmd/sh/string.c @@ -0,0 +1,105 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8.2.1 */ +/* + * UNIX shell + */ + +#include "defs.h" + + +/* ======== general purpose string handling ======== */ + + +unsigned char * +movstr(a, b) +register unsigned char *a, *b; +{ + while (*b++ = *a++); + return(--b); +} + +any(c, s) +wchar_t c; +unsigned char *s; +{ + register unsigned int d; + + while (d = *s++) + { + if (d == c) + return(TRUE); + } + return(FALSE); +} + +int anys(c, s) +unsigned char *c, *s; +{ + wchar_t f, e; + register wchar_t d; + register int n; + if((n = mbtowc(&f, (char *)c, MULTI_BYTE_MAX)) <= 0) + return(FALSE); + d = f; + while(1) { + if((n = mbtowc(&e, (char *)s, MULTI_BYTE_MAX)) <= 0) + return(FALSE); + if(d == e) + return(TRUE); + s += n; + } +} + +int cf(s1, s2) +register unsigned char *s1, *s2; +{ + while (*s1++ == *s2) + if (*s2++ == 0) + return(0); + return(*--s1 - *s2); +} + +int length(as) +unsigned char *as; +{ + register unsigned char *s; + + if (s = as) + while (*s++); + return(s - as); +} + +unsigned char * +movstrn(a, b, n) + register unsigned char *a, *b; + register int n; +{ + while ((n-- > 0) && *a) + *b++ = *a++; + + return(b); +} diff --git a/usr/src/cmd/sh/sym.h b/usr/src/cmd/sh/sym.h new file mode 100644 index 0000000000..610a1056bd --- /dev/null +++ b/usr/src/cmd/sh/sym.h @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */ +/* + * UNIX shell + */ + + +/* symbols for parsing */ +#define DOSYM 0405 +#define FISYM 0420 +#define EFSYM 0422 +#define ELSYM 0421 +#define INSYM 0412 +#define BRSYM 0406 +#define KTSYM 0450 +#define THSYM 0444 +#define ODSYM 0441 +#define ESSYM 0442 +#define IFSYM 0436 +#define FORSYM 0435 +#define WHSYM 0433 +#define UNSYM 0427 +#define CASYM 0417 + +#define SYMREP 04000 +#define ECSYM (SYMREP|';') +#define ANDFSYM (SYMREP|'&') +#define ORFSYM (SYMREP|'|') +#define APPSYM (SYMREP|'>') +#define DOCSYM (SYMREP|'<') +#define EOFSYM 02000 +#define SYMFLG 0400 + +/* arg to `cmd' */ +#define NLFLG 1 +#define MTFLG 2 + +/* for peekc */ +#define MARK 0x80000000 + +/* odd chars */ +#define DQUOTE '"' +#define SQUOTE '`' +#define LITERAL '\'' +#define DOLLAR '$' +#define ESCAPE '\\' +#define BRACE '{' +#define COMCHAR '#' diff --git a/usr/src/cmd/sh/test.c b/usr/src/cmd/sh/test.c new file mode 100644 index 0000000000..513df5a3b5 --- /dev/null +++ b/usr/src/cmd/sh/test.c @@ -0,0 +1,280 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * test expression + * [ expression ] + */ + +#include "defs.h" +#include <sys/types.h> +#include <sys/stat.h> + +extern int lstat(); +int ap, ac; +unsigned char **av; + +test(argn, com) +unsigned char *com[]; +int argn; +{ + ac = argn; + av = com; + ap = 1; + if (eq(com[0],"[")) + { + if (!eq(com[--ac], "]")) + failed("test", "] missing"); + } + com[ac] = 0; + if (ac <= 1) + return(1); + return(exp() ? 0 : 1); +} + +unsigned char * +nxtarg(mt) +{ + if (ap >= ac) + { + if (mt) + { + ap++; + return(0); + } + failed("test", "argument expected"); + } + return(av[ap++]); +} + +exp() +{ + int p1; + unsigned char *p2; + + p1 = e1(); + p2 = nxtarg(1); + if (p2 != 0) + { + if (eq(p2, "-o")) + return(p1 | exp()); + + /* if (!eq(p2, ")")) + failed("test", synmsg); */ + } + ap--; + return(p1); +} + +e1() +{ + int p1; + unsigned char *p2; + + p1 = e2(); + p2 = nxtarg(1); + + if ((p2 != 0) && eq(p2, "-a")) + return(p1 & e1()); + ap--; + return(p1); +} + +e2() +{ + if (eq(nxtarg(0), "!")) + return(!e3()); + ap--; + return(e3()); +} + +e3() +{ + int p1; + register unsigned char *a; + unsigned char *p2; + longlong_t ll_1, ll_2; + + a = nxtarg(0); + if (eq(a, "(")) + { + p1 = exp(); + if (!eq(nxtarg(0), ")")) + failed("test",") expected"); + return(p1); + } + p2 = nxtarg(1); + ap--; + if ((p2 == 0) || (!eq(p2, "=") && !eq(p2, "!="))) + { + if (eq(a, "-r")) + return(chk_access(nxtarg(0), S_IREAD, 0) == 0); + if (eq(a, "-w")) + return(chk_access(nxtarg(0), S_IWRITE, 0) == 0); + if (eq(a, "-x")) + return(chk_access(nxtarg(0), S_IEXEC, 0) == 0); + if (eq(a, "-d")) + return(filtyp(nxtarg(0), S_IFDIR)); + if (eq(a, "-c")) + return(filtyp(nxtarg(0), S_IFCHR)); + if (eq(a, "-b")) + return(filtyp(nxtarg(0), S_IFBLK)); + if (eq(a, "-f")) + if (ucb_builtins) { + struct stat statb; + + return(stat((char *)nxtarg(0), &statb) >= 0 && + (statb.st_mode & S_IFMT) != S_IFDIR); + } + else + return(filtyp(nxtarg(0), S_IFREG)); + if (eq(a, "-u")) + return(ftype(nxtarg(0), S_ISUID)); + if (eq(a, "-g")) + return(ftype(nxtarg(0), S_ISGID)); + if (eq(a, "-k")) + return(ftype(nxtarg(0), S_ISVTX)); + if (eq(a, "-p")) + return(filtyp(nxtarg(0), S_IFIFO)); + if (eq(a, "-h") || eq(a, "-L")) + return(filtyp(nxtarg(0), S_IFLNK)); + if (eq(a, "-s")) + return(fsizep(nxtarg(0))); + if (eq(a, "-t")) + { + if (ap >= ac) /* no args */ + return(isatty(1)); + else if (eq((a = nxtarg(0)), "-a") || eq(a, "-o")) + { + ap--; + return(isatty(1)); + } + else + return(isatty(atoi((char *)a))); + } + if (eq(a, "-n")) + return(!eq(nxtarg(0), "")); + if (eq(a, "-z")) + return(eq(nxtarg(0), "")); + } + + p2 = nxtarg(1); + if (p2 == 0) + return(!eq(a, "")); + if (eq(p2, "-a") || eq(p2, "-o")) + { + ap--; + return(!eq(a, "")); + } + if (eq(p2, "=")) + return(eq(nxtarg(0), a)); + if (eq(p2, "!=")) + return(!eq(nxtarg(0), a)); + ll_1 = strtoll((char *)a, NULL, 10); + ll_2 = strtoll((char *)nxtarg(0), NULL, 10); + if (eq(p2, "-eq")) + return (ll_1 == ll_2); + if (eq(p2, "-ne")) + return (ll_1 != ll_2); + if (eq(p2, "-gt")) + return (ll_1 > ll_2); + if (eq(p2, "-lt")) + return (ll_1 < ll_2); + if (eq(p2, "-ge")) + return (ll_1 >= ll_2); + if (eq(p2, "-le")) + return (ll_1 <= ll_2); + + bfailed(btest, badop, p2); +/* NOTREACHED */ +} + + +ftype(f, field) +unsigned char *f; +int field; +{ + struct stat statb; + + if (stat((char *)f, &statb) < 0) + return(0); + if ((statb.st_mode & field) == field) + return(1); + return(0); +} + +filtyp(f,field) +unsigned char *f; +int field; +{ + struct stat statb; + int (*statf)() = (field == S_IFLNK) ? lstat : stat; + + if ((*statf)(f, &statb) < 0) + return(0); + if ((statb.st_mode & S_IFMT) == field) + return(1); + else + return(0); +} + + + +fsizep(f) +unsigned char *f; +{ + struct stat statb; + + if (stat((char *)f, &statb) < 0) + return(0); + return(statb.st_size > 0); +} + +/* + * fake diagnostics to continue to look like original + * test(1) diagnostics + */ +bfailed(s1, s2, s3) +unsigned char *s1; +unsigned char *s2; +unsigned char *s3; +{ + prp(); + prs(s1); + if (s2) + { + prs(colon); + prs(s2); + prs(s3); + } + newline(); + exitsh(ERROR); +} diff --git a/usr/src/cmd/sh/timeout.h b/usr/src/cmd/sh/timeout.h new file mode 100644 index 0000000000..648d2990e2 --- /dev/null +++ b/usr/src/cmd/sh/timeout.h @@ -0,0 +1,32 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */ +/* + * UNIX shell + */ + +#define TIMEOUT 0 /* seconds elapsing before log-off (normal) */ +#define MAILCHECK "600" /* 10 minutes */ diff --git a/usr/src/cmd/sh/ulimit.c b/usr/src/cmd/sh/ulimit.c new file mode 100644 index 0000000000..7c3084a0e1 --- /dev/null +++ b/usr/src/cmd/sh/ulimit.c @@ -0,0 +1,241 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996,1997 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ident "%Z%%M% %I% %E% SMI" + +/* + * ulimit builtin + */ + +#include <sys/resource.h> +#include <stdlib.h> +#include "defs.h" + +/* + * order is important in this table! it is indexed by resource ID. + */ + +static struct rlimtab { + char *name; + char *scale; + rlim_t divisor; +} rlimtab[] = { +/* RLIMIT_CPU */ "time", "seconds", 1, +/* RLIMIT_FSIZE */ "file", "blocks", 512, +/* RLIMIT_DATA */ "data", "kbytes", 1024, +/* RLIMIT_STACK */ "stack", "kbytes", 1024, +/* RLIMIT_CORE */ "coredump", "blocks", 512, +/* RLIMIT_NOFILE */ "nofiles", "descriptors", 1, +/* RLIMIT_VMEM */ "memory", "kbytes", 1024, +}; + +void +sysulimit(int argc, char **argv) +{ + extern int opterr, optind; + int savopterr, savoptind, savsp; + char *savoptarg; + char *args; + int hard, soft, cnt, c, res; + rlim_t limit, new_limit; + struct rlimit rlimit; + char resources[RLIM_NLIMITS]; + + for (res = 0; res < RLIM_NLIMITS; res++) { + resources[res] = 0; + } + + savoptind = optind; + savopterr = opterr; + savsp = _sp; + savoptarg = optarg; + optind = 1; + _sp = 1; + opterr = 0; + hard = 0; + soft = 0; + cnt = 0; + + while ((c = getopt(argc, argv, "HSacdfnstv")) != -1) { + switch (c) { + case 'S': + soft++; + continue; + case 'H': + hard++; + continue; + case 'a': + for (res = 0; res < RLIM_NLIMITS; res++) { + resources[res]++; + } + cnt = RLIM_NLIMITS; + continue; + case 'c': + res = RLIMIT_CORE; + break; + case 'd': + res = RLIMIT_DATA; + break; + case 'f': + res = RLIMIT_FSIZE; + break; + case 'n': + res = RLIMIT_NOFILE; + break; + case 's': + res = RLIMIT_STACK; + break; + case 't': + res = RLIMIT_CPU; + break; + case 'v': + res = RLIMIT_VMEM; + break; + case '?': + failure(usage, ulimuse); + goto err; + } + resources[res]++; + cnt++; + } + + if (cnt == 0) { + resources[res = RLIMIT_FSIZE]++; + cnt++; + } + + /* + * if out of arguments, then print the specified resources + */ + + if (optind == argc) { + if (!hard && !soft) { + soft++; + } + for (res = 0; res < RLIM_NLIMITS; res++) { + if (resources[res] == 0) { + continue; + } + if (getrlimit(res, &rlimit) < 0) { + continue; + } + if (cnt > 1) { + prs_buff(rlimtab[res].name); + prc_buff('('); + prs_buff(rlimtab[res].scale); + prc_buff(')'); + prc_buff(' '); + } + if (soft) { + if (rlimit.rlim_cur == RLIM_INFINITY) { + prs_buff("unlimited"); + } else { + prull_buff(rlimit.rlim_cur / + rlimtab[res].divisor); + } + } + if (hard && soft) { + prc_buff(':'); + } + if (hard) { + if (rlimit.rlim_max == RLIM_INFINITY) { + prs_buff("unlimited"); + } else { + prull_buff(rlimit.rlim_max / + rlimtab[res].divisor); + } + } + prc_buff('\n'); + } + goto err; + } + + if (cnt > 1 || optind + 1 != argc) { + failure(usage, ulimuse); + goto err; + } + + if (eq(argv[optind], "unlimited")) { + limit = RLIM_INFINITY; + } else { + args = argv[optind]; + + new_limit = limit = 0; + do { + if (*args < '0' || *args > '9') { + failure(argv[0], badulimit); + goto err; + } + /* Check for overflow! */ + new_limit = (limit * 10) + (*args - '0'); + if (new_limit >= limit) { + limit = new_limit; + } else { + failure(argv[0], badulimit); + goto err; + } + } while (*++args); + + /* Check for overflow! */ + new_limit = limit * rlimtab[res].divisor; + if (new_limit >= limit) { + limit = new_limit; + } else { + failure(argv[0], badulimit); + goto err; + } + } + + if (getrlimit(res, &rlimit) < 0) { + failure(argv[0], badulimit); + goto err; + } + + if (!hard && !soft) { + hard++; + soft++; + } + if (hard) { + rlimit.rlim_max = limit; + } + if (soft) { + rlimit.rlim_cur = limit; + } + + if (setrlimit(res, &rlimit) < 0) { + failure(argv[0], badulimit); + } + +err: + optind = savoptind; + opterr = savopterr; + _sp = savsp; + optarg = savoptarg; +} diff --git a/usr/src/cmd/sh/word.c b/usr/src/cmd/sh/word.c new file mode 100644 index 0000000000..f072f52b5a --- /dev/null +++ b/usr/src/cmd/sh/word.c @@ -0,0 +1,456 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright (c) 1996, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.11.2.2 */ +/* + * UNIX shell + */ + +#include "defs.h" +#include "sym.h" +#include <errno.h> +#include <fcntl.h> + +static int readb(struct fileblk *, int, int); + +/* ======== character handling for command lines ======== */ + + +word() +{ + register unsigned int c, d, cc; + struct argnod *arg = (struct argnod *)locstak(); + register unsigned char *argp = arg->argval; + unsigned char *oldargp; + int alpha = 1; + unsigned char *pc; + + wdnum = 0; + wdset = 0; + + while (1) + { + while (c = nextwc(), space(c)) /* skipc() */ + ; + + if (c == COMCHAR) + { + while ((c = readwc()) != NL && c != EOF); + peekc = c; + } + else + { + break; /* out of comment - white space loop */ + } + } + if (!eofmeta(c)) + { + do + { + if (c == LITERAL) + { + oldargp = argp; + while ((c = readwc()) && c != LITERAL){ + /* + * quote each character within + * single quotes + */ + pc = readw(c); + if (argp >= brkend) + growstak(argp); + *argp++='\\'; + /* Pick up rest of multibyte character */ + if (c == NL) + chkpr(); + while (c = *pc++) { + if (argp >= brkend) + growstak(argp); + *argp++ = (unsigned char)c; + } + } + if (argp == oldargp) { /* null argument - '' */ + /* + * Word will be represented by quoted null + * in macro.c if necessary + */ + if (argp >= brkend) + growstak(argp); + *argp++ = '"'; + if (argp >= brkend) + growstak(argp); + *argp++ = '"'; + } + } + else + { + if (c == 0) { + if (argp >= brkend) + growstak(argp); + *argp++ = 0; + } else { + pc = readw(c); + while (*pc) { + if (argp >= brkend) + growstak(argp); + *argp++ = *pc++; + } + } + if (c == '\\') { + if ((cc = readwc()) == 0) { + if (argp >= brkend) + growstak(argp); + *argp++ = 0; + } else { + pc = readw(cc); + while (*pc) { + if (argp >= brkend) + growstak(argp); + *argp++ = *pc++; + } + } + } + if (c == '=') + wdset |= alpha; + if (!alphanum(c)) + alpha = 0; + if (qotchar(c)) + { + d = c; + for (;;) + { + if ((c = nextwc()) == 0) { + if (argp >= brkend) + growstak(argp); + *argp++ = 0; + } else { + pc = readw(c); + while (*pc) { + if (argp >= brkend) + growstak(argp); + *argp++ = *pc++; + } + } + if (c == 0 || c == d) + break; + if (c == NL) + chkpr(); + /* + * don't interpret quoted + * characters + */ + if (c == '\\') { + if ((cc = readwc()) == 0) { + if (argp >= brkend) + growstak(argp); + *argp++ = 0; + } else { + pc = readw(cc); + while (*pc) { + if (argp >= brkend) + growstak(argp); + *argp++ = *pc++; + } + } + } + } + } + } + } while ((c = nextwc(), !eofmeta(c))); + argp = endstak(argp); + if (!letter(arg->argval[0])) + wdset = 0; + + peekn = c | MARK; + if (arg->argval[1] == 0 && + (d = arg->argval[0], digit(d)) && + (c == '>' || c == '<')) + { + word(); + wdnum = d - '0'; + }else{ /* check for reserved words */ + if (reserv == FALSE || + (wdval = syslook(arg->argval, + reserved, no_reserved)) == 0) { + wdval = 0; + } + /* set arg for reserved words too */ + wdarg = arg; + } + }else if (dipchar(c)){ + if ((d = nextwc()) == c) + { + wdval = c | SYMREP; + if (c == '<') + { + if ((d = nextwc()) == '-') + wdnum |= IOSTRIP; + else + peekn = d | MARK; + } + } + else + { + peekn = d | MARK; + wdval = c; + } + } + else + { + if ((wdval = c) == EOF) + wdval = EOFSYM; + if (iopend && eolchar(c)) + { + struct ionod *tmp_iopend; + tmp_iopend = iopend; + iopend = 0; + copy(tmp_iopend); + } + } + reserv = FALSE; + return (wdval); +} + +unsigned int skipwc() +{ + register unsigned int c; + + while (c = nextwc(), space(c)) + ; + return (c); +} + +unsigned int nextwc() +{ + register unsigned int c, d; + +retry: + if ((d = readwc()) == ESCAPE) { + if ((c = readwc()) == NL) { + chkpr(); + goto retry; + } + peekc = c | MARK; + } + return (d); +} + +unsigned char *readw(d) +wchar_t d; +{ + static unsigned char c[MULTI_BYTE_MAX + 1]; + int length; + wchar_t l; + if (isascii(d)) { + c[0] = d; + c[1] = '\0'; + return (c); + } + + length = wctomb((char *)c, d); + if (length <= 0) { + c[0] = (unsigned char)d; + length = 1; + } + c[length] = '\0'; + return (c); +} + +unsigned int +readwc() +{ + wchar_t c; + int len; + struct fileblk *f; + int mbmax = MB_CUR_MAX; + int i, mlen; + + if (peekn) { + c = peekn & 0x7fffffff; + peekn = 0; + return (c); + } + if (peekc) { + c = peekc & 0x7fffffff; + peekc = 0; + return (c); + } + f = standin; + +retry: + if (f->fend > f->fnxt) { + /* + * something in buffer + */ + if (*f->fnxt == 0) { + f->fnxt++; + f->nxtoff++; + if (f->feval == 0) + goto retry; /* = c = readc(); */ + if (estabf(*f->feval++)) + c = EOF; + else + c = SPACE; + if (flags & readpr && standin->fstak == 0) + prc(c); + if (c == NL) + f->flin++; + return (c); + } + + if (isascii(c = (unsigned char)*f->fnxt)) { + f->fnxt++; + f->nxtoff++; + if (flags & readpr && standin->fstak == 0) + prc(c); + if (c == NL) + f->flin++; + return (c); + } + + for (i = 1; i <= mbmax; i++) { + int rest; + if ((rest = f->fend - f->fnxt) < i) { + /* + * not enough bytes available + * f->fsiz could be BUFFERSIZE or 1 + * since mbmax is enough smaller than BUFFERSIZE, + * this loop won't overrun the f->fbuf buffer. + */ + len = readb(f, + (f->fsiz == 1) ? 1 : (f->fsiz - rest), + rest); + if (len == 0) + break; + } + mlen = mbtowc(&c, (char *)f->fnxt, i); + if (mlen > 0) + break; + } + + if (i > mbmax) { + /* + * enough bytes available but cannot be converted to + * a valid wchar. + */ + c = (unsigned char)*f->fnxt; + mlen = 1; + } + + f->fnxt += mlen; + f->nxtoff += mlen; + if (flags & readpr && standin->fstak == 0) + prwc(c); + if (c == NL) + f->flin++; + return (c); + } + + if (f->feof || f->fdes < 0){ + c = EOF; + f->feof++; + return (c); + } + + if (readb(f, f->fsiz, 0) <= 0){ + if (f->fdes != input || !isatty(input)) { + close(f->fdes); + f->fdes = -1; + } + f->feof++; + c = EOF; + return (c); + } + goto retry; +} + +static int +readb(struct fileblk *f, int toread, int rest) +{ + int len; + int fflags; + + if (rest) { + /* + * copies the remaining 'rest' bytes from f->fnxt + * to f->fbuf + */ + (void) memcpy(f->fbuf, f->fnxt, rest); + f->fnxt = f->fbuf; + f->fend = f->fnxt + rest; + f->nxtoff = 0; + f->endoff = rest; + if (f->fbuf[rest - 1] == '\n') { + /* + * if '\n' found, it should be + * a bondary of multibyte char. + */ + return (rest); + } + } + +retry: + do { + if (trapnote & SIGSET) { + newline(); + sigchk(); + } else if ((trapnote & TRAPSET) && (rwait > 0)) { + newline(); + chktrap(); + clearup(); + } + } while ((len = read(f->fdes, f->fbuf + rest, toread)) < 0 && trapnote); + /* + * if child sets O_NDELAY or O_NONBLOCK on stdin + * and exited then turn the modes off and retry + */ + if (len == 0) { + if (((flags & intflg) || + ((flags & oneflg) == 0 && isatty(input) && + (flags & stdflg))) && + ((fflags = fcntl(f->fdes, F_GETFL, 0)) & O_NDELAY)) { + fflags &= ~O_NDELAY; + fcntl(f->fdes, F_SETFL, fflags); + goto retry; + } + } else if (len < 0) { + if (errno == EAGAIN) { + fflags = fcntl(f->fdes, F_GETFL, 0); + fflags &= ~O_NONBLOCK; + fcntl(f->fdes, F_SETFL, fflags); + goto retry; + } + len = 0; + } + f->fnxt = f->fbuf; + f->fend = f->fnxt + (len + rest); + f->nxtoff = 0; + f->endoff = len + rest; + return (len + rest); +} diff --git a/usr/src/cmd/sh/xec.c b/usr/src/cmd/sh/xec.c new file mode 100644 index 0000000000..3de1014bc6 --- /dev/null +++ b/usr/src/cmd/sh/xec.c @@ -0,0 +1,510 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 1996,2002-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * + * UNIX shell + * + */ + + +#include "defs.h" +#include <errno.h> +#include "sym.h" +#include "hash.h" +#include <sys/types.h> +#include <sys/times.h> + +pid_t parent; + +/* ======== command execution ======== */ + + +execute(argt, xflags, errorflg, pf1, pf2) +struct trenod *argt; +int *pf1, *pf2; +{ + /* + * `stakbot' is preserved by this routine + */ + register struct trenod *t; + unsigned char *sav = savstak(); + + sigchk(); + if (!errorflg) + flags &= ~errflg; + + if ((t = argt) && execbrk == 0) { + register int treeflgs; + register unsigned char **com; + int type; + short pos; + + treeflgs = t->tretyp; + type = treeflgs & COMMSK; + + switch (type) + { + case TFND: + { + struct fndnod *f = (struct fndnod *)t; + struct namnod *n = lookup(f->fndnam); + + exitval = 0; + + if (n->namflg & N_RDONLY) + failed(n->namid, wtfailed); + + if (flags & rshflg && (n == &pathnod || + eq(n->namid, "SHELL"))) + failed(n->namid, restricted); + if (n->namflg & N_FUNCTN) + freefunc(n); + else + { + free(n->namval); + free(n->namenv); + + n->namval = 0; + n->namflg &= ~(N_EXPORT | N_ENVCHG); + } + + if (funcnt) + f->fndval->tretyp++; + + n->namenv = (unsigned char *)f->fndval; + attrib(n, N_FUNCTN); + hash_func(n->namid); + break; + } + + case TCOM: + { + unsigned char *a1, *name; + int argn, internal; + struct argnod *schain = gchain; + struct ionod *io = t->treio; + short cmdhash; + short comtype; + + exitval = 0; + + gchain = 0; + argn = getarg(t); + com = scan(argn); + a1 = com[1]; + gchain = schain; + + if (argn != 0) + cmdhash = pathlook(com[0], 1, comptr(t)->comset); + + if (argn == 0 || (comtype = hashtype(cmdhash)) == BUILTIN) { + setlist(comptr(t)->comset, 0); + } + + if (argn && (flags&noexec) == 0) + { + + /* print command if execpr */ + if (flags & execpr) + execprint(com); + + if (comtype == NOTFOUND) + { + pos = hashdata(cmdhash); + if (pos == 1) + failure(*com, notfound); + else if (pos == 2) + failure(*com, badexec); + else + failure(*com, badperm); + break; + } + + else if (comtype == PATH_COMMAND) + { + pos = -1; + } + + else if (comtype & (COMMAND | REL_COMMAND)) + { + pos = hashdata(cmdhash); + } + + else if (comtype == BUILTIN) { + builtin(hashdata(cmdhash),argn,com,t); + freejobs(); + break; + } + else if (comtype == FUNCTION) + { + struct dolnod *olddolh; + struct namnod *n, *opt; + short index; + unsigned char **olddolv = dolv; + int olddolc = dolc; + n = findnam(com[0]); + /* save current positional parameters */ + olddolh = (struct dolnod *)savargs(funcnt); + funcnt++; + index = initio(io, 1); + setargs(com); + execute((struct trenod *)(n->namenv), xflags, errorflg, pf1, pf2); + execbrk = 0; + restore(index); + (void) restorargs(olddolh, funcnt); + dolv = olddolv; + dolc = olddolc; + funcnt--; + + break; + } + } + else if (t->treio == 0) + { + chktrap(); + break; + } + + } + + case TFORK: + { + int monitor = 0; + int linked = 0; + + exitval = 0; + + if (!(xflags & XEC_EXECED) || treeflgs&(FPOU|FAMP)) + { + + int forkcnt = 1; + + if (!(treeflgs&FPOU)) + { + monitor = (!(xflags & XEC_NOSTOP) + && (flags&(monitorflg|jcflg|jcoff)) + == (monitorflg|jcflg)); + if (monitor) { + int savefd; + unsigned char *savebot; + savefd = setb(-1); + savebot = stakbot; + prcmd(t); + (void)setb(savefd); + allocjob(savebot, cwdget(), monitor); + } else + allocjob("", "", 0); + + } + + if (treeflgs & (FPOU|FAMP)) { + link_iodocs(iotemp); + linked = 1; + } + + while ((parent = fork()) == -1) + { + /* + * FORKLIM is the max period between forks - + * power of 2 usually. Currently shell tries + * after 2,4,8,16, and 32 seconds and then quits + */ + + if ((forkcnt = (forkcnt * 2)) > FORKLIM) + { + switch (errno) + { + case ENOMEM: + deallocjob(); + error(noswap); + break; + default: + deallocjob(); + error(nofork); + break; + } + } else if (errno == EPERM) { + deallocjob(); + error(eacces); + break; + } + sigchk(); + sleep(forkcnt); + } + + if (parent) { + if (monitor) + setpgid(parent, 0); + if (treeflgs & FPIN) + closepipe(pf1); + if (!(treeflgs&FPOU)) { + postjob(parent,!(treeflgs&FAMP)); + freejobs(); + } + chktrap(); + break; + } + mypid = getpid(); + } + + /* + * Forked process: assume it is not a subshell for + * now. If it is, the presence of a left parenthesis + * will trigger the jcoff flag to be turned off. + * When jcoff is turned on, monitoring is not going on + * and waitpid will not look for WUNTRACED. + */ + + flags |= (forked|jcoff); + + fiotemp = 0; + + if (linked == 1) { + swap_iodoc_nm(iotemp); + xflags |= XEC_LINKED; + } else if (!(xflags & XEC_LINKED)) + iotemp = 0; +#ifdef ACCT + suspacct(); +#endif + settmp(); + oldsigs(); + + if (!(treeflgs & FPOU)) + makejob(monitor, !(treeflgs & FAMP)); + + /* + * pipe in or out + */ + if (treeflgs & FPIN) + { + renamef(pf1[INPIPE], 0); + close(pf1[OTPIPE]); + } + + if (treeflgs & FPOU) + { + close(pf2[INPIPE]); + renamef(pf2[OTPIPE], 1); + } + + /* + * io redirection + */ + initio(t->treio, 0); + + if (type == TFORK) + execute(forkptr(t)->forktre, xflags | XEC_EXECED, errorflg); + else if (com[0] != ENDARGS) + { + eflag = 0; + setlist(comptr(t)->comset, N_EXPORT); + rmtemp(0); + clearjobs(); + execa(com, pos); + } + done(0); + } + + case TPAR: + /* Forked process is subshell: may want job control */ + flags &= ~jcoff; + clearjobs(); + execute(parptr(t)->partre, xflags, errorflg); + done(0); + + case TFIL: + { + int pv[2]; + + chkpipe(pv); + if (execute(lstptr(t)->lstlef, xflags & XEC_NOSTOP, errorflg, pf1, pv) == 0) + execute(lstptr(t)->lstrit, xflags, errorflg, pv, pf2); + else + closepipe(pv); + } + break; + + case TLST: + execute(lstptr(t)->lstlef, xflags&XEC_NOSTOP, errorflg); + /* Update errorflg if set -e is invoked in the sub-sh*/ + execute(lstptr(t)->lstrit, xflags, (errorflg | (eflag & errflg))); + break; + + case TAND: + case TORF: + { + register xval; + xval = execute(lstptr(t)->lstlef, XEC_NOSTOP, 0); + if ((xval == 0) == (type == TAND)) + execute(lstptr(t)->lstrit, xflags|XEC_NOSTOP, errorflg); + break; + } + + case TFOR: + { + struct namnod *n = lookup(forptr(t)->fornam); + unsigned char **args; + struct dolnod *argsav = 0; + + if (forptr(t)->forlst == 0) + { + args = dolv + 1; + argsav = useargs(); + } + else + { + struct argnod *schain = gchain; + + gchain = 0; + args = scan(getarg(forptr(t)->forlst)); + gchain = schain; + } + loopcnt++; + while (*args != ENDARGS && execbrk == 0) + { + assign(n, *args++); + execute(forptr(t)->fortre, XEC_NOSTOP, errorflg); + if (breakcnt < 0) + execbrk = (++breakcnt != 0); + } + if (breakcnt > 0) + execbrk = (--breakcnt != 0); + + loopcnt--; + if(argsav) + argfor = (struct dolnod *)freeargs(argsav); + } + break; + + case TWH: + case TUN: + { + int i = 0; + + loopcnt++; + while (execbrk == 0 && (execute(whptr(t)->whtre, + XEC_NOSTOP, 0) == 0) == (type == TWH) && + (flags&noexec) == 0) +{ + i = execute(whptr(t)->dotre, XEC_NOSTOP, errorflg); + if (breakcnt < 0) + execbrk = (++breakcnt != 0); + } + if (breakcnt > 0) + execbrk = (--breakcnt != 0); + + loopcnt--; + exitval = i; + } + break; + + case TIF: + if (execute(ifptr(t)->iftre, XEC_NOSTOP, 0) == 0) + execute(ifptr(t)->thtre, xflags|XEC_NOSTOP, errorflg); + else if (ifptr(t)->eltre) + execute(ifptr(t)->eltre, xflags|XEC_NOSTOP, errorflg); + else + exitval = 0; /* force zero exit for if-then-fi */ + break; + + case TSW: + { + register unsigned char *r = mactrim(swptr(t)->swarg); + register struct regnod *regp; + + regp = swptr(t)->swlst; + while (regp) + { + struct argnod *rex = regp->regptr; + + while (rex) + { + register unsigned char *s; + + if (gmatch(r, s = macro(rex->argval)) || (trim(s), eq(r, s))) + { + execute(regp->regcom, XEC_NOSTOP, errorflg); + regp = 0; + break; + } + else + rex = rex->argnxt; + } + if (regp) + regp = regp->regnxt; + } + } + break; + } + exitset(); + } + sigchk(); + tdystak(sav); + flags |= eflag; + return(exitval); +} + +execexp(s, f) +unsigned char *s; +int f; +{ + struct fileblk fb; + + push(&fb); + if (s) + { + estabf(s); + fb.feval = (unsigned char **)(f); + } + else if (f >= 0) + initf(f); + execute(cmd(NL, NLFLG | MTFLG), 0, (int)(flags & errflg)); + pop(); +} + +execprint(com) + unsigned char **com; +{ + register int argn = 0; + unsigned char *s; + + prs(execpmsg); + while(com[argn] != ENDARGS) + { + s = com[argn++]; + write(output, s, length(s) - 1); + blank(); + } + + newline(); +} |
