cvs commit: patches/ash ash-0.4.0-cumulative-fixes.patch

tushar at linuxfromscratch.org tushar at linuxfromscratch.org
Thu Oct 2 00:19:01 PDT 2003


tushar      03/10/02 01:19:01

  Added:       ash      ash-0.4.0-cumulative-fixes.patch
  Log:
  Added ash-0.4.0-cumulative-fixes.patch
  
  Revision  Changes    Path
  1.1                  patches/ash/ash-0.4.0-cumulative-fixes.patch
  
  Index: ash-0.4.0-cumulative-fixes.patch
  ===================================================================
  Submitted By: Tushar Teredesai <tushar at 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.
  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 at debian.org>
  + * This file contains code for the times builtin.
  + * $Id: ash-0.4.0-cumulative-fixes.patch,v 1.1 2003/10/02 07:19:01 tushar 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 at cs.utexas.edu> 
  + *	Etc:		Dave Cinege <dcinege at 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 at cs.utexas.edu> 
  + *	Etc:		Dave Cinege <dcinege at 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;
  
  
  



More information about the patches mailing list