summaryrefslogtreecommitdiff
path: root/usr/src/cmd/sh
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/sh
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/sh')
-rw-r--r--usr/src/cmd/sh/Makefile89
-rw-r--r--usr/src/cmd/sh/args.c416
-rw-r--r--usr/src/cmd/sh/blok.c349
-rw-r--r--usr/src/cmd/sh/bltin.c480
-rw-r--r--usr/src/cmd/sh/brkincr.h29
-rw-r--r--usr/src/cmd/sh/cmd.c619
-rw-r--r--usr/src/cmd/sh/ctype.c135
-rw-r--r--usr/src/cmd/sh/ctype.h116
-rw-r--r--usr/src/cmd/sh/defs.c114
-rw-r--r--usr/src/cmd/sh/defs.h498
-rw-r--r--usr/src/cmd/sh/dup.h32
-rw-r--r--usr/src/cmd/sh/echo.c174
-rw-r--r--usr/src/cmd/sh/error.c121
-rw-r--r--usr/src/cmd/sh/expand.c292
-rw-r--r--usr/src/cmd/sh/fault.c509
-rw-r--r--usr/src/cmd/sh/func.c453
-rw-r--r--usr/src/cmd/sh/hash.c166
-rw-r--r--usr/src/cmd/sh/hash.h57
-rw-r--r--usr/src/cmd/sh/hashserv.c539
-rw-r--r--usr/src/cmd/sh/io.c399
-rw-r--r--usr/src/cmd/sh/jobs.c1077
-rw-r--r--usr/src/cmd/sh/mac.h51
-rw-r--r--usr/src/cmd/sh/macro.c627
-rw-r--r--usr/src/cmd/sh/main.c647
-rw-r--r--usr/src/cmd/sh/mode.h253
-rw-r--r--usr/src/cmd/sh/msg.c266
-rw-r--r--usr/src/cmd/sh/name.c892
-rw-r--r--usr/src/cmd/sh/name.h49
-rw-r--r--usr/src/cmd/sh/print.c379
-rw-r--r--usr/src/cmd/sh/pwd.c299
-rw-r--r--usr/src/cmd/sh/service.c730
-rw-r--r--usr/src/cmd/sh/setbrk.c48
-rw-r--r--usr/src/cmd/sh/sh.xcl191
-rw-r--r--usr/src/cmd/sh/sh_policy.c198
-rw-r--r--usr/src/cmd/sh/sh_policy.h65
-rw-r--r--usr/src/cmd/sh/stak.c163
-rw-r--r--usr/src/cmd/sh/stak.h115
-rw-r--r--usr/src/cmd/sh/string.c105
-rw-r--r--usr/src/cmd/sh/sym.h72
-rw-r--r--usr/src/cmd/sh/test.c280
-rw-r--r--usr/src/cmd/sh/timeout.h32
-rw-r--r--usr/src/cmd/sh/ulimit.c241
-rw-r--r--usr/src/cmd/sh/word.c456
-rw-r--r--usr/src/cmd/sh/xec.c510
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();
+}