Submitted By: DJ Lucas Date: 2005-11-29 Initial Package Version: 0.4.0 Origin: Slackware Source and Tushar Teredesai Description: This is a collection of patches from Debian via Slackware Adjusted patch for use with gcc-4.0.x 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 +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 + +#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 +#ifndef lint +__RCSID("$NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $"); +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __STDC__ +#include +#else +#include +#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 ::= +*/ + +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 + * This file contains code for the times builtin. + * $Id: ash-0.4.0-cumulative_fixes-1.patch,v 1.1 2004/06/04 10:32:01 jim Exp $ + */ + +#include +#include +#include + +#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 #include +#include #include /* @@ -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) ¬_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 #include #include +#include /* * 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 #include #include +#if defined(__GLIBC__) && !defined(GLOB_BROKEN) +#include +#include +#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 + * Etc: Dave Cinege + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 + * Etc: Dave Cinege + * + * 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); + +static 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 +#include +#include +#include + +#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<OSTOP) */ + 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 \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 #include #include +#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) +#undef CEOF /* get rid of the redefine warning */ +#include +#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 #endif +#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) +#include +#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 #include #include /* PIPE_BUF */ #include @@ -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 +#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 +#include + +#include +#include +#include +#include +#include +#include + +#ifdef SETMODE_DEBUG +#include +#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;