Submitted By: Tushar Teredesai <tushar@linuxfromscratch.org>
Date: 2003-10-02
Initial Package Version: 0.4.0
Origin: Slackware Source
Description: This is a collection of patches from Debian via Slackware
(don't you love Open Source:-) along with a minor bison related fix
from me. Additionally I removed debian specific stuff.
ash can be downloaded from any slackware mirror.

$LastChangedBy: bdubbs $
$Date: 2004-08-07 18:56:30 -0600 (Sat, 07 Aug 2004) $

diff -Nur ash-0.4.0.orig/Makefile ash-0.4.0.fixed/Makefile
--- ash-0.4.0.orig/Makefile	2001-01-12 10:50:34.000000000 -0600
+++ ash-0.4.0.fixed/Makefile	2003-10-01 21:08:15.000000000 -0500
@@ -7,56 +7,69 @@
 SHSRCS=	alias.c cd.c echo.c error.c eval.c exec.c expand.c \
 	histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
 	mystring.c options.c parser.c redir.c show.c trap.c output.c var.c \
-	test.c
-GENSRCS=arith.c arith.h arith_lex.c builtins.c builtins.h init.c nodes.c \
-	nodes.h syntax.c syntax.h token.h
+	test.c setmode.c test.c hetio.c
+GENSRCS=builtins.c builtins.h init.c nodes.c arith.c arith.h lex.yy.c \
+	nodes.h syntax.c syntax.h token.h signames.c
 SRCS=	${SHSRCS} ${GENSRCS}
 
-LDADD+=	-ll -ledit -ltermcap
-DPADD+=	${LIBL} ${LIBEDIT} ${LIBTERMCAP}
+OBJS=alias.o cd.o bltin/echo.o error.o eval.o exec.o expand.o \
+	histedit.o input.o jobs.o mail.o main.o memalloc.o miscbltin.o \
+	mystring.o options.o output.o parser.o redir.o show.o \
+	trap.o var.o bltin/test.o signames.o \
+	builtins.o init.o nodes.o syntax.o arith.o lex.yy.o \
+	setmode.o bltin/times.o hetio.o
+
+OPT_FLAGS=-O2 -g
+LDFLAGS=-g
+CFLAGS=$(OPT_FLAGS) -DSHELL -I. -DNO_HISTORY -DBSD=1 -DSMALL -D_GNU_SOURCE \
+	-DGLOB_BROKEN -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)= \
+	-DHETIO
+
+all: $(PROG)
+
+$(PROG): build-tools $(GENSRCS) $(GENHDRS) $(OBJS)
+	$(CC) $(LDFLAGS) -o $(PROG) $(OBJS) $(LDLIBS) -lfl
+	
+lex.yy.c: arith_lex.l
+	flex -8 $< 
+	
+CLEANFILES+= mkinit mkinit.o mknodes mknodes.o \
+	mksyntax mksyntax.o
+	
+CLEANFILES+= ${GENSRCS} ${GENHDRS}
+
+build-tools: mkinit mknodes mksyntax
+
+.ORDER: builtins.c builtins.h
+builtins.c builtins.h: mkbuiltins builtins.def
+	sh mkbuiltins shell.h builtins.def `pwd`
+
+INIT_DEPS = alias.c eval.c exec.c input.c jobs.c options.c parser.c \
+	redir.c trap.c var.c output.c
+	
+init.c: mkinit $(INIT_DEPS)
+	./mkinit $(INIT_DEPS)
+
+mkinit: mkinit.o
+mknodes: mknodes.o
+mksyntax: mksyntax.o
 
-LFLAGS= -8	# 8-bit lex scanner for arithmetic
-YFLAGS=	-d
-
-CPPFLAGS+=-DSHELL -I. -I${.CURDIR}
-
-.PATH:	${.CURDIR}/bltin ${.CURDIR}/../../usr.bin/printf ${.CURDIR}/../test
-
-CLEANFILES+= mkinit mknodes mksyntax
-CLEANFILES+= ${GENSRCS} y.tab.h
-
-token.h: mktokens
-	sh ${.ALLSRC}
-
-builtins.c builtins.h: mkbuiltins shell.h builtins.def
-	sh ${.ALLSRC} ${.OBJDIR}
-
-init.c: mkinit ${SHSRCS}
-	./${.ALLSRC}
+signames.c: mksignames
+	./mksignames
 
 nodes.c nodes.h: mknodes nodetypes nodes.c.pat
-	./${.ALLSRC}
+	./mknodes ./nodetypes ./nodes.c.pat
 
 syntax.c syntax.h: mksyntax
-	./${.ALLSRC}
-
-mkinit: mkinit.c
-	${HOST_LINK.c} -o mkinit ${.IMPSRC}
-
-mknodes: mknodes.c
-	${HOST_LINK.c} -o mknodes ${.IMPSRC}
+	./mksyntax
 
-.if	(${MACHINE_ARCH} == "powerpc") || \
-	(${MACHINE_ARCH} == "arm32") || \
-	(${MACHINE_ARCH} == "arm26")
-TARGET_CHARFLAG= -DTARGET_CHAR="u_int8_t"
-.else
-TARGET_CHARFLAG= -DTARGET_CHAR="int8_t"
-.endif
+arith.c arith.h: arith.y
+	yacc -d arith.y
+	mv y.tab.h arith.h
+	mv y.tab.c arith.c
 
-mksyntax: mksyntax.c
-	${HOST_LINK.c} ${TARGET_CHARFLAG} -o mksyntax ${.IMPSRC}
-
-.include <bsd.prog.mk>
+token.h: mktokens
+	sh ./mktokens
 
-${OBJS}: builtins.h nodes.h syntax.h token.h
+clean:
+	rm -f $(PROG) $(OBJS) $(CLEANFILES) core
diff -Nur ash-0.4.0.orig/arith.y ash-0.4.0.fixed/arith.y
--- ash-0.4.0.orig/arith.y	1999-07-09 06:02:05.000000000 -0500
+++ ash-0.4.0.fixed/arith.y	2003-10-02 00:53:57.000000000 -0500
@@ -150,43 +150,43 @@
 %left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
 %%
 
-exp:	expr = {
+exp:	expr {
 			return ($1);
 		}
 	;
 
 
-expr:	ARITH_LPAREN expr ARITH_RPAREN = { $$ = $2; }
-	| expr ARITH_OR expr	= { $$ = $1 ? $1 : $3 ? $3 : 0; }
-	| expr ARITH_AND expr	= { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; }
-	| expr ARITH_BOR expr	= { $$ = $1 | $3; }
-	| expr ARITH_BXOR expr	= { $$ = $1 ^ $3; }
-	| expr ARITH_BAND expr	= { $$ = $1 & $3; }
-	| expr ARITH_EQ expr	= { $$ = $1 == $3; }
-	| expr ARITH_GT expr	= { $$ = $1 > $3; }
-	| expr ARITH_GE expr	= { $$ = $1 >= $3; }
-	| expr ARITH_LT expr	= { $$ = $1 < $3; }
-	| expr ARITH_LE expr	= { $$ = $1 <= $3; }
-	| expr ARITH_NE expr	= { $$ = $1 != $3; }
-	| expr ARITH_LSHIFT expr = { $$ = $1 << $3; }
-	| expr ARITH_RSHIFT expr = { $$ = $1 >> $3; }
-	| expr ARITH_ADD expr	= { $$ = $1 + $3; }
-	| expr ARITH_SUB expr	= { $$ = $1 - $3; }
-	| expr ARITH_MUL expr	= { $$ = $1 * $3; }
-	| expr ARITH_DIV expr	= {
+expr:	ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; }
+	| expr ARITH_OR expr	{ $$ = $1 ? $1 : $3 ? $3 : 0; }
+	| expr ARITH_AND expr	{ $$ = $1 ? ( $3 ? $3 : 0 ) : 0; }
+	| expr ARITH_BOR expr	{ $$ = $1 | $3; }
+	| expr ARITH_BXOR expr	{ $$ = $1 ^ $3; }
+	| expr ARITH_BAND expr	{ $$ = $1 & $3; }
+	| expr ARITH_EQ expr	{ $$ = $1 == $3; }
+	| expr ARITH_GT expr	{ $$ = $1 > $3; }
+	| expr ARITH_GE expr	{ $$ = $1 >= $3; }
+	| expr ARITH_LT expr	{ $$ = $1 < $3; }
+	| expr ARITH_LE expr	{ $$ = $1 <= $3; }
+	| expr ARITH_NE expr	{ $$ = $1 != $3; }
+	| expr ARITH_LSHIFT expr { $$ = $1 << $3; }
+	| expr ARITH_RSHIFT expr { $$ = $1 >> $3; }
+	| expr ARITH_ADD expr	{ $$ = $1 + $3; }
+	| expr ARITH_SUB expr	{ $$ = $1 - $3; }
+	| expr ARITH_MUL expr	{ $$ = $1 * $3; }
+	| expr ARITH_DIV expr	{
 			if ($3 == 0)
 				yyerror("division by zero");
 			$$ = $1 / $3;
 			}
-	| expr ARITH_REM expr   = {
+	| expr ARITH_REM expr   {
 			if ($3 == 0)
 				yyerror("division by zero");
 			$$ = $1 % $3;
 			}
-	| ARITH_NOT expr	= { $$ = !($2); }
-	| ARITH_BNOT expr	= { $$ = ~($2); }
-	| ARITH_SUB expr %prec ARITH_UNARYMINUS = { $$ = -($2); }
-	| ARITH_ADD expr %prec ARITH_UNARYPLUS = { $$ = $2; }
+	| ARITH_NOT expr	{ $$ = !($2); }
+	| ARITH_BNOT expr	{ $$ = ~($2); }
+	| ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); }
+	| ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; }
 	| ARITH_NUM
 	;
 %%
@@ -195,7 +195,6 @@
 	const char *s;
 {
 
-	yyerrok;
 	yyclearin;
 	arith_lex_reset();	/* reprime lex */
 	error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
diff -Nur ash-0.4.0.orig/bltin/bltin.h ash-0.4.0.fixed/bltin/bltin.h
--- ash-0.4.0.orig/bltin/bltin.h	1997-07-05 06:12:37.000000000 -0500
+++ ash-0.4.0.fixed/bltin/bltin.h	2003-10-01 21:08:15.000000000 -0500
@@ -46,8 +46,10 @@
 
 #include "../shell.h"
 #include "../mystring.h"
+#include "../memalloc.h"
 #ifdef SHELL
 #include "../output.h"
+#ifndef _GNU_SOURCE
 #define stdout out1
 #define stderr out2
 #define printf out1fmt
@@ -56,12 +58,13 @@
 #define fprintf outfmt
 #define fputs outstr
 #define fflush flushout
-#define INITARGS(argv)
 #define warnx(a, b, c) {				\
 	char buf[64];					\
 	(void)snprintf(buf, sizeof(buf), a, b, c);	\
 	error("%s", buf);				\
 }
+#endif
+#define INITARGS(argv)
 
 #else
 #undef NULL
diff -Nur ash-0.4.0.orig/bltin/echo.c ash-0.4.0.fixed/bltin/echo.c
--- ash-0.4.0.orig/bltin/echo.c	1996-11-03 06:06:22.000000000 -0600
+++ ash-0.4.0.fixed/bltin/echo.c	2003-10-01 21:08:15.000000000 -0500
@@ -44,7 +44,13 @@
 
 #define main echocmd
 
+#ifdef _GNU_SOURCE
+#include <stdio.h>
+
+#include "../mystring.h"
+#else
 #include "bltin.h"
+#endif
 
 /* #define eflag 1 */
 
@@ -53,7 +59,6 @@
 	register char **ap;
 	register char *p;
 	register char c;
-	int count;
 	int nflag = 0;
 #ifndef eflag
 	int eflag = 0;
@@ -62,34 +67,42 @@
 	ap = argv;
 	if (argc)
 		ap++;
-	if ((p = *ap) != NULL) {
+	while ((p = *ap) != NULL && *p == '-') {
 		if (equal(p, "-n")) {
-			nflag++;
-			ap++;
+			nflag = 1;
 		} else if (equal(p, "-e")) {
 #ifndef eflag
-			eflag++;
+			eflag = 1;
+#endif
+		} else if (equal(p, "-E")) {
+#ifndef eflag
+			eflag = 0;
 #endif
-			ap++;
 		}
+		else break;
+		ap++;
 	}
 	while ((p = *ap++) != NULL) {
 		while ((c = *p++) != '\0') {
 			if (c == '\\' && eflag) {
-				switch (*p++) {
+				switch (c = *p++) {
+				case 'a':  c = '\007'; break;
 				case 'b':  c = '\b';  break;
 				case 'c':  return 0;		/* exit */
+				case 'e':  c = '\033';  break;
 				case 'f':  c = '\f';  break;
 				case 'n':  c = '\n';  break;
 				case 'r':  c = '\r';  break;
 				case 't':  c = '\t';  break;
 				case 'v':  c = '\v';  break;
 				case '\\':  break;		/* c = '\\' */
-				case '0':
-					c = 0;
-					count = 3;
-					while (--count >= 0 && (unsigned)(*p - '0') < 8)
-						c = (c << 3) + (*p++ - '0');
+				case '0': case '1': case '2': case '3':
+				case '4': case '5': case '6': case '7':
+					c -= '0';
+					if (*p >= '0' && *p <= '7')
+						c = c * 8 + (*p++ - '0');
+					if (*p >= '0' && *p <= '7')
+					c = c * 8 + (*p++ - '0');
 					break;
 				default:
 					p--;
@@ -103,5 +116,12 @@
 	}
 	if (! nflag)
 		putchar('\n');
+#ifdef _GNU_SOURCE
+	fflush(stdout);
+	if (ferror(stdout)) {
+		clearerr(stdout);
+		return 1;
+	}
+#endif
 	return 0;
 }
diff -Nur ash-0.4.0.orig/bltin/test.c ash-0.4.0.fixed/bltin/test.c
--- ash-0.4.0.orig/bltin/test.c	1969-12-31 18:00:00.000000000 -0600
+++ ash-0.4.0.fixed/bltin/test.c	2003-10-01 21:08:15.000000000 -0500
@@ -0,0 +1,583 @@
+/*	$NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $	*/
+
+/*
+ * test(1); version 7-like  --  author Erik Baalbergen
+ * modified by Eric Gisin to be used as built-in.
+ * modified by Arnold Robbins to add SVR3 compatibility
+ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ * modified by J.T. Conklin for NetBSD.
+ *
+ * This program is in the Public Domain.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $");
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+/* test(1) accepts the following grammar:
+	oexpr	::= aexpr | aexpr "-o" oexpr ;
+	aexpr	::= nexpr | nexpr "-a" aexpr ;
+	nexpr	::= primary | "!" primary
+	primary	::= unary-operator operand
+		| operand binary-operator operand
+		| operand
+		| "(" oexpr ")"
+		;
+	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
+		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
+
+	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+			"-nt"|"-ot"|"-ef";
+	operand ::= <any legal UNIX file name>
+*/
+
+enum token {
+	EOI,
+	FILRD,
+	FILWR,
+	FILEX,
+	FILEXIST,
+	FILREG,
+	FILDIR,
+	FILCDEV,
+	FILBDEV,
+	FILFIFO,
+	FILSOCK,
+	FILSYM,
+	FILGZ,
+	FILTT,
+	FILSUID,
+	FILSGID,
+	FILSTCK,
+	FILNT,
+	FILOT,
+	FILEQ,
+	FILUID,
+	FILGID,
+	STREZ,
+	STRNZ,
+	STREQ,
+	STRNE,
+	STRLT,
+	STRGT,
+	INTEQ,
+	INTNE,
+	INTGE,
+	INTGT,
+	INTLE,
+	INTLT,
+	UNOT,
+	BAND,
+	BOR,
+	LPAREN,
+	RPAREN,
+	OPERAND
+};
+
+enum token_types {
+	UNOP,
+	BINOP,
+	BUNOP,
+	BBINOP,
+	PAREN
+};
+
+static struct t_op {
+	const char *op_text;
+	short op_num, op_type;
+} const ops [] = {
+	{"-r",	FILRD,	UNOP},
+	{"-w",	FILWR,	UNOP},
+	{"-x",	FILEX,	UNOP},
+	{"-e",	FILEXIST,UNOP},
+	{"-f",	FILREG,	UNOP},
+	{"-d",	FILDIR,	UNOP},
+	{"-c",	FILCDEV,UNOP},
+	{"-b",	FILBDEV,UNOP},
+	{"-p",	FILFIFO,UNOP},
+	{"-u",	FILSUID,UNOP},
+	{"-g",	FILSGID,UNOP},
+	{"-k",	FILSTCK,UNOP},
+	{"-s",	FILGZ,	UNOP},
+	{"-t",	FILTT,	UNOP},
+	{"-z",	STREZ,	UNOP},
+	{"-n",	STRNZ,	UNOP},
+	{"-h",	FILSYM,	UNOP},		/* for backwards compat */
+	{"-O",	FILUID,	UNOP},
+	{"-G",	FILGID,	UNOP},
+	{"-L",	FILSYM,	UNOP},
+	{"-S",	FILSOCK,UNOP},
+	{"=",	STREQ,	BINOP},
+	{"!=",	STRNE,	BINOP},
+	{"<",	STRLT,	BINOP},
+	{">",	STRGT,	BINOP},
+	{"-eq",	INTEQ,	BINOP},
+	{"-ne",	INTNE,	BINOP},
+	{"-ge",	INTGE,	BINOP},
+	{"-gt",	INTGT,	BINOP},
+	{"-le",	INTLE,	BINOP},
+	{"-lt",	INTLT,	BINOP},
+	{"-nt",	FILNT,	BINOP},
+	{"-ot",	FILOT,	BINOP},
+	{"-ef",	FILEQ,	BINOP},
+	{"!",	UNOT,	BUNOP},
+	{"-a",	BAND,	BBINOP},
+	{"-o",	BOR,	BBINOP},
+	{"(",	LPAREN,	PAREN},
+	{")",	RPAREN,	PAREN},
+	{0,	0,	0}
+};
+
+static char **t_wp;
+static struct t_op const *t_wp_op;
+static gid_t *group_array = NULL;
+static int ngroups;
+
+static void syntax __P((const char *, const char *));
+static int oexpr __P((enum token));
+static int aexpr __P((enum token));
+static int nexpr __P((enum token));
+static int primary __P((enum token));
+static int binop __P((void));
+static int filstat __P((char *, enum token));
+static enum token t_lex __P((char *));
+static int isoperand __P((void));
+static int getn __P((const char *));
+static int newerf __P((const char *, const char *));
+static int olderf __P((const char *, const char *));
+static int equalf __P((const char *, const char *));
+static int test_eaccess();
+static int bash_group_member();
+static void initialize_group_array();
+
+#if defined(SHELL)
+extern void error __P((const char *, ...)) __attribute__((__noreturn__));
+#else
+static void error __P((const char *, ...)) __attribute__((__noreturn__));
+
+static void
+#ifdef __STDC__
+error(const char *msg, ...)
+#else
+error(va_alist)
+	va_dcl
+#endif
+{
+	va_list ap;
+#ifndef __STDC__
+	const char *msg;
+
+	va_start(ap);
+	msg = va_arg(ap, const char *);
+#else
+	va_start(ap, msg);
+#endif
+	verrx(2, msg, ap);
+	/*NOTREACHED*/
+	va_end(ap);
+}
+#endif
+
+#ifdef SHELL
+int testcmd __P((int, char **));
+
+int
+testcmd(argc, argv)
+	int argc;
+	char **argv;
+#else
+int main __P((int, char **));
+
+int
+main(argc, argv)
+	int argc;
+	char **argv;
+#endif
+{
+	int	res;
+
+
+	if (strcmp(argv[0], "[") == 0) {
+		if (strcmp(argv[--argc], "]"))
+			error("missing ]");
+		argv[argc] = NULL;
+	}
+
+	if (argc < 2)
+		return 1;
+
+	t_wp = &argv[1];
+	res = !oexpr(t_lex(*t_wp));
+
+	if (*t_wp != NULL && *++t_wp != NULL)
+		syntax(*t_wp, "unexpected operator");
+
+	return res;
+}
+
+static void
+syntax(op, msg)
+	const char	*op;
+	const char	*msg;
+{
+	if (op && *op)
+		error("%s: %s", op, msg);
+	else
+		error("%s", msg);
+}
+
+static int
+oexpr(n)
+	enum token n;
+{
+	int res;
+
+	res = aexpr(n);
+	if (t_lex(*++t_wp) == BOR)
+		return oexpr(t_lex(*++t_wp)) || res;
+	t_wp--;
+	return res;
+}
+
+static int
+aexpr(n)
+	enum token n;
+{
+	int res;
+
+	res = nexpr(n);
+	if (t_lex(*++t_wp) == BAND)
+		return aexpr(t_lex(*++t_wp)) && res;
+	t_wp--;
+	return res;
+}
+
+static int
+nexpr(n)
+	enum token n;			/* token */
+{
+	if (n == UNOT)
+		return !nexpr(t_lex(*++t_wp));
+	return primary(n);
+}
+
+static int
+primary(n)
+	enum token n;
+{
+	enum token nn;
+	int res;
+
+	if (n == EOI)
+		return 0;		/* missing expression */
+	if (n == LPAREN) {
+		if ((nn = t_lex(*++t_wp)) == RPAREN)
+			return 0;	/* missing expression */
+		res = oexpr(nn);
+		if (t_lex(*++t_wp) != RPAREN)
+			syntax(NULL, "closing paren expected");
+		return res;
+	}
+	if (t_wp_op && t_wp_op->op_type == UNOP) {
+		/* unary expression */
+		if (*++t_wp == NULL)
+			syntax(t_wp_op->op_text, "argument expected");
+		switch (n) {
+		case STREZ:
+			return strlen(*t_wp) == 0;
+		case STRNZ:
+			return strlen(*t_wp) != 0;
+		case FILTT:
+			return isatty(getn(*t_wp));
+		default:
+			return filstat(*t_wp, n);
+		}
+	}
+
+	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
+		return binop();
+	}	  
+
+	return strlen(*t_wp) > 0;
+}
+
+static int
+binop()
+{
+	const char *opnd1, *opnd2;
+	struct t_op const *op;
+
+	opnd1 = *t_wp;
+	(void) t_lex(*++t_wp);
+	op = t_wp_op;
+
+	if ((opnd2 = *++t_wp) == (char *)0)
+		syntax(op->op_text, "argument expected");
+		
+	switch (op->op_num) {
+	case STREQ:
+		return strcmp(opnd1, opnd2) == 0;
+	case STRNE:
+		return strcmp(opnd1, opnd2) != 0;
+	case STRLT:
+		return strcmp(opnd1, opnd2) < 0;
+	case STRGT:
+		return strcmp(opnd1, opnd2) > 0;
+	case INTEQ:
+		return getn(opnd1) == getn(opnd2);
+	case INTNE:
+		return getn(opnd1) != getn(opnd2);
+	case INTGE:
+		return getn(opnd1) >= getn(opnd2);
+	case INTGT:
+		return getn(opnd1) > getn(opnd2);
+	case INTLE:
+		return getn(opnd1) <= getn(opnd2);
+	case INTLT:
+		return getn(opnd1) < getn(opnd2);
+	case FILNT:
+		return newerf (opnd1, opnd2);
+	case FILOT:
+		return olderf (opnd1, opnd2);
+	case FILEQ:
+		return equalf (opnd1, opnd2);
+	default:
+		abort();
+		/* NOTREACHED */
+	}
+}
+
+static int
+filstat(nm, mode)
+	char *nm;
+	enum token mode;
+{
+	struct stat s;
+
+	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
+		return 0;
+
+	switch (mode) {
+	case FILRD:
+		return test_eaccess(nm, R_OK) == 0;
+	case FILWR:
+		return test_eaccess(nm, W_OK) == 0;
+	case FILEX:
+		return test_eaccess(nm, X_OK) == 0;
+	case FILEXIST:
+		return 1;
+	case FILREG:
+		return S_ISREG(s.st_mode);
+	case FILDIR:
+		return S_ISDIR(s.st_mode);
+	case FILCDEV:
+		return S_ISCHR(s.st_mode);
+	case FILBDEV:
+		return S_ISBLK(s.st_mode);
+	case FILFIFO:
+		return S_ISFIFO(s.st_mode);
+	case FILSOCK:
+		return S_ISSOCK(s.st_mode);
+	case FILSYM:
+		return S_ISLNK(s.st_mode);
+	case FILSUID:
+		return (s.st_mode & S_ISUID) != 0;
+	case FILSGID:
+		return (s.st_mode & S_ISGID) != 0;
+	case FILSTCK:
+		return (s.st_mode & S_ISVTX) != 0;
+	case FILGZ:
+		return s.st_size > (off_t)0;
+	case FILUID:
+		return s.st_uid == geteuid();
+	case FILGID:
+		return s.st_gid == getegid();
+	default:
+		return 1;
+	}
+}
+
+static enum token
+t_lex(s)
+	char *s;
+{
+	struct t_op const *op = ops;
+
+	if (s == 0) {
+		t_wp_op = (struct t_op *)0;
+		return EOI;
+	}
+	while (op->op_text) {
+		if (strcmp(s, op->op_text) == 0) {
+			if ((op->op_type == UNOP && isoperand()) ||
+			    (op->op_num == LPAREN && *(t_wp+1) == 0))
+				break;
+			t_wp_op = op;
+			return op->op_num;
+		}
+		op++;
+	}
+	t_wp_op = (struct t_op *)0;
+	return OPERAND;
+}
+
+static int
+isoperand()
+{
+	struct t_op const *op = ops;
+	char *s;
+	char *t;
+
+	if ((s  = *(t_wp+1)) == 0)
+		return 1;
+	if ((t = *(t_wp+2)) == 0)
+		return 0;
+	while (op->op_text) {
+		if (strcmp(s, op->op_text) == 0)
+	    		return op->op_type == BINOP &&
+	    		    (t[0] != ')' || t[1] != '\0'); 
+		op++;
+	}
+	return 0;
+}
+
+/* atoi with error detection */
+static int
+getn(s)
+	const char *s;
+{
+	char *p;
+	long r;
+
+	errno = 0;
+	r = strtol(s, &p, 10);
+
+	if (errno != 0)
+	      error("%s: out of range", s);
+
+	while (isspace((unsigned char)*p))
+	      p++;
+	
+	if (*p)
+	      error("%s: bad number", s);
+
+	return (int) r;
+}
+
+static int
+newerf (f1, f2)
+const char *f1, *f2;
+{
+	struct stat b1, b2;
+
+	return (stat (f1, &b1) == 0 &&
+		stat (f2, &b2) == 0 &&
+		b1.st_mtime > b2.st_mtime);
+}
+
+static int
+olderf (f1, f2)
+const char *f1, *f2;
+{
+	struct stat b1, b2;
+
+	return (stat (f1, &b1) == 0 &&
+		stat (f2, &b2) == 0 &&
+		b1.st_mtime < b2.st_mtime);
+}
+
+static int
+equalf (f1, f2)
+const char *f1, *f2;
+{
+	struct stat b1, b2;
+
+	return (stat (f1, &b1) == 0 &&
+		stat (f2, &b2) == 0 &&
+		b1.st_dev == b2.st_dev &&
+		b1.st_ino == b2.st_ino);
+}
+
+/* Do the same thing access(2) does, but use the effective uid and gid,
+   and don't make the mistake of telling root that any file is
+   executable. */
+static int
+test_eaccess (path, mode)
+char *path;
+int mode;
+{
+	struct stat st;
+	int euid = geteuid();
+
+	if (stat (path, &st) < 0)
+		return (-1);
+
+	if (euid == 0) {
+		/* Root can read or write any file. */
+		if (mode != X_OK)
+		return (0);
+
+		/* Root can execute any file that has any one of the execute
+		   bits set. */
+		if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+			return (0);
+	}
+
+	if (st.st_uid == euid)		/* owner */
+		mode <<= 6;
+	else if (bash_group_member (st.st_gid))
+		mode <<= 3;
+
+	if (st.st_mode & mode)
+		return (0);
+
+	return (-1);
+}
+
+static void
+initialize_group_array ()
+{
+	ngroups = getgroups(0, NULL);
+	group_array = malloc(ngroups * sizeof(gid_t));
+	if (!group_array)
+		error(strerror(ENOMEM));
+	getgroups(ngroups, group_array);
+}
+
+/* Return non-zero if GID is one that we have in our groups list. */
+static int
+bash_group_member (gid)
+gid_t gid;
+{
+	register int i;
+
+	/* Short-circuit if possible, maybe saving a call to getgroups(). */
+	if (gid == getgid() || gid == getegid())
+		return (1);
+
+	if (ngroups == 0)
+		initialize_group_array ();
+
+	/* Search through the list looking for GID. */
+	for (i = 0; i < ngroups; i++)
+		if (gid == group_array[i])
+			return (1);
+
+	return (0);
+}
diff -Nur ash-0.4.0.orig/bltin/times.c ash-0.4.0.fixed/bltin/times.c
--- ash-0.4.0.orig/bltin/times.c	1969-12-31 18:00:00.000000000 -0600
+++ ash-0.4.0.fixed/bltin/times.c	2003-10-01 21:08:15.000000000 -0500
@@ -0,0 +1,30 @@
+#ifdef _GNU_SOURCE
+/*
+ * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
+ * This file contains code for the times builtin.
+ * $Id: ash-0.4.0-cumulative_fixes-1.patch,v 1.1 2004/06/04 10:32:01 jim Exp $
+ */
+
+#include <stdio.h>
+#include <sys/times.h>
+#include <unistd.h>
+
+#define main timescmd
+
+int main() {
+	struct tms buf;
+	long int clk_tck = sysconf(_SC_CLK_TCK);
+
+	times(&buf);
+	printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
+	       (int) (buf.tms_utime / clk_tck / 60),
+	       ((double) buf.tms_utime) / clk_tck,
+	       (int) (buf.tms_stime / clk_tck / 60),
+	       ((double) buf.tms_stime) / clk_tck,
+	       (int) (buf.tms_cutime / clk_tck / 60),
+	       ((double) buf.tms_cutime) / clk_tck,
+	       (int) (buf.tms_cstime / clk_tck / 60),
+	       ((double) buf.tms_cstime) / clk_tck);
+	return 0;
+}
+#endif	/* _GNU_SOURCE */
diff -Nur ash-0.4.0.orig/builtins.def ash-0.4.0.fixed/builtins.def
--- ash-0.4.0.orig/builtins.def	2000-04-10 06:02:58.000000000 -0500
+++ ash-0.4.0.fixed/builtins.def	2003-10-01 21:08:15.000000000 -0500
@@ -49,12 +49,13 @@
 #
 # NOTE: bltincmd must come first!
 
-bltincmd	command
+bltincmd	builtin
 #alloccmd	alloc
 bgcmd -j	bg
 breakcmd	break continue
 #catfcmd	catf
 cdcmd		cd chdir
+commandcmd	command
 dotcmd		.
 echocmd		echo
 evalcmd		eval
@@ -70,6 +71,7 @@
 hashcmd		hash
 jobidcmd	jobid
 jobscmd		jobs
+killcmd -j	kill
 #linecmd		line
 localcmd	local
 #nlechocmd	nlecho
@@ -91,3 +93,4 @@
 aliascmd	alias
 ulimitcmd	ulimit
 testcmd		test [
+timescmd	times
diff -Nur ash-0.4.0.orig/cd.c ash-0.4.0.fixed/cd.c
--- ash-0.4.0.orig/cd.c	1999-07-09 06:02:05.000000000 -0500
+++ ash-0.4.0.fixed/cd.c	2003-10-01 21:08:15.000000000 -0500
@@ -244,6 +244,7 @@
 		curdir = NULL;
 		getpwd();
 		setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
+		setvar("OLDPWD", prevdir, VEXPORT|VTEXTFIXED);
 		INTON;
 		return;
 	}
@@ -275,6 +276,7 @@
 	prevdir = curdir;
 	curdir = savestr(stackblock());
 	setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
+	setvar("OLDPWD", prevdir, VEXPORT|VTEXTFIXED);
 	INTON;
 }
 
@@ -319,7 +321,7 @@
 	 * c implementation of getcwd, that does not open a pipe to
 	 * /bin/pwd.
 	 */
-#if defined(__NetBSD__) || defined(__SVR4)
+#if defined(__NetBSD__) || defined(__SVR4) || defined(__GLIBC__)
 		
 	if (getcwd(buf, sizeof(buf)) == NULL) {
 		char *pwd = getenv("PWD");
diff -Nur ash-0.4.0.orig/error.c ash-0.4.0.fixed/error.c
--- ash-0.4.0.orig/error.c	2001-01-12 10:50:35.000000000 -0600
+++ ash-0.4.0.fixed/error.c	2003-10-01 21:08:15.000000000 -0500
@@ -233,6 +233,7 @@
 	{ ENOTDIR,	E_CREAT,"directory nonexistent" },
 	{ ENOTDIR,	E_EXEC,	"not found" },
 	{ EISDIR,	ALL,	"is a directory" },
+	{ EEXIST,	E_CREAT,"file exists" },
 #ifdef notdef
 	{ EMFILE,	ALL,	"too many open files" },
 #endif
diff -Nur ash-0.4.0.orig/error.h ash-0.4.0.fixed/error.h
--- ash-0.4.0.orig/error.h	1999-07-09 06:02:05.000000000 -0500
+++ ash-0.4.0.fixed/error.h	2003-10-01 21:08:15.000000000 -0500
@@ -102,7 +102,7 @@
  * so we use _setjmp instead.
  */
 
-#if defined(BSD) && !defined(__SVR4)
+#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
 #define setjmp(jmploc)	_setjmp(jmploc)
 #define longjmp(jmploc, val)	_longjmp(jmploc, val)
 #endif
diff -Nur ash-0.4.0.orig/eval.c ash-0.4.0.fixed/eval.c
--- ash-0.4.0.orig/eval.c	2000-05-23 05:03:18.000000000 -0500
+++ ash-0.4.0.fixed/eval.c	2003-10-01 21:08:15.000000000 -0500
@@ -45,7 +45,9 @@
 #endif
 #endif /* not lint */
 
+#include <sys/types.h>
 #include <signal.h>
+#include <malloc.h>
 #include <unistd.h>
 
 /*
@@ -101,6 +103,8 @@
 STATIC void evalpipe __P((union node *));
 STATIC void evalcommand __P((union node *, int, struct backcmd *));
 STATIC void prehash __P((union node *));
+STATIC int is_assignment_builtin __P((const char *));
+STATIC const char *get_standard_path __P((void));
 
 
 /*
@@ -257,6 +261,11 @@
 		evalcase(n, flags);
 		break;
 	case NDEFUN:
+		if (is_special_builtin(n->narg.text)) {
+			outfmt(out2, "%s is a special built-in\n", n->narg.text);
+			exitstatus = 1;
+			break;
+		}
 		defun(n->narg.text, n->narg.next);
 		exitstatus = 0;
 		break;
@@ -442,6 +451,7 @@
 		case NFROM:
 		case NTO:
 		case NAPPEND:
+		case NTOOV:
 			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
 			redir->nfile.expfname = fn.list->text;
 			break;
@@ -497,9 +507,14 @@
 				close(0);
 				copyfd(prevfd, 0);
 				close(prevfd);
+				if (pip[0] == 0) {
+					pip[0] = -1;
+				}
 			}
 			if (pip[1] >= 0) {
-				close(pip[0]);
+				if (pip[0] >= 0) {
+					close(pip[0]);
+				}
 				if (pip[1] != 1) {
 					close(1);
 					copyfd(pip[1], 1);
@@ -607,6 +622,7 @@
 	int argc;
 	char **envp;
 	int varflag;
+	int pseudovarflag;
 	struct strlist *sp;
 	int mode;
 	int pip[2];
@@ -619,12 +635,17 @@
 	struct localvar *volatile savelocalvars;
 	volatile int e;
 	char *lastarg;
+	int not_special;
+	const char *path;
+	const char *standard_path;
 #if __GNUC__
 	/* Avoid longjmp clobbering */
 	(void) &argv;
 	(void) &argc;
 	(void) &lastarg;
 	(void) &flags;
+	(void) &not_special;
+	(void) &standard_path;
 #endif
 
 	/* First expand the arguments. */
@@ -632,21 +653,31 @@
 	setstackmark(&smark);
 	arglist.lastp = &arglist.list;
 	varlist.lastp = &varlist.list;
+	arglist.list = 0;
 	varflag = 1;
+	pseudovarflag = 0;
 	oexitstatus = exitstatus;
 	exitstatus = 0;
+	not_special = 0;
+	path = pathval();
+	standard_path = NULL;
 	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
 		char *p = argp->narg.text;
-		if (varflag && is_name(*p)) {
+		if ((varflag || pseudovarflag) && is_name(*p)) {
 			do {
 				p++;
 			} while (is_in_name(*p));
 			if (*p == '=') {
-				expandarg(argp, &varlist, EXP_VARTILDE);
+				if (varflag)
+					expandarg(argp, &varlist, EXP_VARTILDE);
+				else
+					expandarg(argp, &arglist, EXP_VARTILDE);
 				continue;
 			}
 		}
 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+		if (varflag && arglist.list && is_assignment_builtin(arglist.list->text))
+			pseudovarflag = 1;
 		varflag = 0;
 	}
 	*arglist.lastp = NULL;
@@ -688,37 +719,75 @@
 		cmdentry.u.index = BLTINCMD;
 	} else {
 		static const char PATH[] = "PATH=";
-		const char *path = pathval();
+		const char *oldpath = NULL;
+		int findflag = DO_ERR;
 
 		/*
 		 * Modify the command lookup path, if a PATH= assignment
 		 * is present
 		 */
 		for (sp = varlist.list ; sp ; sp = sp->next)
-			if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
+			if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) {
 				path = sp->text + sizeof(PATH) - 1;
-
-		find_command(argv[0], &cmdentry, DO_ERR, path);
-		if (cmdentry.cmdtype == CMDUNKNOWN) {	/* command not found */
-			exitstatus = 127;
-			flushout(&errout);
-			return;
-		}
-		/* implement the bltin builtin here */
-		if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
-			for (;;) {
+				findflag |= DO_BRUTE;
+			}
+		for(;;) {
+			find_command(argv[0], &cmdentry, findflag, path);
+			if (oldpath) {
+				path = oldpath;
+				oldpath = NULL;
+			}
+			if (cmdentry.cmdtype == CMDUNKNOWN) {	/* command not found */
+				exitstatus = 127;
+				flushout(&errout);
+				goto out;
+			}
+			/* implement the bltin builtin here */
+			if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
+				not_special = 1;
+				for(;;) {
+					argv++;
+					if (--argc == 0)
+						break;
+					if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
+						outfmt(&errout, "%s: not found\n", *argv);
+						exitstatus = 127;
+						flushout(&errout);
+						goto out;
+					}
+					if (cmdentry.u.index != BLTINCMD)
+						break;
+				}
+			}
+			if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == COMMANDCMD) {
+				not_special = 1;
 				argv++;
-				if (--argc == 0)
-					break;
-				if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
-					outfmt(&errout, "%s: not found\n", *argv);
-					exitstatus = 127;
-					flushout(&errout);
-					return;
+				if (--argc == 0) {
+					exitstatus = 0;
+					goto out;
 				}
-				if (cmdentry.u.index != BLTINCMD)
-					break;
+				if (*argv[0] == '-') {
+					if (!equal(argv[0], "-p")) {
+						argv--;
+						argc++;
+						break;
+					}
+					argv++;
+					if (--argc == 0) {
+						exitstatus = 0;
+						goto out;
+					}
+					if (!standard_path) {
+						standard_path = get_standard_path();
+					}
+					oldpath = path;
+					path = standard_path;
+					findflag |= DO_BRUTE;
+				}
+				findflag |= DO_NOFUN;
+				continue;
 			}
+			break;
 		}
 	}
 
@@ -756,13 +825,12 @@
 #ifdef DEBUG
 		trputs("Shell function:  ");  trargs(argv);
 #endif
+		exitstatus = oexitstatus;
 		redirect(cmd->ncmd.redirect, REDIR_PUSH);
 		saveparam = shellparam;
 		shellparam.malloc = 0;
-		shellparam.reset = 1;
 		shellparam.nparam = argc - 1;
 		shellparam.p = argv + 1;
-		shellparam.optnext = NULL;
 		INTOFF;
 		savelocalvars = localvars;
 		localvars = NULL;
@@ -772,6 +840,8 @@
 				freeparam((volatile struct shparam *)
 				    &saveparam);
 			} else {
+				saveparam.optind = shellparam.optind;
+				saveparam.optoff = shellparam.optoff;
 				freeparam(&shellparam);
 				shellparam = saveparam;
 			}
@@ -790,6 +860,8 @@
 		INTOFF;
 		poplocalvars();
 		localvars = savelocalvars;
+		saveparam.optind = shellparam.optind;
+		saveparam.optoff = shellparam.optoff;
 		freeparam(&shellparam);
 		shellparam = saveparam;
 		handler = savehandler;
@@ -807,9 +879,13 @@
 #endif
 		mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
 		if (flags == EV_BACKCMD) {
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+			openmemout();
+#else
 			memout.nleft = 0;
 			memout.nextc = memout.buf;
 			memout.bufsize = 64;
+#endif
 			mode |= REDIR_BACKQ;
 		}
 		redirect(cmd->ncmd.redirect, mode);
@@ -832,6 +908,8 @@
 		out1 = &output;
 		out2 = &errout;
 		freestdout();
+		if (!not_special && is_special_builtin(commandname))
+			listsetvar(cmdenviron);
 		cmdenviron = NULL;
 		if (e != EXSHELLPROC) {
 			commandname = savecmdname;
@@ -854,10 +932,18 @@
 		if (cmdentry.u.index != EXECCMD)
 			popredir();
 		if (flags == EV_BACKCMD) {
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+			closememout();
+#endif
 			backcmd->buf = memout.buf;
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+			backcmd->nleft = memout.bufsize;
+#else
 			backcmd->nleft = memout.nextc - memout.buf;
+#endif
 			memout.buf = NULL;
 		}
+		cmdenviron = NULL;
 	} else {
 #ifdef DEBUG
 		trputs("normal command:  ");  trargs(argv);
@@ -867,7 +953,7 @@
 		for (sp = varlist.list ; sp ; sp = sp->next)
 			setvareq(sp->text, VEXPORT|VSTACK);
 		envp = environment();
-		shellexec(argv, envp, pathval(), cmdentry.u.index);
+		shellexec(argv, envp, path, cmdentry.u.index);
 	}
 	goto out;
 
@@ -1026,3 +1112,48 @@
 	}
 	return 0;
 }
+
+STATIC int
+is_assignment_builtin (command)
+	const char *command;
+{
+	static const char *assignment_builtins[] = {
+		"alias", "declare", "export", "local", "readonly", "typeset",
+		(char *)NULL
+	};
+	int i;
+
+	for (i = 0; assignment_builtins[i]; i++)
+		if (strcmp(command, assignment_builtins[i]) == 0) return 1;
+	return 0;
+}
+
+int
+is_special_builtin(name)
+	const char *name;
+{
+	static const char *special_builtins[] = {
+		"break", ":", ".", "continue", "eval", "exec", "exit",
+		"export", "readonly", "return", "set", "shift", "times",
+		"trap", "unset", (char *)NULL
+	};
+	int i;
+
+	if (!name) return 0;
+	for (i = 0; special_builtins[i]; i++)
+		if (equal(name, special_builtins[i])) return 1;
+	return 0;
+}
+
+STATIC const char *
+get_standard_path()
+{
+	char *p;
+	size_t len;
+
+	len = confstr(_CS_PATH, NULL, 0);
+	p = stalloc(len + 2);
+	*p = '\0';
+	confstr(_CS_PATH, p, len);
+	return p;
+}
diff -Nur ash-0.4.0.orig/eval.h ash-0.4.0.fixed/eval.h
--- ash-0.4.0.orig/eval.h	2000-01-28 06:03:00.000000000 -0600
+++ ash-0.4.0.fixed/eval.h	2003-10-01 21:08:15.000000000 -0500
@@ -61,6 +61,7 @@
 int falsecmd __P((int, char **));
 int truecmd __P((int, char **));
 int execcmd __P((int, char **));
+int is_special_builtin __P((const char *));
 
 /* in_function returns nonzero if we are currently evaluating a function */
 #define in_function()	funcnest
diff -Nur ash-0.4.0.orig/exec.c ash-0.4.0.fixed/exec.c
--- ash-0.4.0.orig/exec.c	2001-01-12 10:50:35.000000000 -0600
+++ ash-0.4.0.fixed/exec.c	2003-10-01 21:08:15.000000000 -0500
@@ -51,6 +51,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <sysexits.h>
 
 /*
  * When commands are first encountered, they are entered in a hash table.
@@ -108,6 +109,9 @@
 STATIC void clearcmdentry __P((int));
 STATIC struct tblentry *cmdlookup __P((char *, int));
 STATIC void delete_cmd_entry __P((void));
+STATIC int describe_command __P((char *, int));
+STATIC int path_change __P((const char *, int *));
+STATIC int is_regular_builtin __P((const char *));
 
 
 
@@ -125,6 +129,10 @@
 	char *cmdname;
 	int e;
 
+	if (fd2 >= 0 && fd2 != 2) {
+		close(fd2);
+	}
+
 	if (strchr(argv[0], '/') != NULL) {
 		tryexec(argv[0], argv, envp);
 		e = errno;
@@ -164,7 +172,7 @@
 	char **envp;
 	{
 	int e;
-#ifndef BSD
+#if !defined(BSD) && !defined(linux)
 	char *p;
 #endif
 
@@ -180,7 +188,7 @@
 		initshellproc();
 		setinputfile(cmd, 0);
 		commandname = arg0 = savestr(argv[0]);
-#ifndef BSD
+#if !defined(BSD) && !defined(linux)
 		pgetc(); pungetc();		/* fill up input buffer */
 		p = parsenextc;
 		if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
@@ -195,7 +203,7 @@
 }
 
 
-#ifndef BSD
+#if !defined(BSD) && !defined(linux)
 /*
  * Execute an interpreter introduced by "#!", for systems where this
  * feature has not been built into the kernel.  If the interpreter is
@@ -351,27 +359,29 @@
 	if (*argptr == NULL) {
 		for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
 			for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-				printentry(cmdp, verbose);
+				if (cmdp->cmdtype != CMDBUILTIN) {
+					printentry(cmdp, verbose);
+				}
 			}
 		}
 		return 0;
 	}
+	c = 0;
 	while ((name = *argptr) != NULL) {
 		if ((cmdp = cmdlookup(name, 0)) != NULL
 		 && (cmdp->cmdtype == CMDNORMAL
 		     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
 			delete_cmd_entry();
 		find_command(name, &entry, DO_ERR, pathval());
-		if (verbose) {
-			if (entry.cmdtype != CMDUNKNOWN) {	/* if no error msg */
-				cmdp = cmdlookup(name, 0);
-				printentry(cmdp, verbose);
-			}
+		if (entry.cmdtype == CMDUNKNOWN) c = 1;
+		else if (verbose) {
+			cmdp = cmdlookup(name, 0);
+			if (cmdp) printentry(cmdp, verbose);
 			flushall();
 		}
 		argptr++;
 	}
-	return 0;
+	return c;
 }
 
 
@@ -435,6 +445,10 @@
 	struct stat statb;
 	int e;
 	int i;
+	int bltin;
+	int firstchange;
+	int updatetbl;
+	int regular;
 
 	/* If name contains a slash, don't use the hash table */
 	if (strchr(name, '/') != NULL) {
@@ -459,12 +473,54 @@
 		return;
 	}
 
+	updatetbl = 1;
+	if (act & DO_BRUTE) {
+		firstchange = path_change(path, &bltin);
+	} else {
+		bltin = builtinloc;
+		firstchange = 9999;
+	}
+
 	/* If name is in the table, and not invalidated by cd, we're done */
-	if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
-		goto success;
+	if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
+		if (cmdp->cmdtype == CMDFUNCTION) {
+			if (act & DO_NOFUN) {
+				updatetbl = 0;
+			} else {
+				goto success;
+			}
+		} else if (act & DO_BRUTE) {
+			if ((cmdp->cmdtype == CMDNORMAL &&
+			     cmdp->param.index >= firstchange) ||
+			    (cmdp->cmdtype == CMDBUILTIN &&
+			     ((builtinloc < 0 && bltin >= 0) ?
+			      bltin : builtinloc) >= firstchange)) {
+				/* need to recompute the entry */
+			} else {
+				goto success;
+			}
+		} else {
+			goto success;
+		}
+	}
+
+	if ((regular = is_regular_builtin(name))) {
+		if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
+		    	goto success;
+		}
+	} else if (act & DO_BRUTE) {
+		if (firstchange == 0) {
+			updatetbl = 0;
+		}
+	}
 
 	/* If %builtin not in path, check for builtin next */
-	if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
+	if ((bltin < 0 || regular) && (i = find_builtin(name)) >= 0) {
+		if (!updatetbl) {
+			entry->cmdtype = CMDBUILTIN;
+			entry->u.index = i;
+			return;
+		}
 		INTOFF;
 		cmdp = cmdlookup(name, 1);
 		cmdp->cmdtype = CMDBUILTIN;
@@ -475,7 +531,7 @@
 
 	/* We have to search path. */
 	prev = -1;		/* where to start */
-	if (cmdp) {		/* doing a rehash */
+	if (cmdp && cmdp->rehash) {	/* doing a rehash */
 		if (cmdp->cmdtype == CMDBUILTIN)
 			prev = builtinloc;
 		else
@@ -488,26 +544,38 @@
 	while ((fullname = padvance(&path, name)) != NULL) {
 		stunalloc(fullname);
 		idx++;
+		if (idx >= firstchange) {
+			updatetbl = 0;
+		}
 		if (pathopt) {
 			if (prefix("builtin", pathopt)) {
-				if ((i = find_builtin(name)) < 0)
-					goto loop;
-				INTOFF;
-				cmdp = cmdlookup(name, 1);
-				cmdp->cmdtype = CMDBUILTIN;
-				cmdp->param.index = i;
-				INTON;
-				goto success;
-			} else if (prefix("func", pathopt)) {
+				if ((i = find_builtin(name)) >= 0) {
+					if (!updatetbl) {
+						entry->cmdtype = CMDBUILTIN;
+						entry->u.index = i;
+						return;
+					}
+					INTOFF;
+					cmdp = cmdlookup(name, 1);
+					cmdp->cmdtype = CMDBUILTIN;
+					cmdp->param.index = i;
+					INTON;
+					goto success;
+				} else {
+					continue;
+				}
+			} else if (!(act & DO_NOFUN) &&
+				   prefix("func", pathopt)) {
 				/* handled below */
 			} else {
-				goto loop;	/* ignore unimplemented options */
+				continue;	/* ignore unimplemented options */
 			}
 		}
 		/* if rehash, don't redo absolute path names */
-		if (fullname[0] == '/' && idx <= prev) {
+		if (fullname[0] == '/' && idx <= prev &&
+		    idx < firstchange) {
 			if (idx < prev)
-				goto loop;
+				continue;
 			TRACE(("searchexec \"%s\": no change\n", name));
 			goto success;
 		}
@@ -522,7 +590,7 @@
 		}
 		e = EACCES;	/* if we fail, this will be the error */
 		if (!S_ISREG(statb.st_mode))
-			goto loop;
+			continue;
 		if (pathopt) {		/* this is a %func directory */
 			stalloc(strlen(fullname) + 1);
 			readcmdfile(fullname);
@@ -544,6 +612,13 @@
 		}
 #endif
 		TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
+		/* If we aren't called with DO_BRUTE and cmdp is set, it must
+		   be a function and we're being called with DO_NOFUN */
+		if (!updatetbl) {
+			entry->cmdtype = CMDNORMAL;
+			entry->u.index = idx;
+			return;
+		}
 		INTOFF;
 		cmdp = cmdlookup(name, 1);
 		cmdp->cmdtype = CMDNORMAL;
@@ -553,7 +628,7 @@
 	}
 
 	/* We failed.  If there was an entry for this command, delete it */
-	if (cmdp)
+	if (cmdp && updatetbl)
 		delete_cmd_entry();
 	if (act & DO_ERR)
 		outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
@@ -618,37 +693,12 @@
 changepath(newval)
 	const char *newval;
 {
-	const char *old, *new;
-	int idx;
 	int firstchange;
 	int bltin;
 
-	old = pathval();
-	new = newval;
-	firstchange = 9999;	/* assume no change */
-	idx = 0;
-	bltin = -1;
-	for (;;) {
-		if (*old != *new) {
-			firstchange = idx;
-			if ((*old == '\0' && *new == ':')
-			 || (*old == ':' && *new == '\0'))
-				firstchange++;
-			old = new;	/* ignore subsequent differences */
-		}
-		if (*new == '\0')
-			break;
-		if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
-			bltin = idx;
-		if (*new == ':') {
-			idx++;
-		}
-		new++, old++;
-	}
+	firstchange = path_change(newval, &bltin);
 	if (builtinloc < 0 && bltin >= 0)
 		builtinloc = bltin;		/* zap builtins */
-	if (builtinloc >= 0 && bltin < 0)
-		firstchange = 0;
 	clearcmdentry(firstchange);
 	builtinloc = bltin;
 }
@@ -838,11 +888,9 @@
 	{
 	struct cmdentry entry;
 
-	INTOFF;
 	entry.cmdtype = CMDFUNCTION;
 	entry.u.func = copyfunc(func);
 	addcmdentry(name, &entry);
-	INTON;
 }
 
 
@@ -945,3 +993,189 @@
 	}
 	return err;
 }
+
+STATIC int
+describe_command(command, verbose)
+	char *command;
+	int verbose;
+{
+	struct cmdentry entry;
+	struct tblentry *cmdp;
+	char **pp;
+	struct alias *ap;
+	extern char *const parsekwd[];
+
+	for (pp = (char **)parsekwd; *pp; pp++)
+		if (**pp == *command && equal(*pp, command))
+			break;
+
+	if (*pp) {
+		if (verbose) {
+			out1fmt("%s is a reserved word\n", command);
+		} else {
+			out1fmt("%s\n", command);
+		}
+		return 0;
+	}
+
+	/* Then look at the aliases */
+	if ((ap = lookupalias(command, 1)) != NULL) {
+		if (verbose) {
+			out1fmt("%s is aliased to `%s'\n", command, ap->val);
+		} else {
+			out1fmt("alias %s='%s'\n", command, ap->val);
+		}
+		return 0;
+	}
+
+	/* Then check if it is a tracked alias */
+	if ((cmdp = cmdlookup(command, 0)) != NULL) {
+		entry.cmdtype = cmdp->cmdtype;
+		entry.u = cmdp->param;
+	}
+	else {
+		/* Finally use brute force */
+		find_command(command, &entry, DO_ABS, pathval());
+	}
+
+	switch (entry.cmdtype) {
+	case CMDNORMAL: {
+		int j = entry.u.index;
+		const char *path = pathval();
+		char *name;
+		if (j == -1) 
+			name = command;
+		else {
+			do { 
+				name = padvance(&path, command);
+				stunalloc(name);
+			} while (--j >= 0);
+		}
+		if (verbose) {
+			out1fmt("%s is %s\n", command, name);
+		} else {
+			out1fmt("%s\n", name);
+		}
+		break;
+	}
+	case CMDFUNCTION:
+		if (verbose) {
+			out1fmt("%s is a function\n", command);
+		} else {
+			out1fmt("%s\n", command);
+		}
+		break;
+	case CMDBUILTIN:
+		if (verbose) {
+			if (is_special_builtin(command)) {
+				out1fmt("%s is a special built-in utility\n", command);
+			} else {
+				out1fmt("%s is a built-in utility\n", command);
+			}
+		} else {
+			out1fmt("%s\n", command);
+		}
+		break;
+	default:
+		outfmt(out2, "%s not found\n", command);
+		return 127;
+	}
+
+	return 0;
+}
+
+int
+commandcmd(argc, argv)
+	int argc;
+	char **argv;
+{
+	int c;
+	int default_path = 0;
+	int verify_only = 0;
+	int verbose_verify_only = 0;
+
+	while ((c = nextopt("pvV")) != '\0')
+		switch (c) {
+		case 'p':
+			default_path = 1;
+			break;
+		case 'v':
+			verify_only = 1;
+			break;
+		case 'V':
+			verbose_verify_only = 1;
+			break;
+		default:
+			outfmt(out2,
+"command: nextopt returned character code 0%o\n", c);
+			return EX_SOFTWARE;
+		}
+
+	if (default_path + verify_only + verbose_verify_only > 1 ||
+	    !*argptr) {
+			outfmt(out2,
+"command [-p] command [arg ...]\n");
+			outfmt(out2,
+"command {-v|-V} command\n");
+			return EX_USAGE;
+	}
+
+	if (verify_only || verbose_verify_only) {
+		return describe_command(*argptr, verbose_verify_only);
+	}
+
+	return 0;
+}
+
+STATIC int
+path_change(newval, bltin)
+	const char *newval;
+	int *bltin;
+{
+	const char *old, *new;
+	int idx;
+	int firstchange;
+
+	old = pathval();
+	new = newval;
+	firstchange = 9999;	/* assume no change */
+	idx = 0;
+	*bltin = -1;
+	for (;;) {
+		if (*old != *new) {
+			firstchange = idx;
+			if ((*old == '\0' && *new == ':')
+			 || (*old == ':' && *new == '\0'))
+				firstchange++;
+			old = new;	/* ignore subsequent differences */
+		}
+		if (*new == '\0')
+			break;
+		if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
+			*bltin = idx;
+		if (*new == ':') {
+			idx++;
+		}
+		new++, old++;
+	}
+	if (builtinloc >= 0 && *bltin < 0)
+		firstchange = 0;
+	return firstchange;
+}
+
+STATIC int
+is_regular_builtin(name)
+        const char *name;
+{
+        static const char *regular_builtins[] = {
+        	"alias", "bg", "cd", "command", "false", "fc", "fg",
+        	"getopts", "jobs", "kill", "newgrp", "read", "true",
+        	"umask", "unalias", "wait", (char *)NULL
+        };
+        int i;
+
+        if (!name) return 0;
+        for (i = 0; regular_builtins[i]; i++)
+                if (equal(name, regular_builtins[i])) return 1;
+        return 0;
+}
diff -Nur ash-0.4.0.orig/exec.h ash-0.4.0.fixed/exec.h
--- ash-0.4.0.orig/exec.h	2000-05-23 05:03:19.000000000 -0500
+++ ash-0.4.0.fixed/exec.h	2003-10-01 21:08:15.000000000 -0500
@@ -56,6 +56,8 @@
 
 #define DO_ERR	1		/* find_command prints errors */
 #define DO_ABS	2		/* find_command checks absolute paths */
+#define DO_NOFUN	4	/* find_command ignores functions */
+#define DO_BRUTE	8	/* find_command ignores hash table */
 
 extern const char *pathopt;	/* set by padvance */
 extern int exerrno;		/* last exec error */
@@ -74,3 +76,4 @@
 void defun __P((char *, union node *));
 int unsetfunc __P((char *));
 int typecmd __P((int, char **));
+int commandcmd __P((int, char **));
diff -Nur ash-0.4.0.orig/expand.c ash-0.4.0.fixed/expand.c
--- ash-0.4.0.orig/expand.c	2000-03-14 06:03:45.000000000 -0600
+++ ash-0.4.0.fixed/expand.c	2003-10-01 21:08:15.000000000 -0500
@@ -54,6 +54,10 @@
 #include <pwd.h>
 #include <stdlib.h>
 #include <stdio.h>
+#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
+#include <fnmatch.h>
+#include <glob.h>
+#endif
 
 /*
  * Routines to expand arguments to commands.  We have to deal with
@@ -102,17 +106,30 @@
 STATIC int subevalvar __P((char *, char *, int, int, int, int));
 STATIC char *evalvar __P((char *, int));
 STATIC int varisset __P((char *, int));
+STATIC char *strtodest __P((char *, int, int));
 STATIC void varvalue __P((char *, int, int));
 STATIC void recordregion __P((int, int, int));
 STATIC void removerecordregions __P((int)); 
 STATIC void ifsbreakup __P((char *, struct arglist *));
 STATIC void ifsfree __P((void));
 STATIC void expandmeta __P((struct strlist *, int));
+#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
+STATIC const char *preglob __P((const char *));
+STATIC void addglob __P((const glob_t *));
+#else
 STATIC void expmeta __P((char *, char *));
+#endif
 STATIC void addfname __P((char *));
+#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
+STATIC int patmatch __P((char *, char *, int));
+STATIC int patmatch2 __P((char *, char *, int));
+STATIC char * _rmescapes __P((char *, int));
+#else
 STATIC struct strlist *expsort __P((struct strlist *));
 STATIC struct strlist *msort __P((struct strlist *, int));
 STATIC int pmatch __P((char *, char *, int));
+#define patmatch2 patmatch
+#endif
 STATIC char *cvtnum __P((int, char *));
 
 /*
@@ -371,7 +388,7 @@
 	 * have to rescan starting from the beginning since CTLESC
 	 * characters have to be processed left to right.
 	 */
-	CHECKSTRSPACE(8, expdest);
+	CHECKSTRSPACE(10, expdest);
 	USTPUTC('\0', expdest);
 	start = stackblock();
 	p = expdest - 1;
@@ -393,7 +410,7 @@
 	if (quotes)
 		rmescapes(p+2);
 	result = arith(p+2);
-	fmtstr(p, 10, "%d", result);
+	fmtstr(p, 12, "%d", result);
 
 	while (*p++)
 		;
@@ -503,7 +520,7 @@
 	int amount;
 
 	herefd = -1;
-	argstr(p, 0);
+	argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
 	STACKSTRNUL(expdest);
 	herefd = saveherefd;
 	argbackq = saveargbackq;
@@ -535,7 +552,7 @@
 		for (loc = startp; loc < str; loc++) {
 			c = *loc;
 			*loc = '\0';
-			if (patmatch(str, startp, varflags & VSQUOTE))
+			if (patmatch2(str, startp, varflags & VSQUOTE))
 				goto recordleft;
 			*loc = c;
 			if ((varflags & VSQUOTE) && *loc == CTLESC)
@@ -547,7 +564,7 @@
 		for (loc = str - 1; loc >= startp;) {
 			c = *loc;
 			*loc = '\0';
-			if (patmatch(str, startp, varflags & VSQUOTE))
+			if (patmatch2(str, startp, varflags & VSQUOTE))
 				goto recordleft;
 			*loc = c;
 			loc--;
@@ -564,7 +581,7 @@
 
 	case VSTRIMRIGHT:
 	        for (loc = str - 1; loc >= startp;) {
-			if (patmatch(str, loc, varflags & VSQUOTE))
+			if (patmatch2(str, loc, varflags & VSQUOTE))
 				goto recordright;
 			loc--;
 			if ((varflags & VSQUOTE) && loc > startp &&
@@ -580,7 +597,7 @@
 
 	case VSTRIMRIGHTMAX:
 		for (loc = startp; loc < str - 1; loc++) {
-			if (patmatch(str, loc, varflags & VSQUOTE))
+			if (patmatch2(str, loc, varflags & VSQUOTE))
 				goto recordright;
 			if ((varflags & VSQUOTE) && *loc == CTLESC)
 			        loc++;
@@ -819,6 +836,34 @@
 
 
 /*
+ * Put a string on the stack.
+ */
+
+STATIC char *
+strtodest(p, quoted, allow_split)
+	char *p;
+	int quoted;
+	int allow_split;
+{
+	char const *syntax;
+
+	if (allow_split) {
+		syntax = quoted ? DQSYNTAX : BASESYNTAX;
+		while (*p) {
+			if (syntax[(int) *p] == CCTL)
+				STPUTC(CTLESC, expdest);
+			STPUTC(*p++, expdest);
+		}
+	} else
+		while (*p)
+			STPUTC(*p++, expdest);
+
+	return p;
+}
+
+
+
+/*
  * Add the value of a specialized variable to the stack string.
  */
 
@@ -834,22 +879,6 @@
 	extern int oexitstatus;
 	char sep;
 	char **ap;
-	char const *syntax;
-
-#define STRTODEST(p) \
-	do {\
-	if (allow_split) { \
-		syntax = quoted? DQSYNTAX : BASESYNTAX; \
-		while (*p) { \
-			if (syntax[(int)*p] == CCTL) \
-				STPUTC(CTLESC, expdest); \
-			STPUTC(*p++, expdest); \
-		} \
-	} else \
-		while (*p) \
-			STPUTC(*p++, expdest); \
-	} while (0)
-
 
 	switch (*name) {
 	case '$':
@@ -875,7 +904,7 @@
 	case '@':
 		if (allow_split && quoted) {
 			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
-				STRTODEST(p);
+				p = strtodest(p, quoted, allow_split);
 				if (*ap)
 					STPUTC('\0', expdest);
 			}
@@ -888,21 +917,20 @@
 		else
 			sep = ' ';
 		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
-			STRTODEST(p);
+			p = strtodest(p, quoted, allow_split);
 			if (*ap && sep)
 				STPUTC(sep, expdest);
 		}
 		break;
 	case '0':
-		p = arg0;
-		STRTODEST(p);
+		p = strtodest(arg0, quoted, allow_split);
 		break;
 	default:
 		if (is_digit(*name)) {
 			num = atoi(name);
 			if (num > 0 && num <= shellparam.nparam) {
-				p = shellparam.p[num - 1];
-				STRTODEST(p);
+				p = strtodest(shellparam.p[num - 1], quoted,
+					      allow_split);
 			}
 		}
 		break;
@@ -1054,6 +1082,98 @@
  * should be escapes.  The results are stored in the list exparg.
  */
 
+#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
+STATIC void
+expandmeta(str, flag)
+	struct strlist *str;
+	int flag;
+{
+	const char *p;
+	glob_t pglob;
+	/* TODO - EXP_REDIR */
+
+	while (str) {
+		if (fflag)
+			goto nometa;
+		p = preglob(str->text);
+		INTOFF;
+		switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
+		case 0:
+			if (!(pglob.gl_flags & GLOB_MAGCHAR))
+				goto nometa2;
+			addglob(&pglob);
+			globfree(&pglob);
+			INTON;
+			break;
+		case GLOB_NOMATCH:
+nometa2:
+			globfree(&pglob);
+			INTON;
+nometa:
+			*exparg.lastp = str;
+			rmescapes(str->text);
+			exparg.lastp = &str->next;
+			break;
+		default:	/* GLOB_NOSPACE */
+			error("Out of space");
+		}
+		str = str->next;
+	}
+}
+
+
+/*
+ * Prepare the string for glob(3).
+ */
+
+STATIC const char *
+preglob(str)
+	const char *str;
+{
+	const char *p;
+	char *q, *r;
+	size_t len;
+
+	p = str;
+	while (*p != CTLQUOTEMARK && *p != CTLESC) {
+		if (*p++ == '\0')
+			return str;
+	}
+	len = p - str;
+	q = r = stalloc(strlen(str) + 1);
+	if (len > 0) {
+		memcpy(q, str, len);
+		q += len;
+	}
+	do {
+		if (*p == CTLQUOTEMARK)
+			continue;
+		if (*p == CTLESC) {
+			if (*++p != '/')
+				*q++ = '\\';
+		}
+		*q++ = *p;
+	} while (*++p);
+	*q = '\0';
+	return r;
+}
+
+
+/*
+ * Add the result of glob(3) to the list.
+ */
+
+STATIC void
+addglob(pglob)
+	const glob_t *pglob;
+{
+	char **p = pglob->gl_pathv;
+
+	do {
+		addfname(*p);
+	} while (*++p);
+}
+#else
 char *expdir;
 
 
@@ -1238,6 +1358,7 @@
 	if (! atend)
 		endname[-1] = '/';
 }
+#endif
 
 
 /*
@@ -1260,6 +1381,7 @@
 }
 
 
+#if !(defined(__GLIBC__) && !defined(GLOB_BROKEN))
 /*
  * Sort the results of file name expansion.  It calculates the number of
  * strings to sort and then calls msort (short for merge sort) to do the
@@ -1321,6 +1443,7 @@
 	}
 	return list;
 }
+#endif
 
 
 
@@ -1328,6 +1451,39 @@
  * Returns true if the pattern matches the string.
  */
 
+#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
+STATIC int
+patmatch(pattern, string, squoted)
+	char *pattern;
+	char *string;
+	int squoted;	/* string might have quote chars */
+	{
+	const char *p;
+	char *q;
+
+	p = preglob(pattern);
+	q = squoted ? _rmescapes(string, 1) : string;
+
+	return !fnmatch(p, q, 0);
+}
+
+
+STATIC int
+patmatch2(pattern, string, squoted)
+	char *pattern;
+	char *string;
+	int squoted;	/* string might have quote chars */
+	{
+	char *p;
+	int res;
+
+	sstrnleft--;
+	p = grabstackstr(expdest);
+	res = patmatch(pattern, string, squoted);
+	ungrabstackstr(p, expdest);
+	return res;
+}
+#else
 int
 patmatch(pattern, string, squoted)
 	char *pattern;
@@ -1462,6 +1618,7 @@
 		return 0;
 	return 1;
 }
+#endif
 
 
 
@@ -1469,6 +1626,50 @@
  * Remove any CTLESC characters from a string.
  */
 
+#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
+void
+rmescapes(str)
+	char *str;
+{
+	_rmescapes(str, 0);
+}
+
+
+STATIC char *
+_rmescapes(str, flag)
+	char *str;
+	int flag;
+{
+	char *p, *q, *r;
+
+	p = str;
+	while (*p != CTLESC && *p != CTLQUOTEMARK) {
+		if (*p++ == '\0')
+			return str;
+	}
+	q = p;
+	r = str;
+	if (flag) {
+		size_t len = p - str;
+		q = r = stalloc(strlen(p) + len + 1);
+		if (len > 0) {
+			memcpy(q, str, len);
+			q += len;
+		}
+	}
+	while (*p) {
+		if (*p == CTLQUOTEMARK) {
+			p++;
+			continue;
+		}
+		if (*p == CTLESC)
+			p++;
+		*q++ = *p++;
+	}
+	*q = '\0';
+	return r;
+}
+#else
 void
 rmescapes(str)
 	char *str;
@@ -1492,6 +1693,7 @@
 	}
 	*q = '\0';
 }
+#endif
 
 
 
diff -Nur ash-0.4.0.orig/expand.h ash-0.4.0.fixed/expand.h
--- ash-0.4.0.orig/expand.h	1999-07-09 06:02:06.000000000 -0500
+++ ash-0.4.0.fixed/expand.h	2003-10-01 21:08:15.000000000 -0500
@@ -64,7 +64,9 @@
 void expandhere __P((union node *, int));
 void expandarg __P((union node *, struct arglist *, int));
 void expari __P((int));
+#if !(defined(__GLIBC__) && !defined(GLOB_BROKEN))
 int patmatch __P((char *, char *, int));
+#endif
 void rmescapes __P((char *));
 int casematch __P((union node *, char *));
 
diff -Nur ash-0.4.0.orig/hetio.c ash-0.4.0.fixed/hetio.c
--- ash-0.4.0.orig/hetio.c	1969-12-31 18:00:00.000000000 -0600
+++ ash-0.4.0.fixed/hetio.c	2003-10-01 21:08:15.000000000 -0500
@@ -0,0 +1,377 @@
+/*
+ * Termios command line History and Editting for NetBSD sh (ash)
+ * Copyright (c) 1999
+ *	Main code:	Adam Rogoyski <rogoyski@cs.utexas.edu> 
+ *	Etc:		Dave Cinege <dcinege@psychosis.com>
+ *
+ * You may use this code as you wish, so long as the original author(s)
+ * are attributed in any redistributions of the source code.
+ * This code is 'as is' with no warranty.
+ * This code may safely be consumed by a BSD or GPL license.
+ *
+ * v 0.5  19990328	Initial release 
+ *
+ * Future plans: Simple file and path name completion. (like BASH)
+ *
+ */
+
+/*
+Usage and Known bugs:
+	Terminal key codes are not extensive, and more will probably
+	need to be added. This version was created on Debian GNU/Linux 2.x.
+	Delete, Backspace, Home, End, and the arrow keys were tested
+	to work in an Xterm and console. Ctrl-A also works as Home.
+	Ctrl-E also works as End. The binary size increase is <3K.
+	
+	Editting will not display correctly for lines greater then the 
+	terminal width. (more then one line.) However, history will.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+
+#include "input.h"
+#include "output.h"
+
+#ifdef HETIO
+
+#include "hetio.h"
+
+   
+#define  MAX_HISTORY   15			/* Maximum length of the linked list for the command line history */
+
+#define ESC	27
+#define DEL	127
+
+static struct history *his_front = NULL;	/* First element in command line list */
+static struct history *his_end = NULL;		/* Last element in command line list */
+static struct termios old_term, new_term;	/* Current termio and the previous termio before starting ash */
+
+static int history_counter = 0;			/* Number of commands in history list */
+static int reset_term = 0;			/* Set to true if the terminal needs to be reset upon exit */
+static int hetio_inter = 0;
+
+struct history
+{
+   char *s;
+   struct history *p;
+   struct history *n;
+};
+
+
+void input_delete    (int);
+void input_home      (int *);
+void input_end       (int *, int);
+void input_backspace (int *, int *);
+
+
+
+void hetio_init(void)
+{
+	hetio_inter = 1;
+}
+
+
+void hetio_reset_term(void)
+{
+	if (reset_term)
+		tcsetattr(1, TCSANOW, &old_term);
+}
+
+
+void setIO(struct termios *new, struct termios *old)	/* Set terminal IO to canonical mode, and save old term settings. */
+{
+	tcgetattr(0, old);
+	memcpy(new, old, sizeof(*new));
+	new->c_cc[VMIN] = 1;
+	new->c_cc[VTIME] = 0;
+	new->c_lflag &= ~ICANON; /* unbuffered input */
+	new->c_lflag &= ~ECHO;
+	tcsetattr(0, TCSANOW, new);
+}
+
+void input_home(int *cursor)				/* Command line input routines */
+{
+ 	while (*cursor > 0) {
+		out1c('\b');
+		--*cursor;
+	}
+	flushout(&output);
+}
+
+
+void input_delete(int cursor)
+{
+	int j = 0;
+
+	memmove(parsenextc + cursor, parsenextc + cursor + 1,
+		BUFSIZ - cursor - 1);
+	for (j = cursor; j < (BUFSIZ - 1); j++) {
+		if (!*(parsenextc + j))
+			break;
+		else
+			out1c(*(parsenextc + j));
+	}
+
+	out1str(" \b");
+	
+	while (j-- > cursor)
+		out1c('\b');
+	flushout(&output);
+}
+
+
+void input_end(int *cursor, int len)
+{
+	while (*cursor < len) {
+		out1str("\033[C");
+		++*cursor;
+	}
+	flushout(&output);
+}
+
+
+void
+input_backspace(int *cursor, int *len)
+{
+	int j = 0;
+
+	if (*cursor > 0) {
+		out1str("\b \b");
+		--*cursor;
+		memmove(parsenextc + *cursor, parsenextc + *cursor + 1, 
+			BUFSIZ - *cursor + 1);
+		
+		for (j = *cursor; j < (BUFSIZ - 1); j++) {
+			if (!*(parsenextc + j))
+				break;
+			else
+				out1c(*(parsenextc + j));
+		}
+		
+		out1str(" \b");
+		
+		while (j-- > *cursor)
+			out1c('\b');
+		
+		--*len;
+		flushout(&output);
+	}
+}
+
+int hetio_read_input(int fd)
+{
+	int nr = 0;
+
+	if (!hetio_inter) {		/* Are we an interactive shell? */
+		return -255;		
+	} else {
+		int len = 0;
+		int j = 0;
+		int cursor = 0;
+		int break_out = 0;
+		int ret = 0;
+		char c = 0;
+		struct history *hp = his_end;
+
+		if (!reset_term) {
+			setIO(&new_term, &old_term);
+			reset_term = 1;
+		} else {
+			tcsetattr(0, TCSANOW, &new_term);
+		}
+		
+		memset(parsenextc, 0, BUFSIZ);
+		
+		while (1) {
+			if ((ret = read(fd, &c, 1)) < 1)
+				return ret;
+			
+			switch (c) {
+   				case 1:		/* Control-A Beginning of line */
+   					input_home(&cursor);
+					break;
+				case 5:		/* Control-E EOL */
+					input_end(&cursor, len);
+					break;
+				case 4:		/* Control-D */
+#ifndef CTRL_D_DELETE
+					return 0;
+#else
+					if (cursor != len) {
+						input_delete(cursor);
+						len--;
+					}
+					break;
+#endif
+				case '\b':	/* Backspace */
+				case DEL:
+					input_backspace(&cursor, &len);
+					break;
+				case '\n':	/* Enter */
+					*(parsenextc + len++ + 1) = c;
+					out1c(c);
+					flushout(&output);
+					break_out = 1;
+					break;
+				case ESC:	/* escape sequence follows */
+					if ((ret = read(fd, &c, 1)) < 1)
+						return ret;
+										
+					if (c == '[' || c == 'O' ) {    /* 91 */
+						if ((ret = read(fd, &c, 1)) < 1)
+							return ret;
+						
+						switch (c) {
+							case 'A':
+								if (hp && hp->p) {		/* Up */
+									hp = hp->p;
+									goto hop;
+								}
+								break;
+							case 'B':
+								if (hp && hp->n && hp->n->s) {	/* Down */
+									hp = hp->n;
+									goto hop;
+								}
+								break;
+
+hop:						/* hop */							
+								len = strlen(parsenextc);
+
+								for (; cursor > 0; cursor--)		/* return to begining of line */
+									out1c('\b');
+
+		   						for (j = 0; j < len; j++)		/* erase old command */
+									out1c(' ');
+
+								for (j = len; j > 0; j--)		/* return to begining of line */
+									out1c('\b');
+
+								strcpy (parsenextc, hp->s);		/* write new command */
+								len = strlen (hp->s);
+								out1str(parsenextc);
+								flushout(&output);
+								cursor = len;
+								break;
+							case 'C':		/* Right */
+      								if (cursor < len) {
+									out1str("\033[C");
+									cursor++;
+									flushout(&output);
+						 		}
+								break;
+							case 'D':		/* Left */
+								if (cursor > 0) {
+									out1str("\033[D");
+									cursor--;
+									flushout(&output);
+								}
+								break;
+							case '3':		/* Delete */
+								if (cursor != len) {
+									input_delete(cursor);
+									len--;
+								}
+								break;								
+							case 'H':		/* Home (xterm) */
+							case '1':		/* Home (Ctrl-A) */
+      								input_home(&cursor);
+								break;
+							case 'F':		/* End (xterm_ */
+							case '4':		/* End (Ctrl-E) */
+								input_end(&cursor, len);
+								break;
+						}
+						if (c == '1' || c == '3' || c == '4')
+							if ((ret = read(fd, &c, 1)) < 1)
+								return ret;  /* read 126 (~) */
+					}
+			
+					c = 0;
+					break;
+		
+				default:				/* If it's regular input, do the normal thing */
+	       
+					if (!isprint(c))		/* Skip non-printable characters */
+						break;
+							       
+	       				if (len >= (BUFSIZ - 2))	/* Need to leave space for enter */
+		  				break;
+	       		
+					len++;
+			
+					if (cursor == (len - 1)) {	/* Append if at the end of the line */
+						*(parsenextc + cursor) = c;
+					} else {			/* Insert otherwise */
+						memmove(parsenextc + cursor + 1, parsenextc + cursor,
+							len - cursor - 1);
+					
+						*(parsenextc + cursor) = c;
+			
+						for (j = cursor; j < len; j++)
+							out1c(*(parsenextc + j));
+						for (; j > cursor; j--)
+							out1str("\033[D");
+					}
+		
+					cursor++;
+					out1c(c);
+					flushout(&output);
+					break;
+			}
+			
+			if (break_out)		/* Enter is the command terminator, no more input. */
+				break;
+		}
+	
+		nr = len + 1;
+		tcsetattr(0, TCSANOW, &old_term);
+		
+		
+		if (*(parsenextc)) {		/* Handle command history log */
+			struct history *h = his_end;
+  
+			if (!h) {       /* No previous history */
+				h = his_front = malloc(sizeof (struct history));
+				h->n = malloc(sizeof (struct history));
+				h->p = NULL;
+				h->s = strdup(parsenextc);
+
+				h->n->p = h;
+				h->n->n = NULL;
+				h->n->s = NULL;
+				his_end = h->n;
+				history_counter++;
+			} else {	/* Add a new history command */
+  
+				h->n = malloc(sizeof (struct history)); 
+
+				h->n->p = h;
+				h->n->n = NULL;
+				h->n->s = NULL;
+				h->s = strdup(parsenextc);
+				his_end = h->n;
+
+				if (history_counter >= MAX_HISTORY) {	/* After max history, remove the last known command */
+					struct history *p = his_front->n;
+					
+					p->p = NULL;
+					free(his_front->s);
+					free(his_front);
+					his_front = p;
+				} else {
+					history_counter++;
+				}
+			}
+		}
+	} 
+
+	return nr;
+}
+#endif
diff -Nur ash-0.4.0.orig/hetio.h ash-0.4.0.fixed/hetio.h
--- ash-0.4.0.orig/hetio.h	1969-12-31 18:00:00.000000000 -0600
+++ ash-0.4.0.fixed/hetio.h	2003-10-01 21:08:15.000000000 -0500
@@ -0,0 +1,22 @@
+/*
+ * Termios command line History and Editting for NetBSD sh (ash)
+ * Copyright (c) 1999
+ *	Main code:	Adam Rogoyski <rogoyski@cs.utexas.edu> 
+ *	Etc:		Dave Cinege <dcinege@psychosis.com>
+ *
+ * You may use this code as you wish, so long as the original author(s)
+ * are attributed in any redistributions of the source code.
+ * This code is 'as is' with no warranty.
+ * This code may safely be consumed by a BSD or GPL license.
+ *
+ * v 0.5  19990328	Initial release 
+ *
+ * Future plans: Simple file and path name completion. (like BASH)
+ *
+ */
+
+void hetio_init(void);
+int hetio_read_input(int fd);
+void hetio_reset_term(void);
+
+extern int hetio_inter;
diff -Nur ash-0.4.0.orig/histedit.c ash-0.4.0.fixed/histedit.c
--- ash-0.4.0.orig/histedit.c	2001-01-12 10:50:35.000000000 -0600
+++ ash-0.4.0.fixed/histedit.c	2003-10-01 21:08:15.000000000 -0500
@@ -60,9 +60,9 @@
 #include "main.h"
 #include "output.h"
 #include "mystring.h"
-#include "myhistedit.h"
 #include "error.h"
 #ifndef SMALL
+#include "myhistedit.h"
 #include "eval.h"
 #include "memalloc.h"
 
@@ -219,7 +219,11 @@
 	if (argc == 1)
 		error("missing history argument");
 
+#ifdef __GLIBC__
+	optind = 1;
+#else
 	optreset = 1; optind = 1; /* initialize getopt */
+#endif
 	while (not_fcnumber(argv[optind]) &&
 	      (ch = getopt(argc, argv, ":e:lnrs")) != -1)
 		switch ((char)ch) {
diff -Nur ash-0.4.0.orig/input.c ash-0.4.0.fixed/input.c
--- ash-0.4.0.orig/input.c	2000-05-23 05:03:19.000000000 -0500
+++ ash-0.4.0.fixed/input.c	2003-10-01 21:08:15.000000000 -0500
@@ -66,7 +66,13 @@
 #include "error.h"
 #include "alias.h"
 #include "parser.h"
+#ifndef SMALL
 #include "myhistedit.h"
+#endif
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
 
 #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
 
@@ -108,7 +114,9 @@
 int init_editline = 0;		/* editline library initialized? */
 int whichprompt;		/* 1 == PS1, 2 == PS2 */
 
+#ifndef SMALL
 EditLine *el;			/* cookie for editline package */
+#endif
 
 STATIC void pushfile __P((void));
 static int preadfd __P((void));
@@ -198,6 +206,11 @@
 		}
 	} else
 #endif
+
+#ifdef HETIO
+		nr = hetio_read_input(parsefile->fd);
+		if (nr == -255)
+#endif
 		nr = read(parsefile->fd, buf, BUFSIZ - 1);
 
 
diff -Nur ash-0.4.0.orig/jobs.c ash-0.4.0.fixed/jobs.c
--- ash-0.4.0.orig/jobs.c	2000-05-23 05:03:19.000000000 -0500
+++ ash-0.4.0.fixed/jobs.c	2003-10-01 21:08:15.000000000 -0500
@@ -92,6 +92,7 @@
 int initialpgrp;		/* pgrp of shell on invocation */
 short curjob;			/* current job */
 #endif
+STATIC int intreceived;
 
 STATIC void restartjob __P((struct job *));
 STATIC void freejob __P((struct job *));
@@ -101,8 +102,10 @@
 STATIC int waitproc __P((int, int *));
 STATIC void cmdtxt __P((union node *));
 STATIC void cmdputs __P((const char *));
+STATIC void waitonint(int);
 
 
+#if JOBS
 /*
  * Turn job control on and off.
  *
@@ -126,9 +129,9 @@
 	if (on) {
 		do { /* while we are in the background */
 #ifdef OLD_TTY_DRIVER
-			if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
+			if (ioctl(fd2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
 #else
-			initialpgrp = tcgetpgrp(2);
+			initialpgrp = tcgetpgrp(fd2);
 			if (initialpgrp < 0) {
 #endif
 				out2str("sh: can't access tty; job control turned off\n");
@@ -143,7 +146,7 @@
 			}
 		} while (0);
 #ifdef OLD_TTY_DRIVER
-		if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
+		if (ioctl(fd2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
 			out2str("sh: need new tty driver to run job control; job control turned off\n");
 			mflag = 0;
 			return;
@@ -154,16 +157,16 @@
 		setsignal(SIGTTIN);
 		setpgid(0, rootpid);
 #ifdef OLD_TTY_DRIVER
-		ioctl(2, TIOCSPGRP, (char *)&rootpid);
+		ioctl(fd2, TIOCSPGRP, (char *)&rootpid);
 #else
-		tcsetpgrp(2, rootpid);
+		tcsetpgrp(fd2, rootpid);
 #endif
 	} else { /* turning job control off */
 		setpgid(0, initialpgrp);
 #ifdef OLD_TTY_DRIVER
-		ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
+		ioctl(fd2, TIOCSPGRP, (char *)&initialpgrp);
 #else
-		tcsetpgrp(2, initialpgrp);
+		tcsetpgrp(fd2, initialpgrp);
 #endif
 		setsignal(SIGTSTP);
 		setsignal(SIGTTOU);
@@ -171,6 +174,7 @@
 	}
 	jobctl = on;
 }
+#endif
 
 
 #ifdef mkinit
@@ -189,6 +193,94 @@
 
 #if JOBS
 int
+killcmd(argc, argv)
+	int argc;
+	char **argv;
+{
+	extern char *signal_names[];
+	int signo = -1;
+	int list = 0;
+	int i;
+	pid_t pid;
+	struct job *jp;
+
+	if (argc <= 1) {
+		error(
+"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
+"kill -l [exitstatus]"
+		);
+	}
+
+	if (*argv[1] == '-') {
+		signo = decode_signal(argv[1]+1);
+		if (signo < 0) {
+			int c;
+
+			while ((c = nextopt("ls:")) != '\0')
+				switch (c) {
+				case 'l':
+					list = 1;
+					break;
+				case 's':
+					signo = decode_signal(optarg);
+		                        break;
+				default:
+					error(
+	"nextopt returned character code 0%o", c);
+			}
+		} else
+			argptr++;
+	}
+
+	if (!list && signo < 0)
+		signo = SIGTERM;
+
+	if ((signo < 0 || !*argptr) ^ list) {
+		error(
+"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
+"kill -l [exitstatus]"
+		);
+	}
+
+	if (list) {
+		if (!*argptr) {
+			out1fmt("0\n");
+			for (i = 1; i < NSIG; i++) {
+				if (strncmp(signal_names[i], "SIGJUNK(", 8)
+				    == 0)
+					continue;
+				out1fmt("%s\n", signal_names[i] + 3);
+			}
+			return 0;
+		}
+		signo = atoi(*argptr);
+		if (signo > 128)
+			signo -= 128;
+		if (0 < signo && signo < NSIG)
+			out1fmt("%s\n", signal_names[signo] + 3);
+		else
+			error("invalid signal number or exit status: %s",
+			      *argptr);
+		return 0;
+	}
+
+	do {
+		if (**argptr == '%') {
+			jp = getjob(*argptr);
+			if (jp->jobctl == 0)
+				error("job %s not created under job control",
+				      *argptr);
+			pid = -jp->ps[0].pid;
+		} else
+			pid = atoi(*argptr);
+		if (kill(pid, signo) != 0)
+			error("%s: %s", *argptr, strerror(errno));
+	} while (*++argptr);
+
+	return 0;
+}
+
+int
 fgcmd(argc, argv)
 	int argc;
 	char **argv;
@@ -202,9 +294,9 @@
 		error("job not created under job control");
 	pgrp = jp->ps[0].pid;
 #ifdef OLD_TTY_DRIVER
-	ioctl(2, TIOCSPGRP, (char *)&pgrp);
+	ioctl(fd2, TIOCSPGRP, (char *)&pgrp);
 #else
-	tcsetpgrp(2, pgrp);
+	tcsetpgrp(fd2, pgrp);
 #endif
 	restartjob(jp);
 	INTOFF;
@@ -594,9 +686,6 @@
 		TRACE(("Child shell %d\n", getpid()));
 		wasroot = rootshell;
 		rootshell = 0;
-		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
-			if (p->used)
-				freejob(p);
 		closescript();
 		INTON;
 		clear_traps();
@@ -611,10 +700,10 @@
 			if (mode == FORK_FG) {
 				/*** this causes superfluous TIOCSPGRPS ***/
 #ifdef OLD_TTY_DRIVER
-				if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
+				if (ioctl(fd2, TIOCSPGRP, (char *)&pgrp) < 0)
 					error("TIOCSPGRP failed, errno=%d", errno);
 #else
-				if (tcsetpgrp(2, pgrp) < 0)
+				if (tcsetpgrp(fd2, pgrp) < 0)
 					error("tcsetpgrp failed, errno=%d", errno);
 #endif
 			}
@@ -623,6 +712,7 @@
 		} else if (mode == FORK_BG) {
 			ignoresig(SIGINT);
 			ignoresig(SIGQUIT);
+			ignoresig(SIGHUP);
 			if ((jp == NULL || jp->nprocs == 0) &&
 			    ! fd0_redirected_p ()) {
 				close(0);
@@ -634,6 +724,7 @@
 		if (mode == FORK_BG) {
 			ignoresig(SIGINT);
 			ignoresig(SIGQUIT);
+			ignoresig(SIGHUP);
 			if ((jp == NULL || jp->nprocs == 0) &&
 			    ! fd0_redirected_p ()) {
 				close(0);
@@ -642,6 +733,9 @@
 			}
 		}
 #endif
+		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
+			if (p->used)
+				freejob(p);
 		if (wasroot && iflag) {
 			setsignal(SIGINT);
 			setsignal(SIGQUIT);
@@ -701,19 +795,39 @@
 #endif
 	int status;
 	int st;
+	struct sigaction act, oact;
 
 	INTOFF;
+	intreceived = 0;
+#if JOBS
+	if (!jobctl) {
+#else
+	if (!iflag) {
+#endif
+		sigaction(SIGINT, 0, &act);
+		act.sa_handler = waitonint;
+		sigaction(SIGINT, &act, &oact);
+	}
 	TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
 	while (jp->state == 0) {
 		dowait(1, jp);
 	}
 #if JOBS
+	if (!jobctl) {
+#else
+	if (!iflag) {
+#endif
+		extern char *trap[];
+		sigaction(SIGINT, &oact, 0);
+		if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
+	}
+#if JOBS
 	if (jp->jobctl) {
 #ifdef OLD_TTY_DRIVER
-		if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
+		if (ioctl(fd2, TIOCSPGRP, (char *)&mypgrp) < 0)
 			error("TIOCSPGRP failed, errno=%d\n", errno);
 #else
-		if (tcsetpgrp(2, mypgrp) < 0)
+		if (tcsetpgrp(fd2, mypgrp) < 0)
 			error("tcsetpgrp failed, errno=%d\n", errno);
 #endif
 	}
@@ -896,10 +1010,10 @@
 #ifdef BSD
 	int flags;
 
-#if JOBS
-	flags = WUNTRACED;
-#else
 	flags = 0;
+#if JOBS
+	if (jobctl)
+		flags |= WUNTRACED;
 #endif
 	if (block == 0)
 		flags |= WNOHANG;
@@ -1068,6 +1182,8 @@
 		p = ">>";  i = 1;  goto redir;
 	case NTOFD:
 		p = ">&";  i = 1;  goto redir;
+	case NTOOV:
+		p = ">|";  i = 1;  goto redir;
 	case NFROM:
 		p = "<";  i = 0;  goto redir;
 	case NFROMFD:
@@ -1140,3 +1256,8 @@
 	}
 	cmdnextc = q;
 }
+
+STATIC void waitonint(int sig) {
+	intreceived = 1;
+	return;
+}
diff -Nur ash-0.4.0.orig/jobs.h ash-0.4.0.fixed/jobs.h
--- ash-0.4.0.orig/jobs.h	2000-05-23 05:03:19.000000000 -0500
+++ ash-0.4.0.fixed/jobs.h	2003-10-01 21:08:15.000000000 -0500
@@ -80,6 +80,7 @@
 extern int job_warning;		/* user was warned about stopped jobs */
 
 void setjobctl __P((int));
+int killcmd __P((int, char **));
 int fgcmd __P((int, char **));
 int bgcmd __P((int, char **));
 int jobscmd __P((int, char **));
diff -Nur ash-0.4.0.orig/main.c ash-0.4.0.fixed/main.c
--- ash-0.4.0.orig/main.c	2001-01-12 10:50:36.000000000 -0600
+++ ash-0.4.0.fixed/main.c	2003-10-01 21:08:15.000000000 -0500
@@ -79,6 +79,10 @@
 #include "exec.h"
 #include "cd.h"
 
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
 #define PROFILE 0
 
 int rootpid;
@@ -111,10 +115,16 @@
 	struct stackmark smark;
 	volatile int state;
 	char *shinit;
+	int priviliged;
+
+	priviliged = getuid() != geteuid() || getgid() != getegid();
 
 #if PROFILE
 	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
 #endif
+#if defined(linux) || defined(__GNU__)
+	signal(SIGCHLD, SIG_DFL);
+#endif
 	state = 0;
 	if (setjmp(jmploc.loc)) {
 		/*
@@ -181,11 +191,14 @@
 		read_profile("/etc/profile");
 state1:
 		state = 2;
-		read_profile(".profile");
+		if (priviliged == 0)
+			read_profile(".profile");
+		else
+			read_profile("/etc/suid_profile");
 	}
 state2:
 	state = 3;
-	if (getuid() == geteuid() && getgid() == getegid()) {
+	if (iflag && !priviliged) {
 		if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
 			state = 3;
 			read_profile(shinit);
@@ -239,6 +252,10 @@
 
 	TRACE(("cmdloop(%d) called\n", top));
 	setstackmark(&smark);
+#ifdef HETIO
+	if(iflag && top)
+		hetio_init();
+#endif
 	for (;;) {
 		if (pendingsigs)
 			dotrap();
diff -Nur ash-0.4.0.orig/miscbltin.c ash-0.4.0.fixed/miscbltin.c
--- ash-0.4.0.orig/miscbltin.c	2001-01-12 10:50:37.000000000 -0600
+++ ash-0.4.0.fixed/miscbltin.c	2003-10-01 21:08:15.000000000 -0500
@@ -70,6 +70,15 @@
 
 #undef rflag
 
+#ifdef __GLIBC__
+mode_t getmode(const void *, mode_t);
+void *setmode(const char *);
+
+#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
+typedef enum __rlimit_resource rlim_t;
+#endif
+#endif
+
 extern char **argptr;		/* argument list for builtin command */
 
 
diff -Nur ash-0.4.0.orig/mksignames.c ash-0.4.0.fixed/mksignames.c
--- ash-0.4.0.orig/mksignames.c	1969-12-31 18:00:00.000000000 -0600
+++ ash-0.4.0.fixed/mksignames.c	2003-10-01 21:08:15.000000000 -0500
@@ -0,0 +1,400 @@
+/* signames.c -- Create and write `signames.c', which contains an array of
+   signal names. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#if !defined (NSIG)
+#  define NSIG 64
+#endif
+
+char *signal_names[2 * NSIG];
+
+char *progname;
+
+#if defined (SIGRTMAX) || defined (SIGRTMIN)
+#  define RTLEN 14
+#  define RTLIM 256
+#endif
+
+void
+initialize_signames ()
+{
+  register int i;
+#if defined (SIGRTMAX) || defined (SIGRTMIN)
+  int rtmin, rtmax, rtcnt;
+#endif
+
+  for (i = 1; i < sizeof(signal_names)/sizeof(signal_names[0]); i++)
+    signal_names[i] = (char *)NULL;
+
+  /* `signal' 0 is what we do on exit. */
+  signal_names[0] = "EXIT";
+
+  /* Place signal names which can be aliases for more common signal
+     names first.  This allows (for example) SIGABRT to overwrite SIGLOST. */
+
+  /* POSIX 1003.1b-1993 real time signals, but take care of incomplete
+     implementations. Acoording to the standard, both, SIGRTMIN and
+     SIGRTMAX must be defined, SIGRTMIN must be stricly less than
+     SIGRTMAX, and the difference must be at least 7, that is, there
+     must be at least eight distinct real time signals. */
+
+  /* The generated signal names are SIGRTMIN, SIGRTMIN+1, ...,
+     SIGRTMIN+x, SIGRTMAX-x, ..., SIGRTMAX-1, SIGRTMAX. If the number
+     of RT signals is odd, there is an extra SIGRTMIN+(x+1).
+     These names are the ones used by ksh and /usr/xpg4/bin/sh on SunOS5. */
+
+#if defined (SIGRTMIN)
+  rtmin = SIGRTMIN;
+  signal_names[rtmin] = "SIGRTMIN";
+#endif
+
+#if defined (SIGRTMAX)
+  rtmax = SIGRTMAX;
+  signal_names[rtmax] = "SIGRTMAX";
+#endif
+
+#if defined (SIGRTMAX) && defined (SIGRTMIN)
+  if (rtmax > rtmin)
+    {
+      rtcnt = (rtmax - rtmin - 1) / 2;
+      /* croak if there are too many RT signals */
+      if (rtcnt >= RTLIM/2)
+	{
+	  rtcnt = RTLIM/2-1;
+	  fprintf(stderr, "%s: error: more than %i real time signals, fix `%s'\n",
+		  progname, RTLIM, progname);
+	}
+
+      for (i = 1; i <= rtcnt; i++)
+	{
+	  signal_names[rtmin+i] = (char *)malloc(RTLEN);
+	  sprintf (signal_names[rtmin+i], "SIGRTMIN+%d", i);
+	  signal_names[rtmax-i] = (char *)malloc(RTLEN);
+	  sprintf (signal_names[rtmax-i], "SIGRTMAX-%d", i);
+	}
+
+      if (rtcnt < RTLIM/2-1 && rtcnt != (rtmax-rtmin)/2)
+	{
+	  /* Need an extra RTMIN signal */
+	  signal_names[rtmin+rtcnt+1] = (char *)malloc(RTLEN);
+	  sprintf (signal_names[rtmin+rtcnt+1], "SIGRTMIN+%d", rtcnt+1);
+	}
+    }
+#endif /* SIGRTMIN && SIGRTMAX */
+
+/* AIX */
+#if defined (SIGLOST)	/* resource lost (eg, record-lock lost) */
+  signal_names[SIGLOST] = "SIGLOST";
+#endif
+
+#if defined (SIGMSG)	/* HFT input data pending */
+  signal_names[SIGMSG] = "SIGMSG";
+#endif
+
+#if defined (SIGDANGER)	/* system crash imminent */
+  signal_names[SIGDANGER] = "SIGDANGER";
+#endif
+
+#if defined (SIGMIGRATE) /* migrate process to another CPU */
+  signal_names[SIGMIGRATE] = "SIGMIGRATE";
+#endif
+
+#if defined (SIGPRE)	/* programming error */
+  signal_names[SIGPRE] = "SIGPRE";
+#endif
+
+#if defined (SIGVIRT)	/* AIX virtual time alarm */
+  signal_names[SIGVIRT] = "SIGVIRT";
+#endif
+
+#if defined (SIGALRM1)	/* m:n condition variables */
+  signal_names[SIGALRM1] = "SIGALRM1";
+#endif
+
+#if defined (SIGWAITING)	/* m:n scheduling */
+  signal_names[SIGWAITING] = "SIGWAITING";
+#endif
+
+#if defined (SIGGRANT)	/* HFT monitor mode granted */
+  signal_names[SIGGRANT] = "SIGGRANT";
+#endif
+
+#if defined (SIGKAP)	/* keep alive poll from native keyboard */
+  signal_names[SIGKAP] = "SIGKAP";
+#endif
+
+#if defined (SIGRETRACT) /* HFT monitor mode retracted */
+  signal_names[SIGRETRACT] = "SIGRETRACT";
+#endif
+
+#if defined (SIGSOUND)	/* HFT sound sequence has completed */
+  signal_names[SIGSOUND] = "SIGSOUND";
+#endif
+
+#if defined (SIGSAK)	/* Secure Attention Key */
+  signal_names[SIGSAK] = "SIGSAK";
+#endif
+
+/* SunOS5 */
+#if defined (SIGLWP)	/* special signal used by thread library */
+  signal_names[SIGLWP] = "SIGLWP";
+#endif
+
+#if defined (SIGFREEZE)	/* special signal used by CPR */
+  signal_names[SIGFREEZE] = "SIGFREEZE";
+#endif
+
+#if defined (SIGTHAW)	/* special signal used by CPR */
+  signal_names[SIGTHAW] = "SIGTHAW";
+#endif
+
+#if defined (SIGCANCEL)	/* thread cancellation signal used by libthread */
+  signal_names[SIGCANCEL] = "SIGCANCEL";
+#endif
+
+/* HP-UX */
+#if defined (SIGDIL)	/* DIL signal (?) */
+  signal_names[SIGDIL] = "SIGDIL";
+#endif
+
+/* System V */
+#if defined (SIGCLD)	/* Like SIGCHLD.  */
+  signal_names[SIGCLD] = "SIGCLD";
+#endif
+
+#if defined (SIGPWR)	/* power state indication */
+  signal_names[SIGPWR] = "SIGPWR";
+#endif
+
+#if defined (SIGPOLL)	/* Pollable event (for streams)  */
+  signal_names[SIGPOLL] = "SIGPOLL";
+#endif
+
+/* Unknown */
+#if defined (SIGWINDOW)
+  signal_names[SIGWINDOW] = "SIGWINDOW";
+#endif
+
+/* Common */
+#if defined (SIGHUP)	/* hangup */
+  signal_names[SIGHUP] = "SIGHUP";
+#endif
+
+#if defined (SIGINT)	/* interrupt */
+  signal_names[SIGINT] = "SIGINT";
+#endif
+
+#if defined (SIGQUIT)	/* quit */
+  signal_names[SIGQUIT] = "SIGQUIT";
+#endif
+
+#if defined (SIGILL)	/* illegal instruction (not reset when caught) */
+  signal_names[SIGILL] = "SIGILL";
+#endif
+
+#if defined (SIGTRAP)	/* trace trap (not reset when caught) */
+  signal_names[SIGTRAP] = "SIGTRAP";
+#endif
+
+#if defined (SIGIOT)	/* IOT instruction */
+  signal_names[SIGIOT] = "SIGIOT";
+#endif
+
+#if defined (SIGABRT)	/* Cause current process to dump core. */
+  signal_names[SIGABRT] = "SIGABRT";
+#endif
+
+#if defined (SIGEMT)	/* EMT instruction */
+  signal_names[SIGEMT] = "SIGEMT";
+#endif
+
+#if defined (SIGFPE)	/* floating point exception */
+  signal_names[SIGFPE] = "SIGFPE";
+#endif
+
+#if defined (SIGKILL)	/* kill (cannot be caught or ignored) */
+  signal_names[SIGKILL] = "SIGKILL";
+#endif
+
+#if defined (SIGBUS)	/* bus error */
+  signal_names[SIGBUS] = "SIGBUS";
+#endif
+
+#if defined (SIGSEGV)	/* segmentation violation */
+  signal_names[SIGSEGV] = "SIGSEGV";
+#endif
+
+#if defined (SIGSYS)	/* bad argument to system call */
+  signal_names[SIGSYS] = "SIGSYS";
+#endif
+
+#if defined (SIGPIPE)	/* write on a pipe with no one to read it */
+  signal_names[SIGPIPE] = "SIGPIPE";
+#endif
+
+#if defined (SIGALRM)	/* alarm clock */
+  signal_names[SIGALRM] = "SIGALRM";
+#endif
+
+#if defined (SIGTERM)	/* software termination signal from kill */
+  signal_names[SIGTERM] = "SIGTERM";
+#endif
+
+#if defined (SIGURG)	/* urgent condition on IO channel */
+  signal_names[SIGURG] = "SIGURG";
+#endif
+
+#if defined (SIGSTOP)	/* sendable stop signal not from tty */
+  signal_names[SIGSTOP] = "SIGSTOP";
+#endif
+
+#if defined (SIGTSTP)	/* stop signal from tty */
+  signal_names[SIGTSTP] = "SIGTSTP";
+#endif
+
+#if defined (SIGCONT)	/* continue a stopped process */
+  signal_names[SIGCONT] = "SIGCONT";
+#endif
+
+#if defined (SIGCHLD)	/* to parent on child stop or exit */
+  signal_names[SIGCHLD] = "SIGCHLD";
+#endif
+
+#if defined (SIGTTIN)	/* to readers pgrp upon background tty read */
+  signal_names[SIGTTIN] = "SIGTTIN";
+#endif
+
+#if defined (SIGTTOU)	/* like TTIN for output if (tp->t_local&LTOSTOP) */
+  signal_names[SIGTTOU] = "SIGTTOU";
+#endif
+
+#if defined (SIGIO)	/* input/output possible signal */
+  signal_names[SIGIO] = "SIGIO";
+#endif
+
+#if defined (SIGXCPU)	/* exceeded CPU time limit */
+  signal_names[SIGXCPU] = "SIGXCPU";
+#endif
+
+#if defined (SIGXFSZ)	/* exceeded file size limit */
+  signal_names[SIGXFSZ] = "SIGXFSZ";
+#endif
+
+#if defined (SIGVTALRM)	/* virtual time alarm */
+  signal_names[SIGVTALRM] = "SIGVTALRM";
+#endif
+
+#if defined (SIGPROF)	/* profiling time alarm */
+  signal_names[SIGPROF] = "SIGPROF";
+#endif
+
+#if defined (SIGWINCH)	/* window changed */
+  signal_names[SIGWINCH] = "SIGWINCH";
+#endif
+
+/* 4.4 BSD */
+#if defined (SIGINFO) && !defined (_SEQUENT_)	/* information request */
+  signal_names[SIGINFO] = "SIGINFO";
+#endif
+
+#if defined (SIGUSR1)	/* user defined signal 1 */
+  signal_names[SIGUSR1] = "SIGUSR1";
+#endif
+
+#if defined (SIGUSR2)	/* user defined signal 2 */
+  signal_names[SIGUSR2] = "SIGUSR2";
+#endif
+
+#if defined (SIGKILLTHR)	/* BeOS: Kill Thread */
+  signal_names[SIGKILLTHR] = "SIGKILLTHR";
+#endif
+
+  for (i = 0; i < NSIG; i++)
+    if (signal_names[i] == (char *)NULL)
+      {
+	signal_names[i] = (char *)malloc (18);
+	sprintf (signal_names[i], "SIGJUNK(%d)", i);
+      }
+
+  signal_names[NSIG] = "DEBUG";
+}
+
+void
+write_signames (stream)
+     FILE *stream;
+{
+  register int i;
+
+  fprintf (stream, "/* This file was automatically created by %s.\n",
+	   progname);
+  fprintf (stream, "   Do not edit.  Edit support/mksignames.c instead. */\n\n");
+  fprintf (stream, "#include <signal.h>\n\n");
+  fprintf (stream,
+	   "/* A translation list so we can be polite to our users. */\n");
+  fprintf (stream, "char *signal_names[NSIG + 2] = {\n");
+
+  for (i = 0; i <= NSIG; i++)
+    fprintf (stream, "    \"%s\",\n", signal_names[i]);
+
+  fprintf (stream, "    (char *)0x0,\n");
+  fprintf (stream, "};\n");
+}
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  char *stream_name;
+  FILE *stream;
+
+  progname = argv[0];
+
+  if (argc == 1)
+    {
+      stream_name = "signames.c";
+    }
+  else if (argc == 2)
+    {
+      stream_name = argv[1];
+    }
+  else
+    {
+      fprintf (stderr, "Usage: %s [output-file]\n", progname);
+      exit (1);
+    }
+
+  stream = fopen (stream_name, "w");
+  if (!stream)
+    {
+      fprintf (stderr, "%s: %s: cannot open for writing\n",
+	       progname, stream_name);
+      exit (2);
+    }
+
+  initialize_signames ();
+  write_signames (stream);
+  exit (0);
+}
diff -Nur ash-0.4.0.orig/mksyntax.c ash-0.4.0.fixed/mksyntax.c
--- ash-0.4.0.orig/mksyntax.c	2001-01-12 10:50:38.000000000 -0600
+++ ash-0.4.0.fixed/mksyntax.c	2003-10-01 21:08:15.000000000 -0500
@@ -238,14 +238,14 @@
 	add("$", "CVAR");
 	add("}", "CENDVAR");
 	/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
-	add("!*?[=~:/-", "CCTL");
+	add("!*?[=~:/-]", "CCTL");
 	print("dqsyntax");
 	init();
 	fputs("\n/* syntax table used when in single quotes */\n", cfile);
 	add("\n", "CNL");
 	add("'", "CENDQUOTE");
 	/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
-	add("!*?[=~:/-", "CCTL");
+	add("!*?[=~:/-]\\", "CCTL");
 	print("sqsyntax");
 	init();
 	fputs("\n/* syntax table used when in arithmetic */\n", cfile);
diff -Nur ash-0.4.0.orig/nodetypes ash-0.4.0.fixed/nodetypes
--- ash-0.4.0.orig/nodetypes	1999-02-05 06:04:52.000000000 -0600
+++ ash-0.4.0.fixed/nodetypes	2003-10-01 21:08:15.000000000 -0500
@@ -119,6 +119,7 @@
 NFROM nfile			# fd< fname
 NFROMTO nfile			# fd<> fname
 NAPPEND nfile			# fd>> fname
+NTOOV nfile			# fd>| fname
 	type	  int
 	next	  nodeptr		# next redirection in list
 	fd	  int			# file descriptor being redirected
diff -Nur ash-0.4.0.orig/options.c ash-0.4.0.fixed/options.c
--- ash-0.4.0.orig/options.c	1999-07-09 06:02:07.000000000 -0500
+++ ash-0.4.0.fixed/options.c	2003-10-01 21:08:15.000000000 -0500
@@ -79,7 +79,7 @@
 STATIC void options __P((int));
 STATIC void minus_o __P((char *, int));
 STATIC void setoption __P((int, int));
-STATIC int getopts __P((char *, char *, char **, char ***, char **));
+STATIC int getopts __P((char *, char *, char **, int *, int *));
 
 
 /*
@@ -118,7 +118,8 @@
 	        arg0 = *argptr++;
 
 	shellparam.p = argptr;
-	shellparam.reset = 1;
+	shellparam.optind = 1;
+	shellparam.optoff = -1;
 	/* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
 	while (*argptr) {
 		shellparam.nparam++;
@@ -282,7 +283,8 @@
 	shellparam.malloc = 1;
 	shellparam.nparam = nparam;
 	shellparam.p = newparam;
-	shellparam.optnext = NULL;
+	shellparam.optind = 1;
+	shellparam.optoff = -1;
 }
 
 
@@ -330,7 +332,8 @@
 	}
 	ap2 = shellparam.p;
 	while ((*ap2++ = *ap1++) != NULL);
-	shellparam.optnext = NULL;
+	shellparam.optind = 1;
+	shellparam.optoff = -1;
 	INTON;
 	return 0;
 }
@@ -363,10 +366,8 @@
 getoptsreset(value)
 	const char *value;
 {
-	if (number(value) == 1) {
-		shellparam.optnext = NULL;
-		shellparam.reset = 1;
-	}
+	shellparam.optind = number(value);
+	shellparam.optoff = -1;
 }
 
 /*
@@ -385,50 +386,58 @@
 
 	if (argc < 3)
 		error("Usage: getopts optstring var [arg]");
-	else if (argc == 3)
+	else if (argc == 3) {
 		optbase = shellparam.p;
-	else
+		if (shellparam.optind > shellparam.nparam + 1) {
+			shellparam.optind = 1;
+			shellparam.optoff = -1;
+		}
+	}
+	else {
 		optbase = &argv[3];
-
-	if (shellparam.reset == 1) {
-		shellparam.optnext = optbase;
-		shellparam.optptr = NULL;
-		shellparam.reset = 0;
+		if (shellparam.optind > argc - 2) {
+			shellparam.optind = 1;
+			shellparam.optoff = -1;
+		}
 	}
 
-	return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
-		       &shellparam.optptr);
+	return getopts(argv[1], argv[2], optbase, &shellparam.optind,
+		       &shellparam.optoff);
 }
 
 STATIC int
-getopts(optstr, optvar, optfirst, optnext, optpptr)
+getopts(optstr, optvar, optfirst, optind, optoff)
 	char *optstr;
 	char *optvar;
 	char **optfirst;
-	char ***optnext;
-	char **optpptr;
+	int *optind;
+	int *optoff;
 {
 	char *p, *q;
 	char c = '?';
 	int done = 0;
-	int ind = 0;
 	int err = 0;
 	char s[10];
+	char **optnext = optfirst + *optind - 1;
 
-	if ((p = *optpptr) == NULL || *p == '\0') {
+	if (*optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
+	    strlen(*(optnext - 1)) < *optoff)
+		p = NULL;
+	else
+		p = *(optnext - 1) + *optoff;
+	if (p == NULL || *p == '\0') {
 		/* Current word is done, advance */
-		if (*optnext == NULL)
+		if (optnext == NULL)
 			return 1;
-		p = **optnext;
+		p = *optnext;
 		if (p == NULL || *p != '-' || *++p == '\0') {
 atend:
-			ind = *optnext - optfirst + 1;
-			*optnext = NULL;
+			*optind = optnext - optfirst + 1;
 			p = NULL;
 			done = 1;
 			goto out;
 		}
-		(*optnext)++;
+		optnext++;
 		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
 			goto atend;
 	}
@@ -453,7 +462,7 @@
 	}
 
 	if (*++q == ':') {
-		if (*p == '\0' && (p = **optnext) == NULL) {
+		if (*p == '\0' && (p = *optnext) == NULL) {
 			if (optstr[0] == ':') {
 				s[0] = c;
 				s[1] = '\0';
@@ -468,30 +477,29 @@
 			goto bad;
 		}
 
-		if (p == **optnext)
-			(*optnext)++;
+		if (p == *optnext)
+			optnext++;
 		setvarsafe("OPTARG", p, 0);
 		p = NULL;
 	}
 	else
 		setvarsafe("OPTARG", "", 0);
-	ind = *optnext - optfirst + 1;
+	*optind = optnext - optfirst + 1;
 	goto out;
 
 bad:
-	ind = 1;
-	*optnext = NULL;
+	*optind = 1;
 	p = NULL;
 out:
-	*optpptr = p;
-	fmtstr(s, sizeof(s), "%d", ind);
+	*optoff = p ? p - *(optnext - 1) : -1;
+	fmtstr(s, sizeof(s), "%d", *optind);
 	err |= setvarsafe("OPTIND", s, VNOFUNC);
 	s[0] = c;
 	s[1] = '\0';
 	err |= setvarsafe(optvar, s, 0);
 	if (err) {
-		*optnext = NULL;
-		*optpptr = NULL;
+		*optind = 1;
+		*optoff = -1;
 		flushall();
 		exraise(EXERROR);
 	}
diff -Nur ash-0.4.0.orig/options.h ash-0.4.0.fixed/options.h
--- ash-0.4.0.orig/options.h	1999-07-09 06:02:07.000000000 -0500
+++ ash-0.4.0.fixed/options.h	2003-10-01 21:08:15.000000000 -0500
@@ -41,10 +41,9 @@
 struct shparam {
 	int nparam;		/* # of positional parameters (without $0) */
 	unsigned char malloc;	/* if parameter list dynamically allocated */
-	unsigned char reset;	/* if getopts has been reset */
 	char **p;		/* parameter list */
-	char **optnext;		/* next parameter to be processed by getopts */
-	char *optptr;		/* used by getopts */
+	int optind;		/* next parameter to be processed by getopts */
+	int optoff;		/* used by getopts */
 };
 
 
diff -Nur ash-0.4.0.orig/output.c ash-0.4.0.fixed/output.c
--- ash-0.4.0.orig/output.c	2001-01-12 10:50:39.000000000 -0600
+++ ash-0.4.0.fixed/output.c	2003-10-01 21:08:15.000000000 -0500
@@ -65,6 +65,10 @@
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+#undef CEOF			/* get rid of the redefine warning */
+#include <fcntl.h>
+#endif
 
 #include "shell.h"
 #include "syntax.h"
@@ -79,9 +83,15 @@
 #define OUTPUT_ERR 01		/* error occurred on output */
 
 
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
+struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
+struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
+#else
 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
 struct output errout = {NULL, 0, NULL, 100, 2, 0};
 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
+#endif
 struct output *out1 = &output;
 struct output *out2 = &errout;
 
@@ -92,9 +102,19 @@
 INCLUDE "output.h"
 INCLUDE "memalloc.h"
 
+INIT {
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+	initstreams();
+#endif
+}
+
 RESET {
 	out1 = &output;
 	out2 = &errout;
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+	if (memout.stream != NULL)
+		closememout();
+#endif
 	if (memout.buf != NULL) {
 		ckfree(memout.buf);
 		memout.buf = NULL;
@@ -124,33 +144,22 @@
 
 
 void
-out1str(p)
-	const char *p;
-	{
-	outstr(p, out1);
-}
-
-
-void
-out2str(p)
-	const char *p;
-	{
-	outstr(p, out2);
-}
-
-
-void
 outstr(p, file)
 	const char *p;
 	struct output *file;
 	{
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+	fputs(p, file->stream);
+#else
 	while (*p)
 		outc(*p++, file);
+#endif
 	if (file == out2)
 		flushout(file);
 }
 
 
+#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
 char out_junk[16];
 
 
@@ -183,6 +192,7 @@
 	}
 	dest->nleft--;
 }
+#endif
 
 
 void
@@ -192,11 +202,11 @@
 }
 
 
+#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
 void
 flushout(dest)
 	struct output *dest;
 	{
-
 	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
 		return;
 	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
@@ -204,6 +214,7 @@
 	dest->nextc = dest->buf;
 	dest->nleft = dest->bufsize;
 }
+#endif
 
 
 void
@@ -264,6 +275,7 @@
 	va_end(ap);
 }
 
+#if !defined(__GLIBC__) && !defined(__UCLIBC__)
 void
 #ifdef __STDC__
 dprintf(const char *fmt, ...)
@@ -285,6 +297,7 @@
 	va_end(ap);
 	flushout(out2);
 }
+#endif
 
 void
 #ifdef __STDC__
@@ -295,7 +308,9 @@
 #endif
 {
 	va_list ap;
+#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
 	struct output strout;
+#endif
 #ifndef __STDC__
 	char *outbuf;
 	size_t length;
@@ -308,6 +323,9 @@
 #else
 	va_start(ap, fmt);
 #endif
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+	vsnprintf(outbuf, length, fmt, ap);
+#else
 	strout.nextc = outbuf;
 	strout.nleft = length;
 	strout.fd = BLOCK_OUT;
@@ -316,8 +334,10 @@
 	outc('\0', &strout);
 	if (strout.flags & OUTPUT_ERR)
 		outbuf[length - 1] = '\0';
+#endif
 }
 
+#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
 /*
  * Formatted output.  This routine handles a subset of the printf formats:
  * - Formats supported: d, u, o, p, X, s, and c.
@@ -534,7 +554,7 @@
 	}
 #endif	/* !HAVE_VASPRINTF */
 }
-
+#endif
 
 
 /*
@@ -544,7 +564,7 @@
 int
 xwrite(fd, buf, nbytes)
 	int fd;
-	char *buf;
+	const char *buf;
 	int nbytes;
 	{
 	int ntry;
@@ -570,6 +590,8 @@
 }
 
 
+
+#ifdef notdef
 /*
  * Version of ioctl that retries after a signal is caught.
  * XXX unused function
@@ -586,3 +608,27 @@
 	while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
 	return i;
 }
+#endif
+
+
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+void initstreams() {
+	output.stream = stdout;
+	errout.stream = stderr;
+}
+
+
+void
+openmemout() {
+	memout.stream = open_memstream(&memout.buf, &memout.bufsize);
+}
+
+
+void
+closememout() {
+	INTOFF;
+	fclose(memout.stream);
+	memout.stream = NULL;
+	INTON;
+}
+#endif
diff -Nur ash-0.4.0.orig/output.h ash-0.4.0.fixed/output.h
--- ash-0.4.0.orig/output.h	1998-01-31 12:28:11.000000000 -0600
+++ ash-0.4.0.fixed/output.h	2003-10-01 21:08:15.000000000 -0500
@@ -45,13 +45,19 @@
 #else
 #include <varargs.h>
 #endif
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+#include <stdio.h>
+#endif
 
 struct output {
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+	FILE *stream;
+#endif
 	char *nextc;
 	int nleft;
 	char *buf;
 	int bufsize;
-	short fd;
+	int fd;
 	short flags;
 };
 
@@ -61,29 +67,44 @@
 extern struct output *out1;
 extern struct output *out2;
 
-void open_mem __P((char *, int, struct output *));
-void out1str __P((const char *));
-void out2str __P((const char *));
 void outstr __P((const char *, struct output *));
+#ifndef _GNU_SOURCE
 void emptyoutbuf __P((struct output *));
+#endif
 void flushall __P((void));
+#ifndef _GNU_SOURCE
 void flushout __P((struct output *));
+#endif
 void freestdout __P((void));
 void outfmt __P((struct output *, const char *, ...))
     __attribute__((__format__(__printf__,2,3)));
 void out1fmt __P((const char *, ...))
     __attribute__((__format__(__printf__,1,2)));
+#if !defined(__GLIBC__) && !defined(__UCLIBC__)
 void dprintf __P((const char *, ...))
     __attribute__((__format__(__printf__,1,2)));
+#endif
 void fmtstr __P((char *, size_t, const char *, ...))
     __attribute__((__format__(__printf__,3,4)));
+#ifndef _GNU_SOURCE
 void doformat __P((struct output *, const char *, va_list));
-int xwrite __P((int, char *, int));
-int xioctl __P((int, unsigned long, char *));
+#endif
+int xwrite __P((int, const char *, int));
+#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
+void initstreams __P((void));
+void openmemout __P((void));
+void closememout __P((void));
 
+#define outc(c, o)	putc(c, (o)->stream)
+#define flushout(o)	fflush((o)->stream)
+#define doformat(d, f, a)	vfprintf((d)->stream, f, a)
+#else
 #define outc(c, file)	(--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
-#define out1c(c)	outc(c, out1);
-#define out2c(c)	outc(c, out2);
+#endif
+#define out1c(c)	outc(c, out1)
+#define out2c(c)	outc(c, out2)
+#define out1str(s)	outstr(s, out1)
+#define out2str(s)	outstr(s, out2)
 
 #define OUTPUT_INCL
 #endif
diff -Nur ash-0.4.0.orig/parser.c ash-0.4.0.fixed/parser.c
--- ash-0.4.0.orig/parser.c	2001-01-12 10:50:39.000000000 -0600
+++ ash-0.4.0.fixed/parser.c	2003-10-01 21:08:15.000000000 -0500
@@ -221,6 +221,7 @@
 	union node *n1, *n2, *n3;
 	int t;
 
+	checkkwd = 1;
 	n1 = pipeline();
 	for (;;) {
 		if ((t = readtoken()) == TAND) {
@@ -231,6 +232,7 @@
 			tokpushback++;
 			return n1;
 		}
+		checkkwd = 2;
 		n2 = pipeline();
 		n3 = (union node *)stalloc(sizeof (struct nbinary));
 		n3->type = t;
@@ -250,9 +252,11 @@
 
 	negate = 0;
 	TRACE(("pipeline: entered\n"));
-	while (readtoken() == TNOT)
+	if (readtoken() == TNOT) {
 		negate = !negate;
-	tokpushback++;
+		checkkwd = 1;
+	} else
+		tokpushback++;
 	n1 = command();
 	if (readtoken() == TPIPE) {
 		pipenode = (union node *)stalloc(sizeof (struct npipe));
@@ -264,6 +268,7 @@
 		do {
 			prev = lp;
 			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+			checkkwd = 2;
 			lp->n = command();
 			prev->next = lp;
 		} while (readtoken() == TPIPE);
@@ -288,9 +293,8 @@
 	union node *ap, **app;
 	union node *cp, **cpp;
 	union node *redir, **rpp;
-	int t, negate = 0;
+	int t;
 
-	checkkwd = 2;
 	redir = NULL;
 	n1 = NULL;
 	rpp = &redir;
@@ -303,12 +307,6 @@
 	}
 	tokpushback++;
 
-	while (readtoken() == TNOT) {
-		TRACE(("command: TNOT recognized\n"));
-		negate = !negate;
-	}
-	tokpushback++;
-
 	switch (readtoken()) {
 	case TIF:
 		n1 = (union node *)stalloc(sizeof (struct nif));
@@ -417,6 +415,8 @@
 		cpp = &n1->ncase.cases;
 		checkkwd = 2, readtoken();
 		do {
+			if (lasttoken == TLP)
+				readtoken();
 			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
 			cp->type = NCLIST;
 			app = &cp->nclist.pattern;
@@ -464,21 +464,22 @@
 		break;
 	/* Handle an empty command like other simple commands.  */
 	case TSEMI:
+	case TAND:
+	case TOR:
+	case TNL:
+	case TEOF:
+	case TRP:
+	case TBACKGND:
 		/*
 		 * An empty command before a ; doesn't make much sense, and
 		 * should certainly be disallowed in the case of `if ;'.
 		 */
 		if (!redir)
 			synexpect(-1);
-	case TAND:
-	case TOR:
-	case TNL:
-	case TEOF:
 	case TWORD:
-	case TRP:
 		tokpushback++;
 		n1 = simplecmd(rpp, redir);
-		goto checkneg;
+		return n1;
 	default:
 		synexpect(-1);
 		/* NOTREACHED */
@@ -502,15 +503,7 @@
 		n1->nredir.redirect = redir;
 	}
 
-checkneg:
-	if (negate) {
-		n2 = (union node *)stalloc(sizeof (struct nnot));
-		n2->type = NNOT;
-		n2->nnot.com = n1;
-		return n2;
-	}
-	else
-		return n1;
+	return n1;
 }
 
 
@@ -520,8 +513,7 @@
 	{
 	union node *args, **app;
 	union node **orig_rpp = rpp;
-	union node *n = NULL, *n2;
-	int negate = 0;
+	union node *n = NULL;
 
 	/* If we don't have any redirections already, then we must reset */
 	/* rpp to be the address of the local redir variable.  */
@@ -537,12 +529,6 @@
 	 */
 	orig_rpp = rpp;
 
-	while (readtoken() == TNOT) {
-		TRACE(("command: TNOT recognized\n"));
-		negate = !negate;
-	}
-	tokpushback++;
-
 	for (;;) {
 		if (readtoken() == TWORD) {
 			n = (union node *)stalloc(sizeof (struct narg));
@@ -565,8 +551,9 @@
 				synerror("Bad function name");
 #endif
 			n->type = NDEFUN;
+			checkkwd = 2;
 			n->narg.next = command();
-			goto checkneg;
+			return n;
 		} else {
 			tokpushback++;
 			break;
@@ -579,16 +566,7 @@
 	n->ncmd.backgnd = 0;
 	n->ncmd.args = args;
 	n->ncmd.redirect = redir;
-
-checkneg:
-	if (negate) {
-		n2 = (union node *)stalloc(sizeof (struct nnot));
-		n2->type = NNOT;
-		n2->nnot.com = n;
-		return n2;
-	}
-	else
-		return n;
+	return n;
 }
 
 STATIC union node *
@@ -743,7 +721,7 @@
 			}
 		}
 out:
-		checkkwd = (t == TNOT) ? savecheckkwd : 0;
+		checkkwd = 0;
 	}
 #ifdef DEBUG
 	if (!alreadyseen)
@@ -882,6 +860,7 @@
 	int varnest;	/* levels of variables expansion */
 	int arinest;	/* levels of arithmetic expansion */
 	int parenlevel;	/* levels of parens in arithmetic */
+	int dqvarnest;	/* levels of variables expansion within double quotes */
 	int oldstyle;
 	char const *prevsyntax;	/* syntax before arithmetic */
 #if __GNUC__
@@ -892,6 +871,7 @@
 	(void) &varnest;
 	(void) &arinest;
 	(void) &parenlevel;
+	(void) &dqvarnest;
 	(void) &oldstyle;
 	(void) &prevsyntax;
 	(void) &syntax;
@@ -906,6 +886,7 @@
 	varnest = 0;
 	arinest = 0;
 	parenlevel = 0;
+	dqvarnest = 0;
 
 	STARTSTACKSTR(out);
 	loop: {	/* for each line, until end of word */
@@ -938,7 +919,8 @@
 				USTPUTC(c, out);
 				break;
 			case CCTL:
-				if (eofmark == NULL || dblquote)
+				if ((eofmark == NULL || dblquote) &&
+				    dqvarnest == 0)
 					USTPUTC(CTLESC, out);
 				USTPUTC(c, out);
 				break;
@@ -983,7 +965,8 @@
 					if (arinest) {
 						syntax = ARISYNTAX;
 						dblquote = 0;
-					} else if (eofmark == NULL) {
+					} else if (eofmark == NULL &&
+						   dqvarnest == 0) {
 						syntax = BASESYNTAX;
 						dblquote = 0;
 					}
@@ -996,6 +979,9 @@
 			case CENDVAR:	/* '}' */
 				if (varnest > 0) {
 					varnest--;
+					if (dqvarnest > 0) {
+						dqvarnest--;
+					}
 					USTPUTC(CTLENDVAR, out);
 				} else {
 					USTPUTC(c, out);
@@ -1125,6 +1111,8 @@
 			np->type = NAPPEND;
 		else if (c == '&')
 			np->type = NTOFD;
+		else if (c == '|')
+			np->type = NTOOV;
 		else {
 			np->type = NTO;
 			pungetc();
@@ -1260,8 +1248,12 @@
 		if (dblquote || arinest)
 			flags |= VSQUOTE;
 		*(stackblock() + typeloc) = subtype | flags;
-		if (subtype != VSNORMAL)
+		if (subtype != VSNORMAL) {
 			varnest++;
+			if (dblquote) {
+				dqvarnest++;
+			}
+		}
 	}
 	goto parsesub_return;
 }
diff -Nur ash-0.4.0.orig/redir.c ash-0.4.0.fixed/redir.c
--- ash-0.4.0.orig/redir.c	2000-05-23 05:03:19.000000000 -0500
+++ ash-0.4.0.fixed/redir.c	2003-10-01 21:08:15.000000000 -0500
@@ -45,6 +45,7 @@
 #endif
 #endif /* not lint */
 
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/param.h>	/* PIPE_BUF */
 #include <signal.h>
@@ -66,6 +67,7 @@
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
+#include "options.h"
 
 
 #define EMPTY -2		/* marks an unused slot in redirtab */
@@ -92,8 +94,15 @@
 */
 int fd0_redirected = 0;
 
-STATIC void openredirect __P((union node *, char[10 ]));
+/*
+ * We also keep track of where fd2 goes.
+ */
+int fd2 = 2;
+
+STATIC int openredirect __P((union node *));
+STATIC void dupredirect __P((union node *, int, char[10 ]));
 STATIC int openhere __P((union node *));
+STATIC int noclobberopen __P((const char *));
 
 
 /*
@@ -113,6 +122,7 @@
 	struct redirtab *sv = NULL;
 	int i;
 	int fd;
+	int newfd;
 	int try;
 	char memory[10];	/* file descriptors to write to memory */
 
@@ -133,36 +143,47 @@
 		    n->ndup.dupfd == fd)
 			continue; /* redirect from/to same file descriptor */
 
-		if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
-			INTOFF;
-again:
-			if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
+		INTOFF;
+		newfd = openredirect(n);
+		if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
+		    (fd == fd2)) {
+			if (newfd == fd) {
+				try++;
+			} else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
 				switch (errno) {
 				case EBADF:
 					if (!try) {
-						openredirect(n, memory);
+						dupredirect(n, newfd, memory);
 						try++;
-						goto again;
+						break;
 					}
 					/* FALLTHROUGH*/
 				default:
+					if (newfd >= 0) {
+						close(newfd);
+					}
 					INTON;
 					error("%d: %s", fd, strerror(errno));
 					/* NOTREACHED */
 				}
 			}
 			if (!try) {
-				sv->renamed[fd] = i;
 				close(fd);
+				if (flags & REDIR_PUSH) {
+					sv->renamed[fd] = i;
+				}
+				if (fd == fd2) {
+					fd2 = i;
+				}
 			}
-			INTON;
-		} else {
+		} else if (fd != newfd) {
 			close(fd);
 		}
                 if (fd == 0)
                         fd0_redirected++;
 		if (!try)
-			openredirect(n, memory);
+			dupredirect(n, newfd, memory);
+		INTON;
 	}
 	if (memory[1])
 		out1 = &memout;
@@ -171,22 +192,13 @@
 }
 
 
-STATIC void
-openredirect(redir, memory)
+STATIC int
+openredirect(redir)
 	union node *redir;
-	char memory[10];
 	{
-	int fd = redir->nfile.fd;
 	char *fname;
 	int f;
 
-	/*
-	 * We suppress interrupts so that we won't leave open file
-	 * descriptors around.  This may not be such a good idea because
-	 * an open of a device or a fifo can block indefinitely.
-	 */
-	INTOFF;
-	memory[fd] = 0;
 	switch (redir->nfile.type) {
 	case NFROM:
 		fname = redir->nfile.expfname;
@@ -199,6 +211,14 @@
 			goto ecreate;
 		break;
 	case NTO:
+		/* Take care of noclobber mode. */
+		if (Cflag) {
+			fname = redir->nfile.expfname;
+			if ((f = noclobberopen(fname)) < 0)
+				goto ecreate;
+			break;
+		}
+	case NTOOV:
 		fname = redir->nfile.expfname;
 #ifdef O_CREAT
 		if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
@@ -222,32 +242,48 @@
 		break;
 	case NTOFD:
 	case NFROMFD:
+		f = -1;
+		break;
+	case NHERE:
+	case NXHERE:
+		f = openhere(redir);
+		break;
+	default:
+		abort();
+	}
+
+	return f;
+ecreate:
+	error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
+eopen:
+	error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
+}
+
+
+STATIC void
+dupredirect(redir, f, memory)
+	union node *redir;
+	int f;
+	char memory[10];
+	{
+	int fd = redir->nfile.fd;
+
+	memory[fd] = 0;
+	if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
 		if (redir->ndup.dupfd >= 0) {	/* if not ">&-" */
 			if (memory[redir->ndup.dupfd])
 				memory[fd] = 1;
 			else
 				copyfd(redir->ndup.dupfd, fd);
 		}
-		INTON;
 		return;
-	case NHERE:
-	case NXHERE:
-		f = openhere(redir);
-		break;
-	default:
-		abort();
 	}
 
 	if (f != fd) {
 		copyfd(f, fd);
 		close(f);
 	}
-	INTON;
 	return;
-ecreate:
-	error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
-eopen:
-	error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
 }
 
 
@@ -304,6 +340,7 @@
 	struct redirtab *rp = redirlist;
 	int i;
 
+	INTOFF;
 	for (i = 0 ; i < 10 ; i++) {
 		if (rp->renamed[i] != EMPTY) {
                         if (i == 0)
@@ -313,9 +350,11 @@
 				copyfd(rp->renamed[i], i);
 				close(rp->renamed[i]);
 			}
+			if (rp->renamed[i] == fd2) {
+				fd2 = i;
+			}
 		}
 	}
-	INTOFF;
 	redirlist = rp->next;
 	ckfree(rp);
 	INTON;
@@ -359,6 +398,9 @@
 		for (i = 0 ; i < 10 ; i++) {
 			if (rp->renamed[i] >= 0) {
 				close(rp->renamed[i]);
+				if (rp->renamed[i] == fd2) {
+					fd2 = -1;
+				}
 			}
 			rp->renamed[i] = EMPTY;
 		}
@@ -389,3 +431,62 @@
 	}
 	return newfd;
 }
+
+/*
+ * Open a file in noclobber mode.
+ * The code was copied from bash.
+ */
+int
+noclobberopen(fname)
+	const char *fname;
+{
+	int r, fd;
+	struct stat finfo, finfo2;
+
+	/*
+	 * If the file exists and is a regular file, return an error
+	 * immediately.
+	 */
+	r = stat(fname, &finfo);
+	if (r == 0 && S_ISREG(finfo.st_mode)) {
+		errno = EEXIST;
+		return -1;
+	}
+
+	/*
+	 * If the file was not present (r != 0), make sure we open it
+	 * exclusively so that if it is created before we open it, our open
+	 * will fail.  Make sure that we do not truncate an existing file.
+	 * Note that we don't turn on O_EXCL unless the stat failed -- if the
+	 * file was not a regular file, we leave O_EXCL off.
+	 */
+	if (r != 0)
+		return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
+	fd = open(fname, O_WRONLY|O_CREAT, 0666);
+
+	/* If the open failed, return the file descriptor right away. */
+	if (fd < 0)
+		return fd;
+
+	/*
+	 * OK, the open succeeded, but the file may have been changed from a
+	 * non-regular file to a regular file between the stat and the open.
+	 * We are assuming that the O_EXCL open handles the case where FILENAME
+	 * did not exist and is symlinked to an existing file between the stat
+	 * and open.
+	 */
+
+	/*
+	 * If we can open it and fstat the file descriptor, and neither check
+	 * revealed that it was a regular file, and the file has not been
+	 * replaced, return the file descriptor.
+	 */
+	 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
+	     finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
+	 	return fd;
+
+	/* The file has been replaced.  badness. */
+	close(fd);
+	errno = EEXIST;
+	return -1;
+}
diff -Nur ash-0.4.0.orig/redir.h ash-0.4.0.fixed/redir.h
--- ash-0.4.0.orig/redir.h	2000-05-23 05:03:19.000000000 -0500
+++ ash-0.4.0.fixed/redir.h	2003-10-01 21:08:15.000000000 -0500
@@ -42,6 +42,8 @@
 #define REDIR_PUSH 01		/* save previous values of file descriptors */
 #define REDIR_BACKQ 02		/* save the command output in memory */
 
+extern int fd2;
+
 union node;
 void redirect __P((union node *, int));
 void popredir __P((void));
diff -Nur ash-0.4.0.orig/setmode.c ash-0.4.0.fixed/setmode.c
--- ash-0.4.0.orig/setmode.c	1969-12-31 18:00:00.000000000 -0600
+++ ash-0.4.0.fixed/setmode.c	2003-10-01 21:08:15.000000000 -0500
@@ -0,0 +1,486 @@
+/*	$NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Dave Borman at Cray Research, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)setmode.c	8.2 (Berkeley) 3/25/94";
+#else
+__RCSID("$NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef SETMODE_DEBUG
+#include <stdio.h>
+#endif
+
+#ifdef __weak_alias
+__weak_alias(getmode,_getmode)
+__weak_alias(setmode,_setmode)
+#endif
+
+#ifdef __GLIBC__
+#define S_ISTXT __S_ISVTX
+#endif
+
+#define	SET_LEN	6		/* initial # of bitcmd struct to malloc */
+#define	SET_LEN_INCR 4		/* # of bitcmd structs to add as needed */
+
+typedef struct bitcmd {
+	char	cmd;
+	char	cmd2;
+	mode_t	bits;
+} BITCMD;
+
+#define	CMD2_CLR	0x01
+#define	CMD2_SET	0x02
+#define	CMD2_GBITS	0x04
+#define	CMD2_OBITS	0x08
+#define	CMD2_UBITS	0x10
+
+static BITCMD	*addcmd __P((BITCMD *, int, int, int, u_int));
+static void	 compress_mode __P((BITCMD *));
+#ifdef SETMODE_DEBUG
+static void	 dumpmode __P((BITCMD *));
+#endif
+
+/*
+ * Given the old mode and an array of bitcmd structures, apply the operations
+ * described in the bitcmd structures to the old mode, and return the new mode.
+ * Note that there is no '=' command; a strict assignment is just a '-' (clear
+ * bits) followed by a '+' (set bits).
+ */
+mode_t
+getmode(bbox, omode)
+	const void *bbox;
+	mode_t omode;
+{
+	const BITCMD *set;
+	mode_t clrval, newmode, value;
+
+	_DIAGASSERT(bbox != NULL);
+
+	set = (const BITCMD *)bbox;
+	newmode = omode;
+	for (value = 0;; set++)
+		switch(set->cmd) {
+		/*
+		 * When copying the user, group or other bits around, we "know"
+		 * where the bits are in the mode so that we can do shifts to
+		 * copy them around.  If we don't use shifts, it gets real
+		 * grundgy with lots of single bit checks and bit sets.
+		 */
+		case 'u':
+			value = (newmode & S_IRWXU) >> 6;
+			goto common;
+
+		case 'g':
+			value = (newmode & S_IRWXG) >> 3;
+			goto common;
+
+		case 'o':
+			value = newmode & S_IRWXO;
+common:			if (set->cmd2 & CMD2_CLR) {
+				clrval =
+				    (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
+				if (set->cmd2 & CMD2_UBITS)
+					newmode &= ~((clrval<<6) & set->bits);
+				if (set->cmd2 & CMD2_GBITS)
+					newmode &= ~((clrval<<3) & set->bits);
+				if (set->cmd2 & CMD2_OBITS)
+					newmode &= ~(clrval & set->bits);
+			}
+			if (set->cmd2 & CMD2_SET) {
+				if (set->cmd2 & CMD2_UBITS)
+					newmode |= (value<<6) & set->bits;
+				if (set->cmd2 & CMD2_GBITS)
+					newmode |= (value<<3) & set->bits;
+				if (set->cmd2 & CMD2_OBITS)
+					newmode |= value & set->bits;
+			}
+			break;
+
+		case '+':
+			newmode |= set->bits;
+			break;
+
+		case '-':
+			newmode &= ~set->bits;
+			break;
+
+		case 'X':
+			if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
+				newmode |= set->bits;
+			break;
+
+		case '\0':
+		default:
+#ifdef SETMODE_DEBUG
+			(void)printf("getmode:%04o -> %04o\n", omode, newmode);
+#endif
+			return (newmode);
+		}
+}
+
+#define	ADDCMD(a, b, c, d) do {						\
+	if (set >= endset) {						\
+		BITCMD *newset;						\
+		setlen += SET_LEN_INCR;					\
+		newset = realloc(saveset, sizeof(BITCMD) * setlen);	\
+		if (newset == NULL) {					\
+			free(saveset);					\
+			return (NULL);					\
+		}							\
+		set = newset + (set - saveset);				\
+		saveset = newset;					\
+		endset = newset + (setlen - 2);				\
+	}								\
+	set = addcmd(set, (a), (b), (c), (d));				\
+} while (/*CONSTCOND*/0)
+
+#define	STANDARD_BITS	(S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
+
+void *
+setmode(p)
+	const char *p;
+{
+	int perm, who;
+	char op, *ep;
+	BITCMD *set, *saveset, *endset;
+	sigset_t sigset, sigoset;
+	mode_t mask;
+	int equalopdone = 0;	/* pacify gcc */
+	int permXbits, setlen;
+
+	if (!*p)
+		return (NULL);
+
+	/*
+	 * Get a copy of the mask for the permissions that are mask relative.
+	 * Flip the bits, we want what's not set.  Since it's possible that
+	 * the caller is opening files inside a signal handler, protect them
+	 * as best we can.
+	 */
+	sigfillset(&sigset);
+	(void)sigprocmask(SIG_BLOCK, &sigset, &sigoset);
+	(void)umask(mask = umask(0));
+	mask = ~mask;
+	(void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
+
+	setlen = SET_LEN + 2;
+	
+	if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
+		return (NULL);
+	saveset = set;
+	endset = set + (setlen - 2);
+
+	/*
+	 * If an absolute number, get it and return; disallow non-octal digits
+	 * or illegal bits.
+	 */
+	if (isdigit((unsigned char)*p)) {
+		perm = (mode_t)strtol(p, &ep, 8);
+		if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
+			free(saveset);
+			return (NULL);
+		}
+		ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
+		set->cmd = 0;
+		return (saveset);
+	}
+
+	/*
+	 * Build list of structures to set/clear/copy bits as described by
+	 * each clause of the symbolic mode.
+	 */
+	for (;;) {
+		/* First, find out which bits might be modified. */
+		for (who = 0;; ++p) {
+			switch (*p) {
+			case 'a':
+				who |= STANDARD_BITS;
+				break;
+			case 'u':
+				who |= S_ISUID|S_IRWXU;
+				break;
+			case 'g':
+				who |= S_ISGID|S_IRWXG;
+				break;
+			case 'o':
+				who |= S_IRWXO;
+				break;
+			default:
+				goto getop;
+			}
+		}
+
+getop:		if ((op = *p++) != '+' && op != '-' && op != '=') {
+			free(saveset);
+			return (NULL);
+		}
+		if (op == '=')
+			equalopdone = 0;
+
+		who &= ~S_ISTXT;
+		for (perm = 0, permXbits = 0;; ++p) {
+			switch (*p) {
+			case 'r':
+				perm |= S_IRUSR|S_IRGRP|S_IROTH;
+				break;
+			case 's':
+				/*
+				 * If specific bits where requested and 
+				 * only "other" bits ignore set-id. 
+				 */
+				if (who == 0 || (who & ~S_IRWXO))
+					perm |= S_ISUID|S_ISGID;
+				break;
+			case 't':
+				/*
+				 * If specific bits where requested and 
+				 * only "other" bits ignore set-id. 
+				 */
+				if (who == 0 || (who & ~S_IRWXO)) {
+					who |= S_ISTXT;
+					perm |= S_ISTXT;
+				}
+				break;
+			case 'w':
+				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
+				break;
+			case 'X':
+				permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
+				break;
+			case 'x':
+				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+				break;
+			case 'u':
+			case 'g':
+			case 'o':
+				/*
+				 * When ever we hit 'u', 'g', or 'o', we have
+				 * to flush out any partial mode that we have,
+				 * and then do the copying of the mode bits.
+				 */
+				if (perm) {
+					ADDCMD(op, who, perm, mask);
+					perm = 0;
+				}
+				if (op == '=')
+					equalopdone = 1;
+				if (op == '+' && permXbits) {
+					ADDCMD('X', who, permXbits, mask);
+					permXbits = 0;
+				}
+				ADDCMD(*p, who, op, mask);
+				break;
+
+			default:
+				/*
+				 * Add any permissions that we haven't already
+				 * done.
+				 */
+				if (perm || (op == '=' && !equalopdone)) {
+					if (op == '=')
+						equalopdone = 1;
+					ADDCMD(op, who, perm, mask);
+					perm = 0;
+				}
+				if (permXbits) {
+					ADDCMD('X', who, permXbits, mask);
+					permXbits = 0;
+				}
+				goto apply;
+			}
+		}
+
+apply:		if (!*p)
+			break;
+		if (*p != ',')
+			goto getop;
+		++p;
+	}
+	set->cmd = 0;
+#ifdef SETMODE_DEBUG
+	(void)printf("Before compress_mode()\n");
+	dumpmode(saveset);
+#endif
+	compress_mode(saveset);
+#ifdef SETMODE_DEBUG
+	(void)printf("After compress_mode()\n");
+	dumpmode(saveset);
+#endif
+	return (saveset);
+}
+
+static BITCMD *
+addcmd(set, op, who, oparg, mask)
+	BITCMD *set;
+	int oparg, who;
+	int op;
+	u_int mask;
+{
+
+	_DIAGASSERT(set != NULL);
+
+	switch (op) {
+	case '=':
+		set->cmd = '-';
+		set->bits = who ? who : STANDARD_BITS;
+		set++;
+
+		op = '+';
+		/* FALLTHROUGH */
+	case '+':
+	case '-':
+	case 'X':
+		set->cmd = op;
+		set->bits = (who ? who : mask) & oparg;
+		break;
+
+	case 'u':
+	case 'g':
+	case 'o':
+		set->cmd = op;
+		if (who) {
+			set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
+				    ((who & S_IRGRP) ? CMD2_GBITS : 0) |
+				    ((who & S_IROTH) ? CMD2_OBITS : 0);
+			set->bits = (mode_t)~0;
+		} else {
+			set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
+			set->bits = mask;
+		}
+	
+		if (oparg == '+')
+			set->cmd2 |= CMD2_SET;
+		else if (oparg == '-')
+			set->cmd2 |= CMD2_CLR;
+		else if (oparg == '=')
+			set->cmd2 |= CMD2_SET|CMD2_CLR;
+		break;
+	}
+	return (set + 1);
+}
+
+#ifdef SETMODE_DEBUG
+static void
+dumpmode(set)
+	BITCMD *set;
+{
+
+	_DIAGASSERT(set != NULL);
+
+	for (; set->cmd; ++set)
+		(void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
+		    set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
+		    set->cmd2 & CMD2_CLR ? " CLR" : "",
+		    set->cmd2 & CMD2_SET ? " SET" : "",
+		    set->cmd2 & CMD2_UBITS ? " UBITS" : "",
+		    set->cmd2 & CMD2_GBITS ? " GBITS" : "",
+		    set->cmd2 & CMD2_OBITS ? " OBITS" : "");
+}
+#endif
+
+/*
+ * Given an array of bitcmd structures, compress by compacting consecutive
+ * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
+ * 'g' and 'o' commands continue to be separate.  They could probably be 
+ * compacted, but it's not worth the effort.
+ */
+static void
+compress_mode(set)
+	BITCMD *set;
+{
+	BITCMD *nset;
+	int setbits, clrbits, Xbits, op;
+
+	_DIAGASSERT(set != NULL);
+
+	for (nset = set;;) {
+		/* Copy over any 'u', 'g' and 'o' commands. */
+		while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
+			*set++ = *nset++;
+			if (!op)
+				return;
+		}
+
+		for (setbits = clrbits = Xbits = 0;; nset++) {
+			if ((op = nset->cmd) == '-') {
+				clrbits |= nset->bits;
+				setbits &= ~nset->bits;
+				Xbits &= ~nset->bits;
+			} else if (op == '+') {
+				setbits |= nset->bits;
+				clrbits &= ~nset->bits;
+				Xbits &= ~nset->bits;
+			} else if (op == 'X')
+				Xbits |= nset->bits & ~setbits;
+			else
+				break;
+		}
+		if (clrbits) {
+			set->cmd = '-';
+			set->cmd2 = 0;
+			set->bits = clrbits;
+			set++;
+		}
+		if (setbits) {
+			set->cmd = '+';
+			set->cmd2 = 0;
+			set->bits = setbits;
+			set++;
+		}
+		if (Xbits) {
+			set->cmd = 'X';
+			set->cmd2 = 0;
+			set->bits = Xbits;
+			set++;
+		}
+	}
+}
diff -Nur ash-0.4.0.orig/sh.1 ash-0.4.0.fixed/sh.1
--- ash-0.4.0.orig/sh.1	2001-01-12 10:50:40.000000000 -0600
+++ ash-0.4.0.fixed/sh.1	2003-10-01 21:08:15.000000000 -0500
@@ -649,7 +649,7 @@
 they were one program:
 .Pp
 .Bd -literal -offset indent
-{ echo -n \*q hello \*q ; echo \*q world" } > greeting
+{ echo \*q hello \\c\*q ; echo \*q world" } > greeting
 .Ed
 .Pp
 .Ss Functions
@@ -1306,14 +1306,16 @@
 will continue to print the old name for the directory.
 .It Xo read Op Fl p Ar prompt
 .Op Fl r
-.Op Ar variable...
+.Ar variable...
 .Xc
 The prompt is printed if the
 .Fl p
 option is specified and the standard input is a terminal.  Then a line is
 read from the standard input.  The trailing newline is deleted from the
 line and the line is split as described in the section on word splitting
-above, and the pieces are assigned to the variables in order. If there are
+above, and the pieces are assigned to the variables in order.
+At least one variable must be specified.
+If there are
 more pieces than variables, the remaining pieces (along with the
 characters in
 .Ev IFS
@@ -1394,6 +1396,9 @@
 by one. If there are zero positional parameters,
 .Ic shift
 does nothing.
+.It times
+Print the accumulated user and system times for the shell and for processes
+run from the shell.  The return status is 0.
 .It Xo trap
 .Op Ar action
 .Ar signal...
diff -Nur ash-0.4.0.orig/show.c ash-0.4.0.fixed/show.c
--- ash-0.4.0.orig/show.c	1999-10-09 06:02:09.000000000 -0500
+++ ash-0.4.0.fixed/show.c	2003-10-01 21:08:15.000000000 -0500
@@ -155,6 +155,7 @@
 			case NTO:	s = ">";  dftfd = 1; break;
 			case NAPPEND:	s = ">>"; dftfd = 1; break;
 			case NTOFD:	s = ">&"; dftfd = 1; break;
+			case NTOOV:	s = ">|"; dftfd = 1; break;
 			case NFROM:	s = "<";  dftfd = 0; break;
 			case NFROMFD:	s = "<&"; dftfd = 0; break;
 			case NFROMTO:	s = "<>"; dftfd = 0; break;
diff -Nur ash-0.4.0.orig/trap.c ash-0.4.0.fixed/trap.c
--- ash-0.4.0.orig/trap.c	2000-05-23 05:03:19.000000000 -0500
+++ ash-0.4.0.fixed/trap.c	2003-10-01 21:08:15.000000000 -0500
@@ -62,7 +62,11 @@
 #include "error.h"
 #include "trap.h"
 #include "mystring.h"
+#include "mail.h"
 
+#ifdef HETIO
+#include "hetio.h"
+#endif
 
 /*
  * Sigmode records the current value of the signal handlers for the various
@@ -84,7 +88,7 @@
 char gotsig[NSIG];		/* indicates specified signal received */
 int pendingsigs;			/* indicates some signal received */
 
-static int getsigaction __P((int, sig_t *));
+extern char *signal_names[];
 
 /*
  * The trap builtin.
@@ -107,16 +111,20 @@
 		return 0;
 	}
 	ap = argv + 1;
-	if (is_number(*ap))
+	if (argc == 2)
 		action = NULL;
 	else
 		action = *ap++;
 	while (*ap) {
-		if ((signo = number(*ap)) < 0 || signo > NSIG)
+		if ((signo = decode_signal(*ap)) < 0)
 			error("%s: bad trap", *ap);
 		INTOFF;
-		if (action)
-			action = savestr(action);
+		if (action) {
+			if (action[0] == '-' && action[1] == '\0')
+				action = NULL;
+			else
+				action = savestr(action);
+		}
 		if (trap[signo])
 			ckfree(trap[signo]);
 		trap[signo] = action;
@@ -157,13 +165,13 @@
  * out what it should be set to.
  */
 
-long
+void
 setsignal(signo)
 	int signo;
 {
 	int action;
-	sig_t sigact = SIG_DFL;
 	char *t;
+	struct sigaction act;
 
 	if ((t = trap[signo]) == NULL)
 		action = S_DFL;
@@ -206,15 +214,15 @@
 		/*
 		 * current setting unknown
 		 */
-		if (!getsigaction(signo, &sigact)) {
+		if (sigaction(signo, 0, &act) == -1) {
 			/*
 			 * Pretend it worked; maybe we should give a warning
 			 * here, but other shells don't. We don't alter
 			 * sigmode, so that we retry every time.
 			 */
-			return 0;
+			return;
 		}
-		if (sigact == SIG_IGN) {
+		if (act.sa_handler == SIG_IGN) {
 			if (mflag && (signo == SIGTSTP ||
 			     signo == SIGTTIN || signo == SIGTTOU)) {
 				*t = S_IGN;	/* don't hard ignore these */
@@ -225,31 +233,21 @@
 		}
 	}
 	if (*t == S_HARD_IGN || *t == action)
-		return 0;
+		return;
 	switch (action) {
-		case S_DFL:	sigact = SIG_DFL;	break;
-		case S_CATCH:  	sigact = onsig;		break;
-		case S_IGN:	sigact = SIG_IGN;	break;
+	case S_CATCH:
+		act.sa_handler = onsig;
+		break;
+	case S_IGN:
+		act.sa_handler = SIG_IGN;
+		break;
+	default:
+		act.sa_handler = SIG_DFL;
 	}
 	*t = action;
-	siginterrupt(signo, 1);
-	return (long)signal(signo, sigact);
-}
-
-/*
- * Return the current setting for sig w/o changing it.
- */
-static int
-getsigaction(signo, sigact)
-	int signo;
-	sig_t *sigact;
-{
-	struct sigaction sa;
-
-	if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
-		return 0;
-	*sigact = (sig_t) sa.sa_handler;
-	return 1;
+	act.sa_flags = 0;
+	sigemptyset(&act.sa_mask);
+	sigaction(signo, &act, 0);
 }
 
 /*
@@ -347,6 +345,7 @@
 	setsignal(SIGINT);
 	setsignal(SIGQUIT);
 	setsignal(SIGTERM);
+	chkmail(1);
 	is_interactive = on;
 }
 
@@ -364,6 +363,9 @@
 	char *p;
 
 	TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
+#ifdef HETIO
+	hetio_reset_term();
+#endif
 	if (setjmp(loc1.loc)) {
 		goto l1;
 	}
@@ -383,3 +385,17 @@
 l2:   _exit(status);
 	/* NOTREACHED */
 }
+
+int decode_signal(const char *string)
+{
+	int signo;
+
+	if (is_number(string)) return atoi(string);
+
+	for (signo=0; signo < NSIG; signo++)
+		if (strcasecmp(string, signal_names[signo]) == 0 ||
+			strcasecmp(string, &(signal_names[signo])[3]) == 0)
+			return signo;
+
+	return -1;
+}
diff -Nur ash-0.4.0.orig/trap.h ash-0.4.0.fixed/trap.h
--- ash-0.4.0.orig/trap.h	2000-05-23 05:03:19.000000000 -0500
+++ ash-0.4.0.fixed/trap.h	2003-10-01 21:08:15.000000000 -0500
@@ -42,9 +42,10 @@
 
 int trapcmd __P((int, char **));
 void clear_traps __P((void));
-long setsignal __P((int));
+void setsignal __P((int));
 void ignoresig __P((int));
 void onsig __P((int));
 void dotrap __P((void));
 void setinteractive __P((int));
 void exitshell __P((int)) __attribute__((noreturn));
+int decode_signal __P((const char *));
diff -Nur ash-0.4.0.orig/var.c ash-0.4.0.fixed/var.c
--- ash-0.4.0.orig/var.c	2001-01-12 10:50:40.000000000 -0600
+++ ash-0.4.0.fixed/var.c	2003-10-01 21:08:15.000000000 -0500
@@ -114,7 +114,7 @@
 	  NULL },
 	{ &vmpath,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAILPATH=",
 	  NULL },
-	{ &vpath,	VSTRFIXED|VTEXTFIXED,		"PATH=" _PATH_DEFPATH,
+ 	{ &vpath,	VSTRFIXED|VTEXTFIXED,		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
 	  changepath },
 	/*
 	 * vps1 depends on uid
@@ -138,13 +138,16 @@
 
 /*
  * Initialize the varable symbol tables and import the environment
+ * Setting PWD added by herbert
  */
 
 #ifdef mkinit
+INCLUDE "cd.h"
 INCLUDE "var.h"
 INIT {
 	char **envp;
 	extern char **environ;
+	extern char *curdir;
 
 	initvar();
 	for (envp = environ ; *envp ; envp++) {
@@ -152,6 +155,9 @@
 			setvareq(*envp, VEXPORT|VTEXTFIXED);
 		}
 	}
+
+	getpwd();
+	setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
 }
 #endif
 
@@ -166,6 +172,7 @@
 	const struct varinit *ip;
 	struct var *vp;
 	struct var **vpp;
+	char ppid[30];
 
 	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
 		if ((vp->flags & VEXPORT) == 0) {
@@ -187,6 +194,9 @@
 		vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
 		vps1.flags = VSTRFIXED|VTEXTFIXED;
 	}
+	
+	snprintf(ppid, 29, "%ld", (long)getppid());
+	setvar("PPID", ppid, VREADONLY|VNOFUNC);
 }
 
 /*
@@ -283,6 +293,7 @@
 	struct var *vp, **vpp;
 
 	vpp = hashvar(s);
+	flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
 	for (vp = *vpp ; vp ; vp = vp->next) {
 		if (varequal(s, vp->text)) {
 			if (vp->flags & VREADONLY) {
@@ -305,7 +316,8 @@
 			 * We could roll this to a function, to handle it as
 			 * a regular variable function callback, but why bother?
 			 */
-			if (vp == &vmpath || (vp == &vmail && ! mpathset()))
+			if (iflag &&
+			    (vp == &vmpath || (vp == &vmail && ! mpathset())))
 				chkmail(1);
 			INTON;
 			return;
