ports

recipes for building multiple softwares
git clone git://z3bra.org/ports
Log | Files | Refs

commit 92783c726d4434af275aa29ad71e2a0014503adf
Author: z3bra <willyatmailoodotorg>
Date:   Sun Aug 16 16:43:33 2015

ash: new port

Diffstat:
 ash/makeme                       |  23 +-
 ash/patches/ash-builtin.patch    | 843 ++++++++++++++++++++++++++++++++++++++++-
 ash/patches/ash-debian.disabled  | 702 +++++++++++++++++++++++++++++++++-
 ash/patches/ash-echo.patch       |  91 ++++-
 ash/patches/ash-freebsd.disabled |  60 +++-
 ash/patches/ash-getcwd.patch     |  13 +-
 ash/patches/ash-getopt.patch     | 198 +++++++++-
 ash/patches/ash-glob.patch       | 445 +++++++++++++++++++++-
 ash/patches/ash-hetio.patch      | 559 +++++++++++++++++++++++++++-
 ash/patches/ash-jobs.patch       | 108 +++++-
 ash/patches/ash-kill.patch       | 675 ++++++++++++++++++++++++++++++++-
 ash/patches/ash-makefile.patch   | 115 +++++-
 ash/patches/ash-manpage.patch    |  42 ++-
 ash/patches/ash-memout.patch     | 333 ++++++++++++++++-
 ash/patches/ash-misc.patch       | 122 ++++++-
 ash/patches/ash-ppid.patch       |  21 +-
 ash/patches/ash-redir.patch      | 463 ++++++++++++++++++++++-
 ash/patches/ash-setmode.patch    | 510 ++++++++++++++++++++++++-
 ash/patches/ash-sighup.patch     |  18 +-
 ash/patches/ash-syntax.patch     | 270 +++++++++++++-
 ash/patches/ash-test.patch       | 588 ++++++++++++++++++++++++++++-
 ash/patches/ash-times.patch      |  42 ++-
 22 files changed, 6241 insertions(+), 0 deletions(-)

diff --git a/ash/makeme b/ash/makeme @@ -0,0 +1,23 @@ +name=ash +version=0.4.0 +source=ftp://ftp.slackware.com/pub/slackware/slackware-current/source/ap/ash/$name-$version.tar.gz + +package() +{ + curl -# $source | tar xz + cd $name-$version + + cat ../patches/*.patch | patch -Np1 || true + + sed -i -e 's#= {#{#' arith.y # prevent "syntax error, unexpected =" + sed -i -e '/yyerrok;/d' arith.y # "error: 'yyerrstatus' undeclared" + sed -i -e 's#extern int hetio_inter#static int hetio_inter#' hetio.h + + make CC=pcc LDFLAGS="$LDFLAGS" + + mkdir -p $WORKDIR/$name/bin + cp sh $WORKDIR/$name/bin/sh + chmod 755 $WORKDIR/$name/bin/sh + mkdir -p $WORKDIR/$name/usr/share/man/man1 + cp sh.1 $WORKDIR/$name/usr/share/man/man1/sh.1 +} diff --git a/ash/patches/ash-builtin.patch b/ash/patches/ash-builtin.patch @@ -0,0 +1,843 @@ +diff -urN netbsd-sh/builtins.def ash-0.3.7.orig/builtins.def +--- netbsd-sh/builtins.def Mon Apr 10 13:02:58 2000 ++++ ash-0.3.7.orig/builtins.def Mon Apr 23 22:16:46 2001 +@@ -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 +diff -urN netbsd-sh/eval.c ash-0.3.7.orig/eval.c +--- netbsd-sh/eval.c Tue May 23 12:03:18 2000 ++++ ash-0.3.7.orig/eval.c Mon Apr 23 22:16:46 2001 +@@ -45,7 +45,9 @@ + #endif + #endif /* not lint */ + ++#include <sys/types.h> + #include <signal.h> ++#include <malloc.h> + #include <unistd.h> + + /* +@@ -101,6 +103,8 @@ + STATIC void evalpipe __P((union node *)); + STATIC void evalcommand __P((union node *, int, struct backcmd *)); + STATIC void prehash __P((union node *)); ++STATIC int is_assignment_builtin __P((const char *)); ++STATIC const char *get_standard_path __P((void)); + + + /* +@@ -257,6 +261,11 @@ + evalcase(n, flags); + break; + case NDEFUN: ++ if (is_special_builtin(n->narg.text)) { ++ outfmt(out2, "%s is a special built-in\n", n->narg.text); ++ exitstatus = 1; ++ break; ++ } + defun(n->narg.text, n->narg.next); + exitstatus = 0; + break; +@@ -497,9 +507,14 @@ + close(0); + copyfd(prevfd, 0); + close(prevfd); ++ if (pip[0] == 0) { ++ pip[0] = -1; ++ } + } + if (pip[1] >= 0) { +- close(pip[0]); ++ if (pip[0] >= 0) { ++ close(pip[0]); ++ } + if (pip[1] != 1) { + close(1); + copyfd(pip[1], 1); +@@ -607,6 +622,7 @@ + int argc; + char **envp; + int varflag; ++ int pseudovarflag; + struct strlist *sp; + int mode; + int pip[2]; +@@ -619,12 +635,17 @@ + struct localvar *volatile savelocalvars; + volatile int e; + char *lastarg; ++ int not_special; ++ const char *path; ++ const char *standard_path; + #if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &argv; + (void) &argc; + (void) &lastarg; + (void) &flags; ++ (void) &not_special; ++ (void) &standard_path; + #endif + + /* First expand the arguments. */ +@@ -632,21 +653,31 @@ + setstackmark(&smark); + arglist.lastp = &arglist.list; + varlist.lastp = &varlist.list; ++ arglist.list = 0; + varflag = 1; ++ pseudovarflag = 0; + oexitstatus = exitstatus; + exitstatus = 0; ++ not_special = 0; ++ path = pathval(); ++ standard_path = NULL; + for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { + char *p = argp->narg.text; +- if (varflag && is_name(*p)) { ++ if ((varflag || pseudovarflag) && is_name(*p)) { + do { + p++; + } while (is_in_name(*p)); + if (*p == '=') { +- expandarg(argp, &varlist, EXP_VARTILDE); ++ if (varflag) ++ expandarg(argp, &varlist, EXP_VARTILDE); ++ else ++ expandarg(argp, &arglist, EXP_VARTILDE); + continue; + } + } + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); ++ if (varflag && arglist.list && is_assignment_builtin(arglist.list->text)) ++ pseudovarflag = 1; + varflag = 0; + } + *arglist.lastp = NULL; +@@ -688,37 +719,75 @@ + cmdentry.u.index = BLTINCMD; + } else { + static const char PATH[] = "PATH="; +- const char *path = pathval(); ++ const char *oldpath = NULL; ++ int findflag = DO_ERR; + + /* + * Modify the command lookup path, if a PATH= assignment + * is present + */ + for (sp = varlist.list ; sp ; sp = sp->next) +- if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) ++ if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) { + path = sp->text + sizeof(PATH) - 1; +- +- find_command(argv[0], &cmdentry, DO_ERR, path); +- if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ +- exitstatus = 127; +- flushout(&errout); +- return; +- } +- /* implement the bltin builtin here */ +- if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { +- for (;;) { ++ findflag |= DO_BRUTE; ++ } ++ for(;;) { ++ find_command(argv[0], &cmdentry, findflag, path); ++ if (oldpath) { ++ path = oldpath; ++ oldpath = NULL; ++ } ++ if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ ++ exitstatus = 127; ++ flushout(&errout); ++ goto out; ++ } ++ /* implement the bltin builtin here */ ++ if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { ++ not_special = 1; ++ for(;;) { ++ argv++; ++ if (--argc == 0) ++ break; ++ if ((cmdentry.u.index = find_builtin(*argv)) < 0) { ++ outfmt(&errout, "%s: not found\n", *argv); ++ exitstatus = 127; ++ flushout(&errout); ++ goto out; ++ } ++ if (cmdentry.u.index != BLTINCMD) ++ break; ++ } ++ } ++ if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == COMMANDCMD) { ++ not_special = 1; + argv++; +- if (--argc == 0) +- break; +- if ((cmdentry.u.index = find_builtin(*argv)) < 0) { +- outfmt(&errout, "%s: not found\n", *argv); +- exitstatus = 127; +- flushout(&errout); +- return; ++ if (--argc == 0) { ++ exitstatus = 0; ++ goto out; + } +- if (cmdentry.u.index != BLTINCMD) +- break; ++ if (*argv[0] == '-') { ++ if (!equal(argv[0], "-p")) { ++ argv--; ++ argc++; ++ break; ++ } ++ argv++; ++ if (--argc == 0) { ++ exitstatus = 0; ++ goto out; ++ } ++ if (!standard_path) { ++ standard_path = get_standard_path(); ++ } ++ oldpath = path; ++ path = standard_path; ++ findflag |= DO_BRUTE; ++ } ++ findflag |= DO_NOFUN; ++ continue; + } ++ break; + } + } + +@@ -756,13 +825,12 @@ + #ifdef DEBUG + trputs("Shell function: "); trargs(argv); + #endif ++ exitstatus = oexitstatus; + redirect(cmd->ncmd.redirect, REDIR_PUSH); + saveparam = shellparam; + shellparam.malloc = 0; +- shellparam.reset = 1; + shellparam.nparam = argc - 1; + shellparam.p = argv + 1; +- shellparam.optnext = NULL; + INTOFF; + savelocalvars = localvars; + localvars = NULL; +@@ -772,6 +840,8 @@ + freeparam((volatile struct shparam *) + &saveparam); + } else { ++ saveparam.optind = shellparam.optind; ++ saveparam.optoff = shellparam.optoff; + freeparam(&shellparam); + shellparam = saveparam; + } +@@ -790,6 +860,8 @@ + INTOFF; + poplocalvars(); + localvars = savelocalvars; ++ saveparam.optind = shellparam.optind; ++ saveparam.optoff = shellparam.optoff; + freeparam(&shellparam); + shellparam = saveparam; + handler = savehandler; +@@ -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; +@@ -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; + +@@ -1025,4 +1111,49 @@ + shellexec(argv + 1, environment(), pathval(), 0); + } + 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 -urN netbsd-sh/eval.h ash-0.3.7.orig/eval.h +--- netbsd-sh/eval.h Fri Jan 28 13:03:00 2000 ++++ ash-0.3.7.orig/eval.h Mon Apr 23 22:16:46 2001 +@@ -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 -urN netbsd-sh/exec.c ash-0.3.7.orig/exec.c +--- netbsd-sh/exec.c Fri Jan 12 17:50:35 2001 ++++ ash-0.3.7.orig/exec.c Mon Apr 23 22:16:46 2001 +@@ -51,6 +51,7 @@ + #include <fcntl.h> + #include <errno.h> + #include <stdlib.h> ++#include <sysexits.h> + + /* + * When commands are first encountered, they are entered in a hash table. +@@ -108,6 +109,9 @@ + STATIC void clearcmdentry __P((int)); + STATIC struct tblentry *cmdlookup __P((char *, int)); + STATIC void delete_cmd_entry __P((void)); ++STATIC int describe_command __P((char *, int)); ++STATIC int path_change __P((const char *, int *)); ++STATIC int is_regular_builtin __P((const char *)); + + + +@@ -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; + } + + +@@ -944,4 +992,190 @@ + } + } + 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 -urN netbsd-sh/exec.h ash-0.3.7.orig/exec.h +--- netbsd-sh/exec.h Tue May 23 12:03:19 2000 ++++ ash-0.3.7.orig/exec.h Mon Apr 23 22:16:46 2001 +@@ -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 --git a/ash/patches/ash-debian.disabled b/ash/patches/ash-debian.disabled @@ -0,0 +1,702 @@ +diff -urN netbsd-sh/debian/README.debian ash-0.3.7.orig/debian/README.debian +--- netbsd-sh/debian/README.debian Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/README.debian Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,14 @@ ++ash for DEBIAN ++---------------------- ++ ++This is a very simple port of ash taken from NetBSD-current on 1997/06/18. The ++file setmode.c was taken from src/libc/gen and is needed since the Linux libc ++does provide getmode(3) or setmode(3). History editing is disabled to avoid ++code bloat. This also means that building the package is possible without the ++BSD libedit. ++ ++This port is preriodically revised to keep up to date with NetBSD's current ++release. ++ ++Herbert Xu <herbert@debian.org> ++$Id: README.debian,v 1.6 2000/08/04 11:33:48 herbert Exp $ +diff -urN netbsd-sh/debian/ash-medium.README.Debian ash-0.3.7.orig/debian/ash-medium.README.Debian +--- netbsd-sh/debian/ash-medium.README.Debian Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/ash-medium.README.Debian Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,14 @@ ++ash for DEBIAN ++---------------------- ++ ++This is a very simple port of ash taken from NetBSD-current on 1997/06/18. The ++file setmode.c was taken from src/libc/gen and is needed since the Linux libc ++does provide getmode(3) or setmode(3). History editing is disabled to avoid ++code bloat. This also means that building the package is possible without the ++BSD libedit. ++ ++This port is preriodically revised to keep up to date with NetBSD's current ++release. ++ ++Herbert Xu <herbert@debian.org> ++$Id: ash-medium.README.Debian,v 1.1 2000/08/04 11:49:01 herbert Exp $ +diff -urN netbsd-sh/debian/ash-medium.dirs ash-0.3.7.orig/debian/ash-medium.dirs +--- netbsd-sh/debian/ash-medium.dirs Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/ash-medium.dirs Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,2 @@ ++usr/bin ++usr/share/man/man1 +diff -urN netbsd-sh/debian/ash-udeb.dirs ash-0.3.7.orig/debian/ash-udeb.dirs +--- netbsd-sh/debian/ash-udeb.dirs Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/ash-udeb.dirs Mon Apr 23 22:16:46 2001 +@@ -0,0 +1 @@ ++bin +diff -urN netbsd-sh/debian/bsdyacc ash-0.3.7.orig/debian/bsdyacc +--- netbsd-sh/debian/bsdyacc Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/bsdyacc Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,20 @@ ++#!/bin/sh -e ++ ++if echo "$@" | grep -q -- -o; then ++ OUTPUT=$(echo "$@" | ++ sed 's/.*-o[[:blank:]]\+\([^[:blank:]]\+\)\.c.*/\1/') ++ OPTIONS=$(echo "$@" | ++ sed 's/\(.*\)-o[[:blank:]]\+[^[:blank:]]\+\(.*\)/\1\2/') ++ NEW=1 ++else ++ OUTPUT=$(echo "$@" | ++ sed -e 's/.*[[:blank:]]\+\([^[:blank:]]\+\)\.y.*/\1/') ++ OPTIONS="$@" ++ NEW=0 ++fi ++ ++byacc $OPTIONS ++if [ $NEW = 1 ]; then ++ mv y.tab.c $OUTPUT.c ++fi ++mv y.tab.h $OUTPUT.h +diff -urN netbsd-sh/debian/changelog ash-0.3.7.orig/debian/changelog +--- netbsd-sh/debian/changelog Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/changelog Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,429 @@ ++ash (0.3.7-14) unstable; urgency=low ++ ++ * Removed predependency from udeb (closes: #81995). ++ * Added /bin/sh symlink to udeb (closes: #81967). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 13 Jan 2001 15:23:21 +1100 ++ ++ash (0.3.7-13) unstable; urgency=low ++ ++ * Renamed the udeb to ash-udeb. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 20 Dec 2000 19:32:34 +1100 ++ ++ash (0.3.7-12) unstable; urgency=low ++ ++ * Added support for udebs (Randolph Chung, closes: #79237). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 16 Dec 2000 13:53:28 +1100 ++ ++ash (0.3.7-11) unstable; urgency=low ++ ++ * Preserve the previous exit status upon entering a function ++ (closes: #78374). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 3 Dec 2000 13:34:27 +1100 ++ ++ash (0.3.7-10) unstable; urgency=low ++ ++ * Merged changes for GNU from Igor Khavkine. ++ * Minimise the number of sigactions. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 3 Nov 2000 20:31:52 +1100 ++ ++ash (0.3.7-9) unstable; urgency=low ++ ++ * Predepend on the libraries. ++ * Always save fd 2 when it is redirected (closes: #75302). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 22 Oct 2000 08:40:40 +1100 ++ ++ash (0.3.7-8) unstable; urgency=high ++ ++ * More redirection fixes (closes: #73613). ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 5 Oct 2000 18:22:17 +1100 ++ ++ash (0.3.7-7) unstable; urgency=high ++ ++ * Added missing break in redirection code (closes: #72956). ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 3 Oct 2000 07:58:04 +1100 ++ ++ash (0.3.7-6) unstable; urgency=low ++ ++ * command -[vV] no longer displays an error message on stdout. ++ * Redirecting to /proc/self/fd/* now works (closes: #72852). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 1 Oct 2000 12:56:39 +1100 ++ ++ash (0.3.7-5) unstable; urgency=low ++ ++ * Implemented set -a. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 30 Sep 2000 16:00:33 +1100 ++ ++ash (0.3.7-4) unstable; urgency=low ++ ++ * Added build-time dependency on debhelper (closes: #69920). ++ * Extended maximum length of arithmetic expansions to match 32-bit integers. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 20 Sep 2000 14:28:16 +1100 ++ ++ash (0.3.7-3) unstable; urgency=low ++ ++ * Switch to the old globbing code since glob(3) is hopelessly broken ++ (closes: #69455). ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 21 Aug 2000 20:37:15 +1000 ++ ++ash (0.3.7-2) unstable; urgency=low ++ ++ * Call glob(3) with GLOB_NOMAGIC (ouch). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 6 Aug 2000 17:47:08 +1000 ++ ++ash (0.3.7-1) unstable; urgency=low ++ ++ * NetBSD-current version as of 20000729. ++ * Use fnmatch(3) and glob(3). ++ * Fixed the use of backslashes in the pattern in parameter substitutions, ++ hopefully for the last time. ++ * Applied HETIO patch and built ash.medium (closes: #50788). Will do ash.big ++ when readline is fixed so that it doesn't leak anymore. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 4 Aug 2000 21:36:44 +1000 ++ ++ash (0.3.6-5) unstable; urgency=low ++ ++ * Fixed manpage entry for read with patch from Kevin Ryde (closes: #62500). ++ * Fixed a file descriptor leak for pipelines. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 19 Apr 2000 18:56:20 +1000 ++ ++ash (0.3.6-4) unstable; urgency=low ++ ++ * Fixed the case of an empty command with redirections. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 7 Apr 2000 12:07:18 +1000 ++ ++ash (0.3.6-3) unstable; urgency=low ++ ++ * ! is now recognised correctly. ++ * Ash is now more strict on the syntax, e.g., a lone ! is no longer accepted ++ as an alternative to ! true. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 7 Apr 2000 10:46:06 +1000 ++ ++ash (0.3.6-2) unstable; urgency=low ++ ++ * Fixed a problem with fmtstr() which broke getopts. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 2 Apr 2000 10:49:26 +1000 ++ ++ash (0.3.6-1) unstable; urgency=low ++ ++ * NetBSD-current version as of 20000326. ++ * Added a Build-Depends on groff (closes: #61041). ++ * Implemented noclobber (closes: #59028). ++ * Rewrote output.c to use stream IO. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 1 Apr 2000 19:24:31 +1000 ++ ++ash (0.3.5-10) frozen unstable; urgency=low ++ ++ * Don't stat mail boxes in non-interactive mode (closes: #59213). ++ * Added an fflush(stdout) to the times builtin (closes: #59027). ++ * Documented the times builtin. ++ * Added source depends. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 18 Mar 2000 18:58:44 +1100 ++ ++ash (0.3.5-9) unstable; urgency=low ++ ++ * Double quotes inside paramater substitutions inside double quotes are now ++ ignored as in bash (the originial behaviour was POSIX compliant too but ++ IMHO this one makes a little bit more sense). ++ This one broke mwm (but it was actually mwm's fault). ++ * Corrected backslash/CTLESC treatment for patterns in parameter ++ substitutions. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 6 Nov 1999 18:13:19 +1100 ++ ++ash (0.3.5-8) unstable; urgency=low ++ ++ * Replaced use of echo -n in manual page with escape codes. ++ * Made FHS compliant (closes: #47978). ++ * Restored echo's option processing ability. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 22 Oct 1999 10:20:58 +1000 ++ ++ash (0.3.5-7) unstable; urgency=low ++ ++ * echo no longer supports options. ++ * Don't quote patterns inside parameter substitutions enclosed by double ++ quotes (closes: #47842). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 20 Oct 1999 20:28:14 +1000 ++ ++ash (0.3.5-6) unstable; urgency=low ++ ++ * Use getcwd() instead of /bin/pwd -- Zack Weinberg (closes: #46981). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 10 Oct 1999 16:31:49 +1000 ++ ++ash (0.3.5-5) unstable; urgency=low ++ ++ * Only test for -e on simple commands (fixes #44559). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 8 Sep 1999 22:18:27 +1000 ++ ++ash (0.3.5-4) unstable; urgency=low ++ ++ * Don't wait for stopped children if job control is disabled (fixes #42814). ++ * Allow an option '(' in a case statement (fixes #42364). ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 12 Aug 1999 23:30:30 +1000 ++ ++ash (0.3.5-3) unstable; urgency=low ++ ++ * OK, the fix to the esoteric problem in 0.3.5-1 actually breaks VSASSIGN ++ and VSQUESTION, they should work properly now (fixes #41327). ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 15 Jul 1999 22:47:13 +1000 ++ ++ash (0.3.5-2) unstable; urgency=low ++ ++ * PATH search and execution is now correct. ++ * hash no longer shows builtins. ++ * Added kill builtin. ++ * New description from James R. van Zandt reformatted by Josip Rodin. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 12 Jul 1999 18:51:42 +1000 ++ ++ash (0.3.5-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Adapted to new pmake (fixes #38737). ++ * Fixed behvaiour of backslashes preceding a closing brace for a parameter ++ substituion inside double quotes (even bash messes this one up :). ++ * Fixed command (fixes #34639). ++ * Fixed a pipe bug where stdin may be wrongly closed (fixes #35452). ++ * Revamped getopts (fixes #39694). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 4 Jul 1999 12:19:01 +1000 ++ ++ash (0.3.4-7) unstable; urgency=low ++ ++ * Fixed a glibc 2.1 compatitibility problem. ++ * Fixed a PWD inconsistency that stuffed up the kernel compilation. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 17 May 1999 23:14:57 +1000 ++ ++ash (0.3.4-6) unstable; urgency=low ++ ++ * Fixed incorrect -e test due to the last bug fix (fixes #26509). ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 8 Sep 1998 10:02:46 +1000 ++ ++ash (0.3.4-5) unstable; urgency=low ++ ++ * Use test_eaccess from bash instead of access(2) (fixes #26110). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 26 Aug 1998 21:22:49 +1000 ++ ++ash (0.3.4-4) unstable; urgency=low ++ ++ * Only upload to unstable. ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 5 May 1998 18:01:02 +1000 ++ ++ash (0.3.4-3) frozen unstable; urgency=low ++ ++ * Applied sparc patch (fixes #21562). ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 1 May 1998 19:48:13 +1000 ++ ++ash (0.3.4-2) frozen unstable; urgency=low ++ ++ * Fixed the incorrect trap fixes (fixes #20363). ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 16 Apr 1998 21:07:10 +1000 ++ ++ash (0.3.4-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Reverted word splitting change in 0.3.2-1 since the fix was broken and ++ major work (the quote removal is done too quickly at the moment) is needed ++ to fix it properly. ++ * Fixed more trap noncompliance. ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 19 Mar 1998 22:59:12 +1100 ++ ++ash (0.3.2-5) unstable; urgency=low ++ ++ * Fixed a bug when doing pattern matching in parameter expansions. ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 10 Mar 1998 21:25:40 +1100 ++ ++ash (0.3.2-4) unstable; urgency=low ++ ++ * Allow ] to be quoted in bracket expressions (fixes #17533). ++ * Move dh_fixperms to second last spot (fixes #18267). ++ * Don't do field splitting in evalfor. ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 17 Feb 1998 13:32:09 +1100 ++ ++ash (0.3.2-3) unstable; urgency=low ++ ++ * Fixed stupid core dump. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 11 Feb 1998 21:33:55 +1100 ++ ++ash (0.3.2-2) unstable; urgency=low ++ ++ * Hack for special builtins (fixes #18055). ++ * Hack for command. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 11 Feb 1998 21:19:46 +1100 ++ ++ash (0.3.2-1) unstable; urgency=low ++ ++ * NetBSD-current version as of 19980209. ++ * Fixed a word splitting problem after parameter expansion thanks to Alexey ++ Marinichev. ++ * Converted to debhelper (fixes #14612, #15005). ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 9 Feb 1998 16:53:48 +1100 ++ ++ash (0.3.1-20) unstable; urgency=low ++ ++ * Fixed -e problem with eval. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 7 Dec 1997 20:19:00 +1100 ++ ++ash (0.3.1-19) unstable; urgency=low ++ ++ * Fixed -e problem with command substitution. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 7 Dec 1997 19:44:49 +1100 ++ ++ash (0.3.1-18) unstable; urgency=low ++ ++ * Do not link with ncurses (#15485). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 30 Nov 1997 12:00:11 +1100 ++ ++ash (0.3.1-17) unstable; urgency=low ++ ++ * Set PATH like bash (#15238). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 26 Nov 1997 16:17:27 +1100 ++ ++ash (0.3.1-16) unstable; urgency=low ++ ++ * Fixed incorrect assignment builtin code. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 24 Nov 1997 16:19:10 +1100 ++ ++ash (0.3.1-15) unstable; urgency=low ++ ++ * hash now returns error codes (needed by the Linux kernel). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 23 Nov 1997 21:37:08 +1100 ++ ++ash (0.3.1-14) unstable; urgency=low ++ ++ * Disabled word-splitting for assignment builtins. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 23 Nov 1997 12:45:15 +1100 ++ ++ash (0.3.1-13) unstable; urgency=low ++ ++ * ! is now recognised even after &&/||. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 21 Nov 1997 22:09:05 +1100 ++ ++ash (0.3.1-12) unstable; urgency=low ++ ++ * More fixes to the handling of SIGINT when forking. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 14 Nov 1997 15:14:32 +1100 ++ ++ash (0.3.1-11) unstable; urgency=low ++ ++ * Ignore SIGINT when forking non-interactively. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 3 Nov 1997 12:00:02 +1100 ++ ++ash (0.3.1-10) unstable; urgency=low ++ ++ * echo now handles options correctly. ++ * echo nolonger returns 0 if erorrs occured while writing to stdout. ++ * New code from GNU echo merged. ++ * Error messages from test now work. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 8 Oct 1997 21:47:13 +1000 ++ ++ash (0.3.1-9) unstable; urgency=low ++ ++ * ! is recognised at pipeline level like bash. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 15 Sep 1997 23:13:45 +1000 ++ ++ash (0.3.1-8) unstable; urgency=medium ++ ++ * Old patch regarding SIGCHLD in again. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 31 Aug 1997 11:20:27 +1000 ++ ++ash (0.3.1-7) unstable; urgency=low ++ ++ * /bin/sh -e is behaving even better now (for loops within conditionals). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 23 Aug 1997 22:08:19 +1000 ++ ++ash (0.3.1-6) unstable; urgency=low ++ ++ * /bin/sh -e is behaving better now. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 23 Aug 1997 13:16:26 +1000 ++ ++ash (0.3.1-5) unstable; urgency=low ++ ++ * hash -v /dir/command doesn't coredump anymore. ++ * type /dir/command now works correctly. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 1 Aug 1997 20:48:19 +1000 ++ ++ash (0.3.1-4) unstable; urgency=low ++ ++ * trap now understands symbolic signal names. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 26 Jul 1997 14:04:46 +1000 ++ ++ash (0.3.1-3) unstable; urgency=low ++ ++ * Added the builtin test command. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 20 Jul 1997 15:00:14 +1000 ++ ++ash (0.3.1-2) unstable; urgency=medium ++ ++ * Fixed a coredump involving $*. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 19 Jul 1997 12:03:02 +1000 ++ ++ash (0.3.1-1) unstable; urgency=medium ++ ++ * NetBSD-current version as of 19970715. ++ * Fixed a "use after free" bug (#11294). ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 18 Jul 1997 13:48:09 +1000 ++ ++ash (0.3-1) unstable; urgency=low ++ ++ * Initial Release. ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 19 Jun 1997 19:29:16 +1000 ++ +diff -urN netbsd-sh/debian/control ash-0.3.7.orig/debian/control +--- netbsd-sh/debian/control Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/control Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,69 @@ ++Source: ash ++Section: shells ++Priority: optional ++Maintainer: Herbert Xu <herbert@debian.org> ++Build-Depends: byacc, debhelper, flex, pmake, groff ++Standards-Version: 3.2.1 ++ ++Package: ash ++Architecture: any ++Pre-Depends: ${shlibs:Depends} ++Description: NetBSD /bin/sh ++ "ash" is a POSIX compliant shell that is much smaller than "bash". ++ We take advantage of that by making it the shell on the installation ++ root floppy, where space is at a premium. ++ . ++ It can be usefully installed as /bin/sh (because it executes scripts ++ somewhat faster than "bash"), or as the default shell either of root ++ or of a second user with a userid of 0 (because it depends on fewer ++ libraries, and is therefore less likely to be affected by an upgrade ++ problem or a disk failure). It is also useful for checking that a ++ script uses only POSIX syntax. ++ . ++ "bash" is a better shell for most users, since it has some nice ++ features absent from "ash", and is a required part of the system. ++ ++Package: ash-medium ++Architecture: any ++Pre-Depends: ${shlibs:Depends} ++Priority: extra ++Description: NetBSD /bin/sh with HETIO ++ This is a slightly bigger version of the standard ash package with a ++ hack that provides primitive history support. It may be useful on ++ boot floppies where space is at a premium, yet users still need the ++ ability to access previous commands in the same session. If you're ++ not a boot floppies maintainer, you should probably go for ash, ++ ash.big (not yet available), or bash. ++ . ++ "ash" is a POSIX compliant shell that is much smaller than "bash". ++ We take advantage of that by making it the shell on the installation ++ root floppy, where space is at a premium. ++ . ++ It can be usefully installed as /bin/sh (because it executes scripts ++ somewhat faster than "bash"), or as the default shell either of root ++ or of a second user with a userid of 0 (because it depends on fewer ++ libraries, and is therefore less likely to be affected by an upgrade ++ problem or a disk failure). It is also useful for checking that a ++ script uses only POSIX syntax. ++ . ++ "bash" is a better shell for most users, since it has some nice ++ features absent from "ash", and is a required part of the system. ++ ++Package: ash-udeb ++Architecture: any ++Section: debian-installer ++Description: NetBSD /bin/sh for boot floppies ++ "ash" is a POSIX compliant shell that is much smaller than "bash". ++ We take advantage of that by making it the shell on the installation ++ root floppy, where space is at a premium. ++ . ++ It can be usefully installed as /bin/sh (because it executes scripts ++ somewhat faster than "bash"), or as the default shell either of root ++ or of a second user with a userid of 0 (because it depends on fewer ++ libraries, and is therefore less likely to be affected by an upgrade ++ problem or a disk failure). It is also useful for checking that a ++ script uses only POSIX syntax. ++ . ++ "bash" is a better shell for most users, since it has some nice ++ features absent from "ash", and is a required part of the system. ++ +diff -urN netbsd-sh/debian/copyright ash-0.3.7.orig/debian/copyright +--- netbsd-sh/debian/copyright Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/copyright Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,18 @@ ++This package was debianized by Mark W. Eichin eichin@kitten.gen.ma.us on ++Mon, 24 Feb 1997 16:00:16 -0500. ++ ++This package was re-ported from NetBSD and debianized by ++Herbert Xu herbert@debian.org on Thu, 19 Jun 1997 19:29:16 +1000. ++ ++It was downloaded from ftp.netbsd.org. ++ ++Copyright: ++ ++Copyright (c) 1991, 1993 ++ The Regents of the University of California. All rights reserved. ++ ++This code is derived from software contributed to Berkeley by Kenneth Almquist. ++ ++Please refer to /usr/share/common-licenses/BSD for details. ++ ++$Id: copyright,v 1.3 2000/08/04 11:48:49 herbert Exp $ +diff -urN netbsd-sh/debian/dirs ash-0.3.7.orig/debian/dirs +--- netbsd-sh/debian/dirs Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/dirs Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,2 @@ ++bin ++usr/share/man/man1 +diff -urN netbsd-sh/debian/rules ash-0.3.7.orig/debian/rules +--- netbsd-sh/debian/rules Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/debian/rules Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,92 @@ ++#!/usr/bin/make -f ++# $Id: rules,v 1.22 2001/01/13 04:23:49 herbert Exp $ ++ ++# Uncomment this to turn on verbose mode. ++#export DH_VERBOSE=1 ++CDEF = -g -O2 -Wall -DBSD=1 -DSMALL -D_GNU_SOURCE \ ++ -DGLOB_BROKEN \ ++ -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)= ++CDEFSM = -Os -fomit-frame-pointer -Wall -DBSD=1 -DSMALL -D_GNU_SOURCE \ ++ -DGLOB_BROKEN \ ++ -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)= ++ ++sh.hetio: ++ chmod u+x debian/bsdyacc ++ rm -f *.o ++ pmake CFLAGS='$(CDEF)' HETIO= YACC=`pwd`/debian/bsdyacc ++ mv sh sh.hetio ++ ++sh: ++ chmod u+x debian/bsdyacc ++ rm -f *.o ++ pmake CFLAGS='$(CDEF)' YACC=`pwd`/debian/bsdyacc ++ ++sh.udeb: ++ chmod u+x debian/bsdyacc ++ rm -f *.o ++ pmake CFLAGS='$(CDEFSM)' YACC=`pwd`/debian/bsdyacc ++ mv sh sh.udeb ++ ++build: build-stamp ++build-stamp: sh.hetio sh.udeb sh ++ dh_testdir ++ ++ touch build-stamp ++ ++clean: ++ dh_testdir ++ dh_testroot ++ rm -f build-stamp ++ ++ pmake clean HETIO= ++ rm -f sh.cat1 mksignames signames.h sh.hetio sh.udeb ++ ++ dh_clean ++ ++# Build architecture-independent files here. ++binary-indep: build ++# We have nothing to do by default. ++ ++# Build architecture-dependent files here. ++binary-arch: build ++# dh_testversion ++ dh_testdir ++ dh_testroot ++ dh_clean -k ++ dh_installdirs ++ ++ install sh debian/tmp/bin/ash ++ install -m 644 sh.1 debian/tmp/usr/share/man/man1/ash.1 ++ install sh.hetio debian/ash-medium/usr/bin/ash.medium ++ install -m 644 sh.1 debian/ash-medium/usr/share/man/man1/ash.medium.1 ++ install sh.udeb debian/ash-udeb/bin/ash ++ ln -s ash debian/ash-udeb/bin/sh ++ ++ dh_installdocs -Nash-udeb ++ dh_installexamples ++ dh_installmenu ++# dh_installinit ++ dh_installcron ++# dh_installmanpages ++# dh_undocumented ++ dh_installchangelogs -Nash-udeb ++ dh_strip ++ dh_compress ++ dh_fixperms ++ dh_suidregister ++ dh_installdeb -Nash-udeb ++ dh_shlibdeps ++ dh_gencontrol ++# dh_makeshlibs ++ dh_md5sums ++ dh_builddeb ++ for i in ../ash-udeb_*.deb; do mv $$i $${i%deb}udeb; done ++ sed '/^[^ ]*\.udeb/d; s/^\(ash-udeb_[^ ]*\.\)deb/\1udeb/' \ ++ debian/files > debian/files.new ++ mv debian/files.new debian/files ++ ++source diff: ++ @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false ++ ++binary: binary-indep binary-arch ++.PHONY: build clean binary-indep binary-arch binary + diff --git a/ash/patches/ash-echo.patch b/ash/patches/ash-echo.patch @@ -0,0 +1,91 @@ +diff -urN netbsd-sh/bltin/echo.c ash-0.3.7.orig/bltin/echo.c +--- netbsd-sh/bltin/echo.c Sun Nov 3 13:06:22 1996 ++++ ash-0.3.7.orig/bltin/echo.c Mon Apr 23 22:16:46 2001 +@@ -44,7 +44,13 @@ + + #define main echocmd + ++#ifdef _GNU_SOURCE ++#include <stdio.h> ++ ++#include "../mystring.h" ++#else + #include "bltin.h" ++#endif + + /* #define eflag 1 */ + +@@ -53,7 +59,6 @@ + register char **ap; + register char *p; + register char c; +- int count; + int nflag = 0; + #ifndef eflag + int eflag = 0; +@@ -62,21 +67,26 @@ + 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 'f': c = '\f'; break; +@@ -85,11 +95,13 @@ + 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 +115,12 @@ + } + if (! nflag) + putchar('\n'); ++#ifdef _GNU_SOURCE ++ fflush(stdout); ++ if (ferror(stdout)) { ++ clearerr(stdout); ++ return 1; ++ } ++#endif + return 0; + } + diff --git a/ash/patches/ash-freebsd.disabled b/ash/patches/ash-freebsd.disabled @@ -0,0 +1,60 @@ +diff -ur ash-0.4.0/bltin/echo.c ash-0.4.0+free/bltin/echo.c +--- ash-0.4.0/bltin/echo.c Tue Apr 24 02:03:56 2001 ++++ ash-0.4.0+free/bltin/echo.c Tue Apr 24 01:43:15 2001 +@@ -89,6 +89,7 @@ + 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; +diff -ur ash-0.4.0/cd.c ash-0.4.0+free/cd.c +--- ash-0.4.0/cd.c Tue Apr 24 02:03:56 2001 ++++ ash-0.4.0+free/cd.c Tue Apr 24 01:43:57 2001 +@@ -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; + } + +diff -ur ash-0.4.0/main.c ash-0.4.0+free/main.c +--- ash-0.4.0/main.c Tue Apr 24 02:03:57 2001 ++++ ash-0.4.0+free/main.c Tue Apr 24 02:03:26 2001 +@@ -115,6 +115,9 @@ + 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); +@@ -188,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); diff --git a/ash/patches/ash-getcwd.patch b/ash/patches/ash-getcwd.patch @@ -0,0 +1,13 @@ +diff -urN netbsd-sh/cd.c ash-0.3.7.orig/cd.c +--- netbsd-sh/cd.c Fri Jul 9 13:02:05 1999 ++++ ash-0.3.7.orig/cd.c Mon Apr 23 22:16:46 2001 +@@ -319,7 +319,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 --git a/ash/patches/ash-getopt.patch b/ash/patches/ash-getopt.patch @@ -0,0 +1,198 @@ +diff -urN netbsd-sh/options.c ash-0.3.7.orig/options.c +--- netbsd-sh/options.c Fri Jul 9 13:02:07 1999 ++++ ash-0.3.7.orig/options.c Mon Apr 23 22:16:46 2001 +@@ -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 -urN netbsd-sh/options.h ash-0.3.7.orig/options.h +--- netbsd-sh/options.h Fri Jul 9 13:02:07 1999 ++++ ash-0.3.7.orig/options.h Mon Apr 23 22:16:46 2001 +@@ -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 --git a/ash/patches/ash-glob.patch b/ash/patches/ash-glob.patch @@ -0,0 +1,445 @@ +diff -urN netbsd-sh/expand.c ash-0.3.7.orig/expand.c +--- netbsd-sh/expand.c Tue Mar 14 13:03:45 2000 ++++ ash-0.3.7.orig/expand.c Mon Apr 23 22:16:46 2001 +@@ -54,6 +54,10 @@ + #include <pwd.h> + #include <stdlib.h> + #include <stdio.h> ++#if defined(__GLIBC__) && !defined(GLOB_BROKEN) ++#include <fnmatch.h> ++#include <glob.h> ++#endif + + /* + * Routines to expand arguments to commands. We have to deal with +@@ -102,17 +106,30 @@ + STATIC int subevalvar __P((char *, char *, int, int, int, int)); + STATIC char *evalvar __P((char *, int)); + STATIC int varisset __P((char *, int)); ++STATIC char *strtodest __P((char *, int, int)); + STATIC void varvalue __P((char *, int, int)); + STATIC void recordregion __P((int, int, int)); + STATIC void removerecordregions __P((int)); + STATIC void ifsbreakup __P((char *, struct arglist *)); + STATIC void ifsfree __P((void)); + STATIC void expandmeta __P((struct strlist *, int)); ++#if defined(__GLIBC__) && !defined(GLOB_BROKEN) ++STATIC const char *preglob __P((const char *)); ++STATIC void addglob __P((const glob_t *)); ++#else + STATIC void expmeta __P((char *, char *)); ++#endif + STATIC void addfname __P((char *)); ++#if defined(__GLIBC__) && !defined(GLOB_BROKEN) ++STATIC int patmatch __P((char *, char *, int)); ++STATIC int patmatch2 __P((char *, char *, int)); ++STATIC char * _rmescapes __P((char *, int)); ++#else + STATIC struct strlist *expsort __P((struct strlist *)); + STATIC struct strlist *msort __P((struct strlist *, int)); + STATIC int pmatch __P((char *, char *, int)); ++#define patmatch2 patmatch ++#endif + STATIC char *cvtnum __P((int, char *)); + + /* +@@ -371,7 +388,7 @@ + * have to rescan starting from the beginning since CTLESC + * characters have to be processed left to right. + */ +- CHECKSTRSPACE(8, expdest); ++ CHECKSTRSPACE(10, expdest); + USTPUTC('\0', expdest); + start = stackblock(); + p = expdest - 1; +@@ -393,7 +410,7 @@ + if (quotes) + rmescapes(p+2); + result = arith(p+2); +- fmtstr(p, 10, "%d", result); ++ fmtstr(p, 12, "%d", result); + + while (*p++) + ; +@@ -503,7 +520,7 @@ + int amount; + + herefd = -1; +- argstr(p, 0); ++ argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); + STACKSTRNUL(expdest); + herefd = saveherefd; + argbackq = saveargbackq; +@@ -535,7 +552,7 @@ + for (loc = startp; loc < str; loc++) { + c = *loc; + *loc = '\0'; +- if (patmatch(str, startp, varflags & VSQUOTE)) ++ if (patmatch2(str, startp, varflags & VSQUOTE)) + goto recordleft; + *loc = c; + if ((varflags & VSQUOTE) && *loc == CTLESC) +@@ -547,7 +564,7 @@ + for (loc = str - 1; loc >= startp;) { + c = *loc; + *loc = '\0'; +- if (patmatch(str, startp, varflags & VSQUOTE)) ++ if (patmatch2(str, startp, varflags & VSQUOTE)) + goto recordleft; + *loc = c; + loc--; +@@ -564,7 +581,7 @@ + + case VSTRIMRIGHT: + for (loc = str - 1; loc >= startp;) { +- if (patmatch(str, loc, varflags & VSQUOTE)) ++ if (patmatch2(str, loc, varflags & VSQUOTE)) + goto recordright; + loc--; + if ((varflags & VSQUOTE) && loc > startp && +@@ -580,7 +597,7 @@ + + case VSTRIMRIGHTMAX: + for (loc = startp; loc < str - 1; loc++) { +- if (patmatch(str, loc, varflags & VSQUOTE)) ++ if (patmatch2(str, loc, varflags & VSQUOTE)) + goto recordright; + if ((varflags & VSQUOTE) && *loc == CTLESC) + loc++; +@@ -819,6 +836,34 @@ + + + /* ++ * Put a string on the stack. ++ */ ++ ++STATIC char * ++strtodest(p, quoted, allow_split) ++ char *p; ++ int quoted; ++ int allow_split; ++{ ++ char const *syntax; ++ ++ if (allow_split) { ++ syntax = quoted ? DQSYNTAX : BASESYNTAX; ++ while (*p) { ++ if (syntax[(int) *p] == CCTL) ++ STPUTC(CTLESC, expdest); ++ STPUTC(*p++, expdest); ++ } ++ } else ++ while (*p) ++ STPUTC(*p++, expdest); ++ ++ return p; ++} ++ ++ ++ ++/* + * Add the value of a specialized variable to the stack string. + */ + +@@ -834,22 +879,6 @@ + extern int oexitstatus; + char sep; + char **ap; +- char const *syntax; +- +-#define STRTODEST(p) \ +- do {\ +- if (allow_split) { \ +- syntax = quoted? DQSYNTAX : BASESYNTAX; \ +- while (*p) { \ +- if (syntax[(int)*p] == CCTL) \ +- STPUTC(CTLESC, expdest); \ +- STPUTC(*p++, expdest); \ +- } \ +- } else \ +- while (*p) \ +- STPUTC(*p++, expdest); \ +- } while (0) +- + + switch (*name) { + case '$': +@@ -875,7 +904,7 @@ + case '@': + if (allow_split && quoted) { + for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { +- STRTODEST(p); ++ p = strtodest(p, quoted, allow_split); + if (*ap) + STPUTC('\0', expdest); + } +@@ -888,21 +917,20 @@ + else + sep = ' '; + for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { +- STRTODEST(p); ++ p = strtodest(p, quoted, allow_split); + if (*ap && sep) + STPUTC(sep, expdest); + } + break; + case '0': +- p = arg0; +- STRTODEST(p); ++ p = strtodest(arg0, quoted, allow_split); + break; + default: + if (is_digit(*name)) { + num = atoi(name); + if (num > 0 && num <= shellparam.nparam) { +- p = shellparam.p[num - 1]; +- STRTODEST(p); ++ p = strtodest(shellparam.p[num - 1], quoted, ++ allow_split); + } + } + break; +@@ -1054,6 +1082,98 @@ + * should be escapes. The results are stored in the list exparg. + */ + ++#if defined(__GLIBC__) && !defined(GLOB_BROKEN) ++STATIC void ++expandmeta(str, flag) ++ struct strlist *str; ++ int flag; ++{ ++ const char *p; ++ glob_t pglob; ++ /* TODO - EXP_REDIR */ ++ ++ while (str) { ++ if (fflag) ++ goto nometa; ++ p = preglob(str->text); ++ INTOFF; ++ switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) { ++ case 0: ++ if (!(pglob.gl_flags & GLOB_MAGCHAR)) ++ goto nometa2; ++ addglob(&pglob); ++ globfree(&pglob); ++ INTON; ++ break; ++ case GLOB_NOMATCH: ++nometa2: ++ globfree(&pglob); ++ INTON; ++nometa: ++ *exparg.lastp = str; ++ rmescapes(str->text); ++ exparg.lastp = &str->next; ++ break; ++ default: /* GLOB_NOSPACE */ ++ error("Out of space"); ++ } ++ str = str->next; ++ } ++} ++ ++ ++/* ++ * Prepare the string for glob(3). ++ */ ++ ++STATIC const char * ++preglob(str) ++ const char *str; ++{ ++ const char *p; ++ char *q, *r; ++ size_t len; ++ ++ p = str; ++ while (*p != CTLQUOTEMARK && *p != CTLESC) { ++ if (*p++ == '\0') ++ return str; ++ } ++ len = p - str; ++ q = r = stalloc(strlen(str) + 1); ++ if (len > 0) { ++ memcpy(q, str, len); ++ q += len; ++ } ++ do { ++ if (*p == CTLQUOTEMARK) ++ continue; ++ if (*p == CTLESC) { ++ if (*++p != '/') ++ *q++ = '\\'; ++ } ++ *q++ = *p; ++ } while (*++p); ++ *q = '\0'; ++ return r; ++} ++ ++ ++/* ++ * Add the result of glob(3) to the list. ++ */ ++ ++STATIC void ++addglob(pglob) ++ const glob_t *pglob; ++{ ++ char **p = pglob->gl_pathv; ++ ++ do { ++ addfname(*p); ++ } while (*++p); ++} ++#else + char *expdir; + + +@@ -1238,6 +1358,7 @@ + if (! atend) + endname[-1] = '/'; + } ++#endif + + + /* +@@ -1260,6 +1381,7 @@ + } + + ++#if !(defined(__GLIBC__) && !defined(GLOB_BROKEN)) + /* + * Sort the results of file name expansion. It calculates the number of + * strings to sort and then calls msort (short for merge sort) to do the +@@ -1321,6 +1443,7 @@ + } + return list; + } ++#endif + + + +@@ -1328,6 +1451,39 @@ + * Returns true if the pattern matches the string. + */ + ++#if defined(__GLIBC__) && !defined(GLOB_BROKEN) ++STATIC int ++patmatch(pattern, string, squoted) ++ char *pattern; ++ char *string; ++ int squoted; /* string might have quote chars */ ++ { ++ const char *p; ++ char *q; ++ ++ p = preglob(pattern); ++ q = squoted ? _rmescapes(string, 1) : string; ++ ++ return !fnmatch(p, q, 0); ++} ++ ++ ++STATIC int ++patmatch2(pattern, string, squoted) ++ char *pattern; ++ char *string; ++ int squoted; /* string might have quote chars */ ++ { ++ char *p; ++ int res; ++ ++ sstrnleft--; ++ p = grabstackstr(expdest); ++ res = patmatch(pattern, string, squoted); ++ ungrabstackstr(p, expdest); ++ return res; ++} ++#else + int + patmatch(pattern, string, squoted) + char *pattern; +@@ -1462,6 +1618,7 @@ + return 0; + return 1; + } ++#endif + + + +@@ -1469,6 +1626,50 @@ + * Remove any CTLESC characters from a string. + */ + ++#if defined(__GLIBC__) && !defined(GLOB_BROKEN) ++void ++rmescapes(str) ++ char *str; ++{ ++ _rmescapes(str, 0); ++} ++ ++ ++STATIC char * ++_rmescapes(str, flag) ++ char *str; ++ int flag; ++{ ++ char *p, *q, *r; ++ ++ p = str; ++ while (*p != CTLESC && *p != CTLQUOTEMARK) { ++ if (*p++ == '\0') ++ return str; ++ } ++ q = p; ++ r = str; ++ if (flag) { ++ size_t len = p - str; ++ q = r = stalloc(strlen(p) + len + 1); ++ if (len > 0) { ++ memcpy(q, str, len); ++ q += len; ++ } ++ } ++ while (*p) { ++ if (*p == CTLQUOTEMARK) { ++ p++; ++ continue; ++ } ++ if (*p == CTLESC) ++ p++; ++ *q++ = *p++; ++ } ++ *q = '\0'; ++ return r; ++} ++#else + void + rmescapes(str) + char *str; +@@ -1492,6 +1693,7 @@ + } + *q = '\0'; + } ++#endif + + + + +diff -urN netbsd-sh/expand.h ash-0.3.7.orig/expand.h +--- netbsd-sh/expand.h Fri Jul 9 13:02:06 1999 ++++ ash-0.3.7.orig/expand.h Mon Apr 23 22:16:46 2001 +@@ -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 --git a/ash/patches/ash-hetio.patch b/ash/patches/ash-hetio.patch @@ -0,0 +1,559 @@ +diff -urN ash-0.4.0/Makefile ash-0.4.0-/Makefile +--- ash-0.4.0/Makefile Tue Apr 24 00:57:33 2001 ++++ ash-0.4.0-/Makefile Tue Apr 24 00:59:53 2001 +@@ -7,7 +7,7 @@ + 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 setmode.c test.c ++ 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} +@@ -17,12 +17,13 @@ + 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 ++ 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\)= ++ -DGLOB_BROKEN -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)= \ ++ -DHETIO + + all: $(PROG) + +diff -urN ash-0.4.0/hetio.c ash-0.4.0-/hetio.c +--- ash-0.4.0/hetio.c Thu Jan 1 01:00:00 1970 ++++ ash-0.4.0-/hetio.c Tue Apr 24 01:06:59 2001 +@@ -0,0 +1,377 @@ ++/* ++ * Termios command line History and Editting for NetBSD sh (ash) ++ * Copyright (c) 1999 ++ * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu> ++ * Etc: Dave Cinege <dcinege@psychosis.com> ++ * ++ * You may use this code as you wish, so long as the original author(s) ++ * are attributed in any redistributions of the source code. ++ * This code is 'as is' with no warranty. ++ * This code may safely be consumed by a BSD or GPL license. ++ * ++ * v 0.5 19990328 Initial release ++ * ++ * Future plans: Simple file and path name completion. (like BASH) ++ * ++ */ ++ ++/* ++Usage and Known bugs: ++ Terminal key codes are not extensive, and more will probably ++ need to be added. This version was created on Debian GNU/Linux 2.x. ++ Delete, Backspace, Home, End, and the arrow keys were tested ++ to work in an Xterm and console. Ctrl-A also works as Home. ++ Ctrl-E also works as End. The binary size increase is <3K. ++ ++ Editting will not display correctly for lines greater then the ++ terminal width. (more then one line.) However, history will. ++*/ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <stdlib.h> ++#include <string.h> ++#include <termios.h> ++#include <ctype.h> ++#include <sys/ioctl.h> ++ ++#include "input.h" ++#include "output.h" ++ ++#ifdef HETIO ++ ++#include "hetio.h" ++ ++ ++#define MAX_HISTORY 15 /* Maximum length of the linked list for the command line history */ ++ ++#define ESC 27 ++#define DEL 127 ++ ++static struct history *his_front = NULL; /* First element in command line list */ ++static struct history *his_end = NULL; /* Last element in command line list */ ++static struct termios old_term, new_term; /* Current termio and the previous termio before starting ash */ ++ ++static int history_counter = 0; /* Number of commands in history list */ ++static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ ++static int hetio_inter = 0; ++ ++struct history ++{ ++ char *s; ++ struct history *p; ++ struct history *n; ++}; ++ ++ ++void input_delete (int); ++void input_home (int *); ++void input_end (int *, int); ++void input_backspace (int *, int *); ++ ++ ++ ++void hetio_init(void) ++{ ++ hetio_inter = 1; ++} ++ ++ ++void hetio_reset_term(void) ++{ ++ if (reset_term) ++ tcsetattr(1, TCSANOW, &old_term); ++} ++ ++ ++void setIO(struct termios *new, struct termios *old) /* Set terminal IO to canonical mode, and save old term settings. */ ++{ ++ tcgetattr(0, old); ++ memcpy(new, old, sizeof(*new)); ++ new->c_cc[VMIN] = 1; ++ new->c_cc[VTIME] = 0; ++ new->c_lflag &= ~ICANON; /* unbuffered input */ ++ new->c_lflag &= ~ECHO; ++ tcsetattr(0, TCSANOW, new); ++} ++ ++void input_home(int *cursor) /* Command line input routines */ ++{ ++ while (*cursor > 0) { ++ out1c('\b'); ++ --*cursor; ++ } ++ flushout(&output); ++} ++ ++ ++void input_delete(int cursor) ++{ ++ int j = 0; ++ ++ memmove(parsenextc + cursor, parsenextc + cursor + 1, ++ BUFSIZ - cursor - 1); ++ for (j = cursor; j < (BUFSIZ - 1); j++) { ++ if (!*(parsenextc + j)) ++ break; ++ else ++ out1c(*(parsenextc + j)); ++ } ++ ++ out1str(" \b"); ++ ++ while (j-- > cursor) ++ out1c('\b'); ++ flushout(&output); ++} ++ ++ ++void input_end(int *cursor, int len) ++{ ++ while (*cursor < len) { ++ out1str("\033[C"); ++ ++*cursor; ++ } ++ flushout(&output); ++} ++ ++ ++void ++input_backspace(int *cursor, int *len) ++{ ++ int j = 0; ++ ++ if (*cursor > 0) { ++ out1str("\b \b"); ++ --*cursor; ++ memmove(parsenextc + *cursor, parsenextc + *cursor + 1, ++ BUFSIZ - (*cursor + 1)); ++ ++ for (j = *cursor; j < (BUFSIZ - 1); j++) { ++ if (!*(parsenextc + j)) ++ break; ++ else ++ out1c(*(parsenextc + j)); ++ } ++ ++ out1str(" \b"); ++ ++ while (j-- > *cursor) ++ out1c('\b'); ++ ++ --*len; ++ flushout(&output); ++ } ++} ++ ++int hetio_read_input(int fd) ++{ ++ int nr = 0; ++ ++ if (!hetio_inter) { /* Are we an interactive shell? */ ++ return -255; ++ } else { ++ int len = 0; ++ int j = 0; ++ int cursor = 0; ++ int break_out = 0; ++ int ret = 0; ++ char c = 0; ++ struct history *hp = his_end; ++ ++ if (!reset_term) { ++ setIO(&new_term, &old_term); ++ reset_term = 1; ++ } else { ++ tcsetattr(0, TCSANOW, &new_term); ++ } ++ ++ memset(parsenextc, 0, BUFSIZ); ++ ++ while (1) { ++ if ((ret = read(fd, &c, 1)) < 1) ++ return ret; ++ ++ switch (c) { ++ case 1: /* Control-A Beginning of line */ ++ input_home(&cursor); ++ break; ++ case 5: /* Control-E EOL */ ++ input_end(&cursor, len); ++ break; ++ case 4: /* Control-D */ ++#ifndef CTRL_D_DELETE ++ return 0; ++#else ++ if (cursor != len) { ++ input_delete(cursor); ++ len--; ++ } ++ break; ++#endif ++ case '\b': /* Backspace */ ++ case DEL: ++ input_backspace(&cursor, &len); ++ break; ++ case '\n': /* Enter */ ++ *(parsenextc + len++ + 1) = c; ++ out1c(c); ++ flushout(&output); ++ break_out = 1; ++ break; ++ case ESC: /* escape sequence follows */ ++ if ((ret = read(fd, &c, 1)) < 1) ++ return ret; ++ ++ if (c == '[' || c == 'O' ) { /* 91 */ ++ if ((ret = read(fd, &c, 1)) < 1) ++ return ret; ++ ++ switch (c) { ++ case 'A': ++ if (hp && hp->p) { /* Up */ ++ hp = hp->p; ++ goto hop; ++ } ++ break; ++ case 'B': ++ if (hp && hp->n && hp->n->s) { /* Down */ ++ hp = hp->n; ++ goto hop; ++ } ++ break; ++ ++hop: /* hop */ ++ len = strlen(parsenextc); ++ ++ for (; cursor > 0; cursor--) /* return to begining of line */ ++ out1c('\b'); ++ ++ for (j = 0; j < len; j++) /* erase old command */ ++ out1c(' '); ++ ++ for (j = len; j > 0; j--) /* return to begining of line */ ++ out1c('\b'); ++ ++ strcpy (parsenextc, hp->s); /* write new command */ ++ len = strlen (hp->s); ++ out1str(parsenextc); ++ flushout(&output); ++ cursor = len; ++ break; ++ case 'C': /* Right */ ++ if (cursor < len) { ++ out1str("\033[C"); ++ cursor++; ++ flushout(&output); ++ } ++ break; ++ case 'D': /* Left */ ++ if (cursor > 0) { ++ out1str("\033[D"); ++ cursor--; ++ flushout(&output); ++ } ++ break; ++ case '3': /* Delete */ ++ if (cursor != len) { ++ input_delete(cursor); ++ len--; ++ } ++ break; ++ case 'H': /* Home (xterm) */ ++ case '1': /* Home (Ctrl-A) */ ++ input_home(&cursor); ++ break; ++ case 'F': /* End (xterm_ */ ++ case '4': /* End (Ctrl-E) */ ++ input_end(&cursor, len); ++ break; ++ } ++ if (c == '1' || c == '3' || c == '4') ++ if ((ret = read(fd, &c, 1)) < 1) ++ return ret; /* read 126 (~) */ ++ } ++ ++ c = 0; ++ break; ++ ++ default: /* If it's regular input, do the normal thing */ ++ ++ if (!isprint(c)) /* Skip non-printable characters */ ++ break; ++ ++ if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ ++ break; ++ ++ len++; ++ ++ if (cursor == (len - 1)) { /* Append if at the end of the line */ ++ *(parsenextc + cursor) = c; ++ } else { /* Insert otherwise */ ++ memmove(parsenextc + cursor + 1, parsenextc + cursor, ++ len - cursor - 1); ++ ++ *(parsenextc + cursor) = c; ++ ++ for (j = cursor; j < len; j++) ++ out1c(*(parsenextc + j)); ++ for (; j > cursor; j--) ++ out1str("\033[D"); ++ } ++ ++ cursor++; ++ out1c(c); ++ flushout(&output); ++ break; ++ } ++ ++ if (break_out) /* Enter is the command terminator, no more input. */ ++ break; ++ } ++ ++ nr = len + 1; ++ tcsetattr(0, TCSANOW, &old_term); ++ ++ ++ if (*(parsenextc)) { /* Handle command history log */ ++ struct history *h = his_end; ++ ++ if (!h) { /* No previous history */ ++ h = his_front = malloc(sizeof (struct history)); ++ h->n = malloc(sizeof (struct history)); ++ h->p = NULL; ++ h->s = strdup(parsenextc); ++ ++ h->n->p = h; ++ h->n->n = NULL; ++ h->n->s = NULL; ++ his_end = h->n; ++ history_counter++; ++ } else { /* Add a new history command */ ++ ++ h->n = malloc(sizeof (struct history)); ++ ++ h->n->p = h; ++ h->n->n = NULL; ++ h->n->s = NULL; ++ h->s = strdup(parsenextc); ++ his_end = h->n; ++ ++ if (history_counter >= MAX_HISTORY) { /* After max history, remove the last known command */ ++ struct history *p = his_front->n; ++ ++ p->p = NULL; ++ free(his_front->s); ++ free(his_front); ++ his_front = p; ++ } else { ++ history_counter++; ++ } ++ } ++ } ++ } ++ ++ return nr; ++} ++#endif +diff -urN ash-0.4.0/hetio.h ash-0.4.0-/hetio.h +--- ash-0.4.0/hetio.h Thu Jan 1 01:00:00 1970 ++++ ash-0.4.0-/hetio.h Tue Apr 24 00:13:57 2001 +@@ -0,0 +1,22 @@ ++/* ++ * Termios command line History and Editting for NetBSD sh (ash) ++ * Copyright (c) 1999 ++ * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu> ++ * Etc: Dave Cinege <dcinege@psychosis.com> ++ * ++ * You may use this code as you wish, so long as the original author(s) ++ * are attributed in any redistributions of the source code. ++ * This code is 'as is' with no warranty. ++ * This code may safely be consumed by a BSD or GPL license. ++ * ++ * v 0.5 19990328 Initial release ++ * ++ * Future plans: Simple file and path name completion. (like BASH) ++ * ++ */ ++ ++void hetio_init(void); ++int hetio_read_input(int fd); ++void hetio_reset_term(void); ++ ++extern int hetio_inter; +diff -urN ash-0.4.0/histedit.c ash-0.4.0-/histedit.c +--- ash-0.4.0/histedit.c Fri Jan 12 17:50:35 2001 ++++ ash-0.4.0-/histedit.c Tue Apr 24 00:13:57 2001 +@@ -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 -urN ash-0.4.0/input.c ash-0.4.0-/input.c +--- ash-0.4.0/input.c Tue May 23 12:03:19 2000 ++++ ash-0.4.0-/input.c Tue Apr 24 00:13:57 2001 +@@ -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)); +@@ -197,6 +205,11 @@ + (void) strcpy(buf, rl_cp); + } + } else ++#endif ++ ++#ifdef HETIO ++ nr = hetio_read_input(parsefile->fd); ++ if (nr == -255) + #endif + nr = read(parsefile->fd, buf, BUFSIZ - 1); + +diff -urN ash-0.4.0/main.c ash-0.4.0-/main.c +--- ash-0.4.0/main.c Tue Apr 24 00:57:33 2001 ++++ ash-0.4.0-/main.c Tue Apr 24 00:13:57 2001 +@@ -79,6 +79,10 @@ + #include "exec.h" + #include "cd.h" + ++#ifdef HETIO ++#include "hetio.h" ++#endif ++ + #define PROFILE 0 + + int rootpid; +@@ -242,6 +246,10 @@ + + TRACE(("cmdloop(%d) called\n", top)); + setstackmark(&smark); ++#ifdef HETIO ++ if(iflag && top) ++ hetio_init(); ++#endif + for (;;) { + if (pendingsigs) + dotrap(); +Binary files ash-0.4.0/mksignames and ash-0.4.0-/mksignames differ +diff -urN ash-0.4.0/trap.c ash-0.4.0-/trap.c +--- ash-0.4.0/trap.c Tue Apr 24 00:57:33 2001 ++++ ash-0.4.0-/trap.c Tue Apr 24 00:13:57 2001 +@@ -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 +@@ -341,6 +345,7 @@ + setsignal(SIGINT); + setsignal(SIGQUIT); + setsignal(SIGTERM); ++ chkmail(1); + is_interactive = on; + } + +@@ -358,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; + } diff --git a/ash/patches/ash-jobs.patch b/ash/patches/ash-jobs.patch @@ -0,0 +1,108 @@ +diff -ur netbsd-sh/jobs.c netbsd-sh-/jobs.c +--- netbsd-sh/jobs.c Tue May 23 12:03:19 2000 ++++ netbsd-sh-/jobs.c Mon Apr 23 23:31:47 2001 +@@ -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. + * +@@ -171,6 +174,7 @@ + } + jobctl = on; + } ++#endif + + + #ifdef mkinit +@@ -594,9 +598,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(); +@@ -642,6 +643,9 @@ + } + } + #endif ++ for (i = njobs, p = jobtab ; --i >= 0 ; p++) ++ if (p->used) ++ freejob(p); + if (wasroot && iflag) { + setsignal(SIGINT); + setsignal(SIGQUIT); +@@ -701,13 +705,33 @@ + #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) +@@ -896,10 +920,10 @@ + #ifdef BSD + int flags; + +-#if JOBS +- flags = WUNTRACED; +-#else + flags = 0; ++#if JOBS ++ if (jobctl) ++ flags |= WUNTRACED; + #endif + if (block == 0) + flags |= WNOHANG; +@@ -1139,4 +1163,9 @@ + } + } + cmdnextc = q; ++} ++ ++STATIC void waitonint(int sig) { ++ intreceived = 1; ++ return; + } diff --git a/ash/patches/ash-kill.patch b/ash/patches/ash-kill.patch @@ -0,0 +1,675 @@ +diff -urN netbsd-sh/jobs.c ash-0.3.7.orig/jobs.c +--- netbsd-sh/jobs.c Tue May 23 12:03:19 2000 ++++ ash-0.3.7.orig/jobs.c Mon Apr 23 22:16:46 2001 +@@ -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; + +diff -urN netbsd-sh/jobs.h ash-0.3.7.orig/jobs.h +--- netbsd-sh/jobs.h Tue May 23 12:03:19 2000 ++++ ash-0.3.7.orig/jobs.h Mon Apr 23 22:16:46 2001 +@@ -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 -urN netbsd-sh/builtins.def ash-0.3.7.orig/builtins.def +--- netbsd-sh/builtins.def Mon Apr 10 13:02:58 2000 ++++ ash-0.3.7.orig/builtins.def Mon Apr 23 22:16:46 2001 +@@ -70,6 +71,7 @@ + hashcmd hash + jobidcmd jobid + jobscmd jobs ++killcmd -j kill + #linecmd line + localcmd local + #nlechocmd nlecho +diff -urN netbsd-sh/mksignames.c ash-0.3.7.orig/mksignames.c +--- netbsd-sh/mksignames.c Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/mksignames.c Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,400 @@ ++/* signames.c -- Create and write `signames.c', which contains an array of ++ signal names. */ ++ ++/* Copyright (C) 1992 Free Software Foundation, Inc. ++ ++ This file is part of GNU Bash, the Bourne Again SHell. ++ ++ Bash is free software; you can redistribute it and/or modify it under ++ the terms of the GNU General Public License as published by the Free ++ Software Foundation; either version 2, or (at your option) any later ++ version. ++ ++ Bash is distributed in the hope that it will be useful, but WITHOUT ANY ++ WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ for more details. ++ ++ You should have received a copy of the GNU General Public License along ++ with Bash; see the file COPYING. If not, write to the Free Software ++ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ ++ ++#include <stdio.h> ++#include <sys/types.h> ++#include <signal.h> ++#include <stdlib.h> ++ ++#if !defined (NSIG) ++# define NSIG 64 ++#endif ++ ++char *signal_names[2 * NSIG]; ++ ++char *progname; ++ ++#if defined (SIGRTMAX) || defined (SIGRTMIN) ++# define RTLEN 14 ++# define RTLIM 256 ++#endif ++ ++void ++initialize_signames () ++{ ++ register int i; ++#if defined (SIGRTMAX) || defined (SIGRTMIN) ++ int rtmin, rtmax, rtcnt; ++#endif ++ ++ for (i = 1; i < sizeof(signal_names)/sizeof(signal_names[0]); i++) ++ signal_names[i] = (char *)NULL; ++ ++ /* `signal' 0 is what we do on exit. */ ++ signal_names[0] = "EXIT"; ++ ++ /* Place signal names which can be aliases for more common signal ++ names first. This allows (for example) SIGABRT to overwrite SIGLOST. */ ++ ++ /* POSIX 1003.1b-1993 real time signals, but take care of incomplete ++ implementations. Acoording to the standard, both, SIGRTMIN and ++ SIGRTMAX must be defined, SIGRTMIN must be stricly less than ++ SIGRTMAX, and the difference must be at least 7, that is, there ++ must be at least eight distinct real time signals. */ ++ ++ /* The generated signal names are SIGRTMIN, SIGRTMIN+1, ..., ++ SIGRTMIN+x, SIGRTMAX-x, ..., SIGRTMAX-1, SIGRTMAX. If the number ++ of RT signals is odd, there is an extra SIGRTMIN+(x+1). ++ These names are the ones used by ksh and /usr/xpg4/bin/sh on SunOS5. */ ++ ++#if defined (SIGRTMIN) ++ rtmin = SIGRTMIN; ++ signal_names[rtmin] = "SIGRTMIN"; ++#endif ++ ++#if defined (SIGRTMAX) ++ rtmax = SIGRTMAX; ++ signal_names[rtmax] = "SIGRTMAX"; ++#endif ++ ++#if defined (SIGRTMAX) && defined (SIGRTMIN) ++ if (rtmax > rtmin) ++ { ++ rtcnt = (rtmax - rtmin - 1) / 2; ++ /* croak if there are too many RT signals */ ++ if (rtcnt >= RTLIM/2) ++ { ++ rtcnt = RTLIM/2-1; ++ fprintf(stderr, "%s: error: more than %i real time signals, fix `%s'\n", ++ progname, RTLIM, progname); ++ } ++ ++ for (i = 1; i <= rtcnt; i++) ++ { ++ signal_names[rtmin+i] = (char *)malloc(RTLEN); ++ sprintf (signal_names[rtmin+i], "SIGRTMIN+%d", i); ++ signal_names[rtmax-i] = (char *)malloc(RTLEN); ++ sprintf (signal_names[rtmax-i], "SIGRTMAX-%d", i); ++ } ++ ++ if (rtcnt < RTLIM/2-1 && rtcnt != (rtmax-rtmin)/2) ++ { ++ /* Need an extra RTMIN signal */ ++ signal_names[rtmin+rtcnt+1] = (char *)malloc(RTLEN); ++ sprintf (signal_names[rtmin+rtcnt+1], "SIGRTMIN+%d", rtcnt+1); ++ } ++ } ++#endif /* SIGRTMIN && SIGRTMAX */ ++ ++/* AIX */ ++#if defined (SIGLOST) /* resource lost (eg, record-lock lost) */ ++ signal_names[SIGLOST] = "SIGLOST"; ++#endif ++ ++#if defined (SIGMSG) /* HFT input data pending */ ++ signal_names[SIGMSG] = "SIGMSG"; ++#endif ++ ++#if defined (SIGDANGER) /* system crash imminent */ ++ signal_names[SIGDANGER] = "SIGDANGER"; ++#endif ++ ++#if defined (SIGMIGRATE) /* migrate process to another CPU */ ++ signal_names[SIGMIGRATE] = "SIGMIGRATE"; ++#endif ++ ++#if defined (SIGPRE) /* programming error */ ++ signal_names[SIGPRE] = "SIGPRE"; ++#endif ++ ++#if defined (SIGVIRT) /* AIX virtual time alarm */ ++ signal_names[SIGVIRT] = "SIGVIRT"; ++#endif ++ ++#if defined (SIGALRM1) /* m:n condition variables */ ++ signal_names[SIGALRM1] = "SIGALRM1"; ++#endif ++ ++#if defined (SIGWAITING) /* m:n scheduling */ ++ signal_names[SIGWAITING] = "SIGWAITING"; ++#endif ++ ++#if defined (SIGGRANT) /* HFT monitor mode granted */ ++ signal_names[SIGGRANT] = "SIGGRANT"; ++#endif ++ ++#if defined (SIGKAP) /* keep alive poll from native keyboard */ ++ signal_names[SIGKAP] = "SIGKAP"; ++#endif ++ ++#if defined (SIGRETRACT) /* HFT monitor mode retracted */ ++ signal_names[SIGRETRACT] = "SIGRETRACT"; ++#endif ++ ++#if defined (SIGSOUND) /* HFT sound sequence has completed */ ++ signal_names[SIGSOUND] = "SIGSOUND"; ++#endif ++ ++#if defined (SIGSAK) /* Secure Attention Key */ ++ signal_names[SIGSAK] = "SIGSAK"; ++#endif ++ ++/* SunOS5 */ ++#if defined (SIGLWP) /* special signal used by thread library */ ++ signal_names[SIGLWP] = "SIGLWP"; ++#endif ++ ++#if defined (SIGFREEZE) /* special signal used by CPR */ ++ signal_names[SIGFREEZE] = "SIGFREEZE"; ++#endif ++ ++#if defined (SIGTHAW) /* special signal used by CPR */ ++ signal_names[SIGTHAW] = "SIGTHAW"; ++#endif ++ ++#if defined (SIGCANCEL) /* thread cancellation signal used by libthread */ ++ signal_names[SIGCANCEL] = "SIGCANCEL"; ++#endif ++ ++/* HP-UX */ ++#if defined (SIGDIL) /* DIL signal (?) */ ++ signal_names[SIGDIL] = "SIGDIL"; ++#endif ++ ++/* System V */ ++#if defined (SIGCLD) /* Like SIGCHLD. */ ++ signal_names[SIGCLD] = "SIGCLD"; ++#endif ++ ++#if defined (SIGPWR) /* power state indication */ ++ signal_names[SIGPWR] = "SIGPWR"; ++#endif ++ ++#if defined (SIGPOLL) /* Pollable event (for streams) */ ++ signal_names[SIGPOLL] = "SIGPOLL"; ++#endif ++ ++/* Unknown */ ++#if defined (SIGWINDOW) ++ signal_names[SIGWINDOW] = "SIGWINDOW"; ++#endif ++ ++/* Common */ ++#if defined (SIGHUP) /* hangup */ ++ signal_names[SIGHUP] = "SIGHUP"; ++#endif ++ ++#if defined (SIGINT) /* interrupt */ ++ signal_names[SIGINT] = "SIGINT"; ++#endif ++ ++#if defined (SIGQUIT) /* quit */ ++ signal_names[SIGQUIT] = "SIGQUIT"; ++#endif ++ ++#if defined (SIGILL) /* illegal instruction (not reset when caught) */ ++ signal_names[SIGILL] = "SIGILL"; ++#endif ++ ++#if defined (SIGTRAP) /* trace trap (not reset when caught) */ ++ signal_names[SIGTRAP] = "SIGTRAP"; ++#endif ++ ++#if defined (SIGIOT) /* IOT instruction */ ++ signal_names[SIGIOT] = "SIGIOT"; ++#endif ++ ++#if defined (SIGABRT) /* Cause current process to dump core. */ ++ signal_names[SIGABRT] = "SIGABRT"; ++#endif ++ ++#if defined (SIGEMT) /* EMT instruction */ ++ signal_names[SIGEMT] = "SIGEMT"; ++#endif ++ ++#if defined (SIGFPE) /* floating point exception */ ++ signal_names[SIGFPE] = "SIGFPE"; ++#endif ++ ++#if defined (SIGKILL) /* kill (cannot be caught or ignored) */ ++ signal_names[SIGKILL] = "SIGKILL"; ++#endif ++ ++#if defined (SIGBUS) /* bus error */ ++ signal_names[SIGBUS] = "SIGBUS"; ++#endif ++ ++#if defined (SIGSEGV) /* segmentation violation */ ++ signal_names[SIGSEGV] = "SIGSEGV"; ++#endif ++ ++#if defined (SIGSYS) /* bad argument to system call */ ++ signal_names[SIGSYS] = "SIGSYS"; ++#endif ++ ++#if defined (SIGPIPE) /* write on a pipe with no one to read it */ ++ signal_names[SIGPIPE] = "SIGPIPE"; ++#endif ++ ++#if defined (SIGALRM) /* alarm clock */ ++ signal_names[SIGALRM] = "SIGALRM"; ++#endif ++ ++#if defined (SIGTERM) /* software termination signal from kill */ ++ signal_names[SIGTERM] = "SIGTERM"; ++#endif ++ ++#if defined (SIGURG) /* urgent condition on IO channel */ ++ signal_names[SIGURG] = "SIGURG"; ++#endif ++ ++#if defined (SIGSTOP) /* sendable stop signal not from tty */ ++ signal_names[SIGSTOP] = "SIGSTOP"; ++#endif ++ ++#if defined (SIGTSTP) /* stop signal from tty */ ++ signal_names[SIGTSTP] = "SIGTSTP"; ++#endif ++ ++#if defined (SIGCONT) /* continue a stopped process */ ++ signal_names[SIGCONT] = "SIGCONT"; ++#endif ++ ++#if defined (SIGCHLD) /* to parent on child stop or exit */ ++ signal_names[SIGCHLD] = "SIGCHLD"; ++#endif ++ ++#if defined (SIGTTIN) /* to readers pgrp upon background tty read */ ++ signal_names[SIGTTIN] = "SIGTTIN"; ++#endif ++ ++#if defined (SIGTTOU) /* like TTIN for output if (tp->t_local&LTOSTOP) */ ++ signal_names[SIGTTOU] = "SIGTTOU"; ++#endif ++ ++#if defined (SIGIO) /* input/output possible signal */ ++ signal_names[SIGIO] = "SIGIO"; ++#endif ++ ++#if defined (SIGXCPU) /* exceeded CPU time limit */ ++ signal_names[SIGXCPU] = "SIGXCPU"; ++#endif ++ ++#if defined (SIGXFSZ) /* exceeded file size limit */ ++ signal_names[SIGXFSZ] = "SIGXFSZ"; ++#endif ++ ++#if defined (SIGVTALRM) /* virtual time alarm */ ++ signal_names[SIGVTALRM] = "SIGVTALRM"; ++#endif ++ ++#if defined (SIGPROF) /* profiling time alarm */ ++ signal_names[SIGPROF] = "SIGPROF"; ++#endif ++ ++#if defined (SIGWINCH) /* window changed */ ++ signal_names[SIGWINCH] = "SIGWINCH"; ++#endif ++ ++/* 4.4 BSD */ ++#if defined (SIGINFO) && !defined (_SEQUENT_) /* information request */ ++ signal_names[SIGINFO] = "SIGINFO"; ++#endif ++ ++#if defined (SIGUSR1) /* user defined signal 1 */ ++ signal_names[SIGUSR1] = "SIGUSR1"; ++#endif ++ ++#if defined (SIGUSR2) /* user defined signal 2 */ ++ signal_names[SIGUSR2] = "SIGUSR2"; ++#endif ++ ++#if defined (SIGKILLTHR) /* BeOS: Kill Thread */ ++ signal_names[SIGKILLTHR] = "SIGKILLTHR"; ++#endif ++ ++ for (i = 0; i < NSIG; i++) ++ if (signal_names[i] == (char *)NULL) ++ { ++ signal_names[i] = (char *)malloc (18); ++ sprintf (signal_names[i], "SIGJUNK(%d)", i); ++ } ++ ++ signal_names[NSIG] = "DEBUG"; ++} ++ ++void ++write_signames (stream) ++ FILE *stream; ++{ ++ register int i; ++ ++ fprintf (stream, "/* This file was automatically created by %s.\n", ++ progname); ++ fprintf (stream, " Do not edit. Edit support/mksignames.c instead. */\n\n"); ++ fprintf (stream, "#include <signal.h>\n\n"); ++ fprintf (stream, ++ "/* A translation list so we can be polite to our users. */\n"); ++ fprintf (stream, "char *signal_names[NSIG + 2] = {\n"); ++ ++ for (i = 0; i <= NSIG; i++) ++ fprintf (stream, " \"%s\",\n", signal_names[i]); ++ ++ fprintf (stream, " (char *)0x0,\n"); ++ fprintf (stream, "};\n"); ++} ++ ++int ++main (argc, argv) ++ int argc; ++ char **argv; ++{ ++ char *stream_name; ++ FILE *stream; ++ ++ progname = argv[0]; ++ ++ if (argc == 1) ++ { ++ stream_name = "signames.c"; ++ } ++ else if (argc == 2) ++ { ++ stream_name = argv[1]; ++ } ++ else ++ { ++ fprintf (stderr, "Usage: %s [output-file]\n", progname); ++ exit (1); ++ } ++ ++ stream = fopen (stream_name, "w"); ++ if (!stream) ++ { ++ fprintf (stderr, "%s: %s: cannot open for writing\n", ++ progname, stream_name); ++ exit (2); ++ } ++ ++ initialize_signames (); ++ write_signames (stream); ++ exit (0); ++} +diff -urN netbsd-sh/trap.c ash-0.3.7.orig/trap.c +--- netbsd-sh/trap.c Tue May 23 12:03:19 2000 ++++ ash-0.3.7.orig/trap.c Mon Apr 23 22:16:46 2001 +@@ -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); + } + + /* +@@ -382,4 +384,18 @@ + #endif + 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 -urN netbsd-sh/trap.h ash-0.3.7.orig/trap.h +--- netbsd-sh/trap.h Tue May 23 12:03:19 2000 ++++ ash-0.3.7.orig/trap.h Mon Apr 23 22:16:46 2001 +@@ -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 --git a/ash/patches/ash-makefile.patch b/ash/patches/ash-makefile.patch @@ -0,0 +1,115 @@ +diff -u ash-0.4.0/Makefile ash-0.4.0-/Makefile +--- ash-0.4.0/Makefile Fri Jan 12 17:50:34 2001 ++++ ash-0.4.0-/Makefile Tue Apr 24 00:49:56 2001 +@@ -7,56 +7,68 @@ + 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 ++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 ++ ++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\)= ++ ++all: $(PROG) ++ ++$(PROG): build-tools $(GENSRCS) $(GENHDRS) $(OBJS) ++ $(CC) $(LDFLAGS) -o $(PROG) $(OBJS) $(LDLIBS) -lfl ++ ++lex.yy.c: arith_lex.l ++ flex -8 $< ++ ++CLEANFILES+= mkinit mkinit.o mknodes mknodes.o \ ++ mksyntax mksyntax.o ++ ++CLEANFILES+= ${GENSRCS} ${GENHDRS} ++ ++build-tools: mkinit mknodes mksyntax ++ ++.ORDER: builtins.c builtins.h ++builtins.c builtins.h: mkbuiltins builtins.def ++ sh mkbuiltins shell.h builtins.def `pwd` ++ ++INIT_DEPS = alias.c eval.c exec.c input.c jobs.c options.c parser.c \ ++ redir.c trap.c var.c output.c ++ ++init.c: mkinit $(INIT_DEPS) ++ ./mkinit $(INIT_DEPS) ++ ++mkinit: mkinit.o ++mknodes: mknodes.o ++mksyntax: mksyntax.o + +-LFLAGS= -8 # 8-bit lex scanner for arithmetic +-YFLAGS= -d +- +-CPPFLAGS+=-DSHELL -I. -I${.CURDIR} +- +-.PATH: ${.CURDIR}/bltin ${.CURDIR}/../../usr.bin/printf ${.CURDIR}/../test +- +-CLEANFILES+= mkinit mknodes mksyntax +-CLEANFILES+= ${GENSRCS} y.tab.h +- +-token.h: mktokens +- sh ${.ALLSRC} +- +-builtins.c builtins.h: mkbuiltins shell.h builtins.def +- sh ${.ALLSRC} ${.OBJDIR} +- +-init.c: mkinit ${SHSRCS} +- ./${.ALLSRC} ++signames.c: mksignames ++ ./mksignames + + nodes.c nodes.h: mknodes nodetypes nodes.c.pat +- ./${.ALLSRC} ++ ./mknodes ./nodetypes ./nodes.c.pat + + syntax.c syntax.h: mksyntax +- ./${.ALLSRC} +- +-mkinit: mkinit.c +- ${HOST_LINK.c} -o mkinit ${.IMPSRC} +- +-mknodes: mknodes.c +- ${HOST_LINK.c} -o mknodes ${.IMPSRC} ++ ./mksyntax + +-.if (${MACHINE_ARCH} == "powerpc") || \ +- (${MACHINE_ARCH} == "arm32") || \ +- (${MACHINE_ARCH} == "arm26") +-TARGET_CHARFLAG= -DTARGET_CHAR="u_int8_t" +-.else +-TARGET_CHARFLAG= -DTARGET_CHAR="int8_t" +-.endif ++arith.c arith.h: arith.y ++ yacc -d arith.y ++ mv y.tab.h arith.h ++ mv y.tab.c arith.c + +-mksyntax: mksyntax.c +- ${HOST_LINK.c} ${TARGET_CHARFLAG} -o mksyntax ${.IMPSRC} +- +-.include <bsd.prog.mk> ++token.h: mktokens ++ sh ./mktokens + +-${OBJS}: builtins.h nodes.h syntax.h token.h ++clean: ++ rm -f $(PROG) $(OBJS) $(CLEANFILES) core diff --git a/ash/patches/ash-manpage.patch b/ash/patches/ash-manpage.patch @@ -0,0 +1,42 @@ +diff -urN netbsd-sh/sh.1 ash-0.3.7.orig/sh.1 +--- netbsd-sh/sh.1 Fri Jan 12 17:50:40 2001 ++++ ash-0.3.7.orig/sh.1 Mon Apr 23 22:16:46 2001 +@@ -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 --git a/ash/patches/ash-memout.patch b/ash/patches/ash-memout.patch @@ -0,0 +1,333 @@ +diff -u ash-0.4.0/eval.c ash-0.4.0-/eval.c +--- ash-0.4.0/eval.c Tue Apr 24 00:53:12 2001 ++++ ash-0.4.0-/eval.c Tue Apr 24 00:13:57 2001 +@@ -879,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); +@@ -928,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); +Common subdirectories: ash-0.4.0/funcs and ash-0.4.0-/funcs +diff -u ash-0.4.0/output.c ash-0.4.0-/output.c +--- ash-0.4.0/output.c Fri Jan 12 17:50:39 2001 ++++ ash-0.4.0-/output.c Tue Apr 24 00:43:44 2001 +@@ -65,6 +65,10 @@ + #include <errno.h> + #include <unistd.h> + #include <stdlib.h> ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++#undef CEOF /* get rid of the redefine warning */ ++#include <fcntl.h> ++#endif + + #include "shell.h" + #include "syntax.h" +@@ -79,9 +83,15 @@ + #define OUTPUT_ERR 01 /* error occurred on output */ + + ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++struct output output = {NULL, NULL, 0, NULL, 0, 1, 0}; ++struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0}; ++struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0}; ++#else + struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; + struct output errout = {NULL, 0, NULL, 100, 2, 0}; + struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; ++#endif + struct output *out1 = &output; + struct output *out2 = &errout; + +@@ -92,9 +102,19 @@ + INCLUDE "output.h" + INCLUDE "memalloc.h" + ++INIT { ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++ initstreams(); ++#endif ++} ++ + RESET { + out1 = &output; + out2 = &errout; ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++ if (memout.stream != NULL) ++ closememout(); ++#endif + if (memout.buf != NULL) { + ckfree(memout.buf); + memout.buf = NULL; +@@ -124,33 +144,22 @@ + + + void +-out1str(p) +- const char *p; +- { +- outstr(p, out1); +-} +- +- +-void +-out2str(p) +- const char *p; +- { +- outstr(p, out2); +-} +- +- +-void + outstr(p, file) + const char *p; + struct output *file; + { ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++ fputs(p, file->stream); ++#else + while (*p) + outc(*p++, file); ++#endif + if (file == out2) + flushout(file); + } + + ++#if !defined(_GNU_SOURCE) || defined(__UCLIBC__) + char out_junk[16]; + + +@@ -183,6 +192,7 @@ + } + dest->nleft--; + } ++#endif + + + void +@@ -192,11 +202,11 @@ + } + + ++#if !defined(_GNU_SOURCE) || defined(__UCLIBC__) + void + flushout(dest) + struct output *dest; + { +- + if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) + return; + if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) +@@ -204,6 +214,7 @@ + dest->nextc = dest->buf; + dest->nleft = dest->bufsize; + } ++#endif + + + void +@@ -264,6 +275,7 @@ + va_end(ap); + } + ++#if !defined(__GLIBC__) && !defined(__UCLIBC__) + void + #ifdef __STDC__ + dprintf(const char *fmt, ...) +@@ -285,6 +297,7 @@ + va_end(ap); + flushout(out2); + } ++#endif + + void + #ifdef __STDC__ +@@ -295,7 +308,9 @@ + #endif + { + va_list ap; ++#if !defined(_GNU_SOURCE) || defined(__UCLIBC__) + struct output strout; ++#endif + #ifndef __STDC__ + char *outbuf; + size_t length; +@@ -308,6 +323,9 @@ + #else + va_start(ap, fmt); + #endif ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++ vsnprintf(outbuf, length, fmt, ap); ++#else + strout.nextc = outbuf; + strout.nleft = length; + strout.fd = BLOCK_OUT; +@@ -316,8 +334,10 @@ + outc('\0', &strout); + if (strout.flags & OUTPUT_ERR) + outbuf[length - 1] = '\0'; ++#endif + } + ++#if !defined(_GNU_SOURCE) || defined(__UCLIBC__) + /* + * Formatted output. This routine handles a subset of the printf formats: + * - Formats supported: d, u, o, p, X, s, and c. +@@ -534,7 +554,7 @@ + } + #endif /* !HAVE_VASPRINTF */ + } +- ++#endif + + + /* +@@ -544,7 +564,7 @@ + int + xwrite(fd, buf, nbytes) + int fd; +- char *buf; ++ const char *buf; + int nbytes; + { + int ntry; +@@ -570,6 +590,8 @@ + } + + ++ ++#ifdef notdef + /* + * Version of ioctl that retries after a signal is caught. + * XXX unused function +@@ -586,3 +608,27 @@ + while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); + return i; + } ++#endif ++ ++ ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++void initstreams() { ++ output.stream = stdout; ++ errout.stream = stderr; ++} ++ ++ ++void ++openmemout() { ++ memout.stream = open_memstream(&memout.buf, &memout.bufsize); ++} ++ ++ ++void ++closememout() { ++ INTOFF; ++ fclose(memout.stream); ++ memout.stream = NULL; ++ INTON; ++} ++#endif +diff -u ash-0.4.0/output.h ash-0.4.0-/output.h +--- ash-0.4.0/output.h Sat Jan 31 19:28:11 1998 ++++ ash-0.4.0-/output.h Tue Apr 24 00:13:57 2001 +@@ -45,13 +45,19 @@ + #else + #include <varargs.h> + #endif ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++#include <stdio.h> ++#endif + + struct output { ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++ FILE *stream; ++#endif + char *nextc; + int nleft; + char *buf; + int bufsize; +- short fd; ++ int fd; + short flags; + }; + +@@ -61,29 +67,44 @@ + extern struct output *out1; + extern struct output *out2; + +-void open_mem __P((char *, int, struct output *)); +-void out1str __P((const char *)); +-void out2str __P((const char *)); + void outstr __P((const char *, struct output *)); ++#ifndef _GNU_SOURCE + void emptyoutbuf __P((struct output *)); ++#endif + void flushall __P((void)); ++#ifndef _GNU_SOURCE + void flushout __P((struct output *)); ++#endif + void freestdout __P((void)); + void outfmt __P((struct output *, const char *, ...)) + __attribute__((__format__(__printf__,2,3))); + void out1fmt __P((const char *, ...)) + __attribute__((__format__(__printf__,1,2))); ++#if !defined(__GLIBC__) && !defined(__UCLIBC__) + void dprintf __P((const char *, ...)) + __attribute__((__format__(__printf__,1,2))); ++#endif + void fmtstr __P((char *, size_t, const char *, ...)) + __attribute__((__format__(__printf__,3,4))); ++#ifndef _GNU_SOURCE + void doformat __P((struct output *, const char *, va_list)); +-int xwrite __P((int, char *, int)); +-int xioctl __P((int, unsigned long, char *)); ++#endif ++int xwrite __P((int, const char *, int)); ++#if defined(_GNU_SOURCE) && !defined(__UCLIBC__) ++void initstreams __P((void)); ++void openmemout __P((void)); ++void closememout __P((void)); + ++#define outc(c, o) putc(c, (o)->stream) ++#define flushout(o) fflush((o)->stream) ++#define doformat(d, f, a) vfprintf((d)->stream, f, a) ++#else + #define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c))) +-#define out1c(c) outc(c, out1); +-#define out2c(c) outc(c, out2); ++#endif ++#define out1c(c) outc(c, out1) ++#define out2c(c) outc(c, out2) ++#define out1str(s) outstr(s, out1) ++#define out2str(s) outstr(s, out2) + + #define OUTPUT_INCL + #endif diff --git a/ash/patches/ash-misc.patch b/ash/patches/ash-misc.patch @@ -0,0 +1,122 @@ +diff -urN netbsd-sh/error.c ash-0.3.7.orig/error.c +--- netbsd-sh/error.c Fri Jan 12 17:50:35 2001 ++++ ash-0.3.7.orig/error.c Mon Apr 23 22:16:46 2001 +@@ -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 -urN netbsd-sh/error.h ash-0.3.7.orig/error.h +--- netbsd-sh/error.h Fri Jul 9 13:02:05 1999 ++++ ash-0.3.7.orig/error.h Mon Apr 23 22:16:46 2001 +@@ -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 -urN netbsd-sh/bltin/bltin.h ash-0.3.7.orig/bltin/bltin.h +--- netbsd-sh/bltin/bltin.h Sat Jul 5 13:12:37 1997 ++++ ash-0.3.7.orig/bltin/bltin.h Mon Apr 23 22:16:46 2001 +@@ -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 -urN netbsd-sh/main.c ash-0.3.7.orig/main.c +--- netbsd-sh/main.c Fri Jan 12 17:50:36 2001 ++++ ash-0.3.7.orig/main.c Mon Apr 23 22:16:46 2001 +@@ -115,6 +119,9 @@ + #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)) { + /* +diff -urN netbsd-sh/var.c ash-0.3.7.orig/var.c +--- netbsd-sh/var.c Fri Jan 12 17:50:40 2001 ++++ ash-0.3.7.orig/var.c Mon Apr 23 22:19:54 2001 +@@ -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 + +@@ -283,6 +289,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 +312,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; diff --git a/ash/patches/ash-ppid.patch b/ash/patches/ash-ppid.patch @@ -0,0 +1,21 @@ +diff -ur ash-0.4.0/var.c ash-0.4.0-ppid/var.c +--- ash-0.4.0/var.c Tue Apr 24 01:23:17 2001 ++++ ash-0.4.0-ppid/var.c Tue Apr 24 01:22:07 2001 +@@ -172,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) { +@@ -193,6 +194,9 @@ + vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# "); + vps1.flags = VSTRFIXED|VTEXTFIXED; + } ++ ++ snprintf(ppid, 29, "%ld", (long)getppid()); ++ setvar("PPID", ppid, VREADONLY|VNOFUNC); + } + + /* diff --git a/ash/patches/ash-redir.patch b/ash/patches/ash-redir.patch @@ -0,0 +1,463 @@ +diff -ur netbsd-sh/eval.c netbsd-sh-/eval.c +--- netbsd-sh/eval.c Tue May 23 12:03:18 2000 ++++ netbsd-sh-/eval.c Mon Apr 23 23:33:34 2001 +@@ -442,6 +442,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; +diff -ur netbsd-sh/exec.c netbsd-sh-/exec.c +--- netbsd-sh/exec.c Fri Jan 12 17:50:35 2001 ++++ netbsd-sh-/exec.c Mon Apr 23 23:33:34 2001 +@@ -125,6 +125,10 @@ + char *cmdname; + int e; + ++ if (fd2 >= 0 && fd2 != 2) { ++ close(fd2); ++ } ++ + if (strchr(argv[0], '/') != NULL) { + tryexec(argv[0], argv, envp); + e = errno; +diff -ur netbsd-sh/jobs.c netbsd-sh-/jobs.c +--- netbsd-sh/jobs.c Mon Apr 23 23:34:53 2001 ++++ netbsd-sh-/jobs.c Mon Apr 23 23:34:30 2001 +@@ -129,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"); +@@ -146,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; +@@ -157,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); +@@ -206,9 +206,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; +@@ -612,10 +612,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 + } +@@ -734,10 +734,10 @@ + #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 + } +@@ -1092,6 +1092,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: +Only in netbsd-sh-: jobs.c.orig +diff -ur netbsd-sh/nodetypes netbsd-sh-/nodetypes +--- netbsd-sh/nodetypes Fri Feb 5 13:04:52 1999 ++++ netbsd-sh-/nodetypes Mon Apr 23 23:33:34 2001 +@@ -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 -ur netbsd-sh/parser.c netbsd-sh-/parser.c +--- netbsd-sh/parser.c Fri Jan 12 17:50:39 2001 ++++ netbsd-sh-/parser.c Mon Apr 23 23:33:34 2001 +@@ -1125,6 +1125,8 @@ + np->type = NAPPEND; + else if (c == '&') + np->type = NTOFD; ++ else if (c == '|') ++ np->type = NTOOV; + else { + np->type = NTO; + pungetc(); +diff -ur netbsd-sh/redir.c netbsd-sh-/redir.c +--- netbsd-sh/redir.c Tue May 23 12:03:19 2000 ++++ netbsd-sh-/redir.c Mon Apr 23 23:33:34 2001 +@@ -45,6 +45,7 @@ + #endif + #endif /* not lint */ + ++#include <sys/stat.h> + #include <sys/types.h> + #include <sys/param.h> /* PIPE_BUF */ + #include <signal.h> +@@ -66,6 +67,7 @@ + #include "output.h" + #include "memalloc.h" + #include "error.h" ++#include "options.h" + + + #define EMPTY -2 /* marks an unused slot in redirtab */ +@@ -92,8 +94,15 @@ + */ + int fd0_redirected = 0; + +-STATIC void openredirect __P((union node *, char[10 ])); ++/* ++ * We also keep track of where fd2 goes. ++ */ ++int fd2 = 2; ++ ++STATIC int openredirect __P((union node *)); ++STATIC void dupredirect __P((union node *, int, char[10 ])); + STATIC int openhere __P((union node *)); ++STATIC int noclobberopen __P((const char *)); + + + /* +@@ -113,6 +122,7 @@ + struct redirtab *sv = NULL; + int i; + int fd; ++ int newfd; + int try; + char memory[10]; /* file descriptors to write to memory */ + +@@ -133,36 +143,47 @@ + n->ndup.dupfd == fd) + continue; /* redirect from/to same file descriptor */ + +- if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { +- INTOFF; +-again: +- if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { ++ INTOFF; ++ newfd = openredirect(n); ++ if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) || ++ (fd == fd2)) { ++ if (newfd == fd) { ++ try++; ++ } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { + switch (errno) { + case EBADF: + if (!try) { +- openredirect(n, memory); ++ dupredirect(n, newfd, memory); + try++; +- goto again; ++ break; + } + /* FALLTHROUGH*/ + default: ++ if (newfd >= 0) { ++ close(newfd); ++ } + INTON; + error("%d: %s", fd, strerror(errno)); + /* NOTREACHED */ + } + } + if (!try) { +- sv->renamed[fd] = i; + close(fd); ++ if (flags & REDIR_PUSH) { ++ sv->renamed[fd] = i; ++ } ++ if (fd == fd2) { ++ fd2 = i; ++ } + } +- INTON; +- } else { ++ } else if (fd != newfd) { + close(fd); + } + if (fd == 0) + fd0_redirected++; + if (!try) +- openredirect(n, memory); ++ dupredirect(n, newfd, memory); ++ INTON; + } + if (memory[1]) + out1 = &memout; +@@ -171,22 +192,13 @@ + } + + +-STATIC void +-openredirect(redir, memory) ++STATIC int ++openredirect(redir) + union node *redir; +- char memory[10]; + { +- int fd = redir->nfile.fd; + char *fname; + int f; + +- /* +- * We suppress interrupts so that we won't leave open file +- * descriptors around. This may not be such a good idea because +- * an open of a device or a fifo can block indefinitely. +- */ +- INTOFF; +- memory[fd] = 0; + switch (redir->nfile.type) { + case NFROM: + fname = redir->nfile.expfname; +@@ -199,6 +211,14 @@ + goto ecreate; + break; + case NTO: ++ /* Take care of noclobber mode. */ ++ if (Cflag) { ++ fname = redir->nfile.expfname; ++ if ((f = noclobberopen(fname)) < 0) ++ goto ecreate; ++ break; ++ } ++ case NTOOV: + fname = redir->nfile.expfname; + #ifdef O_CREAT + if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) +@@ -222,32 +242,48 @@ + break; + case NTOFD: + case NFROMFD: ++ f = -1; ++ break; ++ case NHERE: ++ case NXHERE: ++ f = openhere(redir); ++ break; ++ default: ++ abort(); ++ } ++ ++ return f; ++ecreate: ++ error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); ++eopen: ++ error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); ++} ++ ++ ++STATIC void ++dupredirect(redir, f, memory) ++ union node *redir; ++ int f; ++ char memory[10]; ++ { ++ int fd = redir->nfile.fd; ++ ++ memory[fd] = 0; ++ if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { + if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ + if (memory[redir->ndup.dupfd]) + memory[fd] = 1; + else + copyfd(redir->ndup.dupfd, fd); + } +- INTON; + return; +- case NHERE: +- case NXHERE: +- f = openhere(redir); +- break; +- default: +- abort(); + } + + if (f != fd) { + copyfd(f, fd); + close(f); + } +- INTON; + return; +-ecreate: +- error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); +-eopen: +- error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); + } + + +@@ -304,6 +340,7 @@ + struct redirtab *rp = redirlist; + int i; + ++ INTOFF; + for (i = 0 ; i < 10 ; i++) { + if (rp->renamed[i] != EMPTY) { + if (i == 0) +@@ -313,9 +350,11 @@ + copyfd(rp->renamed[i], i); + close(rp->renamed[i]); + } ++ if (rp->renamed[i] == fd2) { ++ fd2 = i; ++ } + } + } +- INTOFF; + redirlist = rp->next; + ckfree(rp); + INTON; +@@ -359,6 +398,9 @@ + for (i = 0 ; i < 10 ; i++) { + if (rp->renamed[i] >= 0) { + close(rp->renamed[i]); ++ if (rp->renamed[i] == fd2) { ++ fd2 = -1; ++ } + } + rp->renamed[i] = EMPTY; + } +@@ -388,4 +430,63 @@ + error("%d: %s", from, strerror(errno)); + } + 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; + } +Only in netbsd-sh-: redir.c.orig +diff -ur netbsd-sh/redir.h netbsd-sh-/redir.h +--- netbsd-sh/redir.h Tue May 23 12:03:19 2000 ++++ netbsd-sh-/redir.h Mon Apr 23 23:33:34 2001 +@@ -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 -ur netbsd-sh/show.c netbsd-sh-/show.c +--- netbsd-sh/show.c Sat Oct 9 13:02:09 1999 ++++ netbsd-sh-/show.c Mon Apr 23 23:33:34 2001 +@@ -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 --git a/ash/patches/ash-setmode.patch b/ash/patches/ash-setmode.patch @@ -0,0 +1,510 @@ +diff -urN netbsd-sh/miscbltin.c ash-0.3.7.orig/miscbltin.c +--- netbsd-sh/miscbltin.c Fri Jan 12 17:50:37 2001 ++++ ash-0.3.7.orig/miscbltin.c Mon Apr 23 22:16:46 2001 +@@ -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 -urN netbsd-sh/setmode.c ash-0.3.7.orig/setmode.c +--- netbsd-sh/setmode.c Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/setmode.c Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,486 @@ ++/* $NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $ */ ++ ++/* ++ * Copyright (c) 1989, 1993, 1994 ++ * The Regents of the University of California. All rights reserved. ++ * ++ * This code is derived from software contributed to Berkeley by ++ * Dave Borman at Cray Research, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by the University of ++ * California, Berkeley and its contributors. ++ * 4. Neither the name of the University nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++#include <sys/cdefs.h> ++#if defined(LIBC_SCCS) && !defined(lint) ++#if 0 ++static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94"; ++#else ++__RCSID("$NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $"); ++#endif ++#endif /* LIBC_SCCS and not lint */ ++ ++#include <sys/types.h> ++#include <sys/stat.h> ++ ++#include <assert.h> ++#include <ctype.h> ++#include <errno.h> ++#include <signal.h> ++#include <stdlib.h> ++#include <unistd.h> ++ ++#ifdef SETMODE_DEBUG ++#include <stdio.h> ++#endif ++ ++#ifdef __weak_alias ++__weak_alias(getmode,_getmode) ++__weak_alias(setmode,_setmode) ++#endif ++ ++#ifdef __GLIBC__ ++#define S_ISTXT __S_ISVTX ++#endif ++ ++#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ ++#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ ++ ++typedef struct bitcmd { ++ char cmd; ++ char cmd2; ++ mode_t bits; ++} BITCMD; ++ ++#define CMD2_CLR 0x01 ++#define CMD2_SET 0x02 ++#define CMD2_GBITS 0x04 ++#define CMD2_OBITS 0x08 ++#define CMD2_UBITS 0x10 ++ ++static BITCMD *addcmd __P((BITCMD *, int, int, int, u_int)); ++static void compress_mode __P((BITCMD *)); ++#ifdef SETMODE_DEBUG ++static void dumpmode __P((BITCMD *)); ++#endif ++ ++/* ++ * Given the old mode and an array of bitcmd structures, apply the operations ++ * described in the bitcmd structures to the old mode, and return the new mode. ++ * Note that there is no '=' command; a strict assignment is just a '-' (clear ++ * bits) followed by a '+' (set bits). ++ */ ++mode_t ++getmode(bbox, omode) ++ const void *bbox; ++ mode_t omode; ++{ ++ const BITCMD *set; ++ mode_t clrval, newmode, value; ++ ++ _DIAGASSERT(bbox != NULL); ++ ++ set = (const BITCMD *)bbox; ++ newmode = omode; ++ for (value = 0;; set++) ++ switch(set->cmd) { ++ /* ++ * When copying the user, group or other bits around, we "know" ++ * where the bits are in the mode so that we can do shifts to ++ * copy them around. If we don't use shifts, it gets real ++ * grundgy with lots of single bit checks and bit sets. ++ */ ++ case 'u': ++ value = (newmode & S_IRWXU) >> 6; ++ goto common; ++ ++ case 'g': ++ value = (newmode & S_IRWXG) >> 3; ++ goto common; ++ ++ case 'o': ++ value = newmode & S_IRWXO; ++common: if (set->cmd2 & CMD2_CLR) { ++ clrval = ++ (set->cmd2 & CMD2_SET) ? S_IRWXO : value; ++ if (set->cmd2 & CMD2_UBITS) ++ newmode &= ~((clrval<<6) & set->bits); ++ if (set->cmd2 & CMD2_GBITS) ++ newmode &= ~((clrval<<3) & set->bits); ++ if (set->cmd2 & CMD2_OBITS) ++ newmode &= ~(clrval & set->bits); ++ } ++ if (set->cmd2 & CMD2_SET) { ++ if (set->cmd2 & CMD2_UBITS) ++ newmode |= (value<<6) & set->bits; ++ if (set->cmd2 & CMD2_GBITS) ++ newmode |= (value<<3) & set->bits; ++ if (set->cmd2 & CMD2_OBITS) ++ newmode |= value & set->bits; ++ } ++ break; ++ ++ case '+': ++ newmode |= set->bits; ++ break; ++ ++ case '-': ++ newmode &= ~set->bits; ++ break; ++ ++ case 'X': ++ if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) ++ newmode |= set->bits; ++ break; ++ ++ case '\0': ++ default: ++#ifdef SETMODE_DEBUG ++ (void)printf("getmode:%04o -> %04o\n", omode, newmode); ++#endif ++ return (newmode); ++ } ++} ++ ++#define ADDCMD(a, b, c, d) do { \ ++ if (set >= endset) { \ ++ BITCMD *newset; \ ++ setlen += SET_LEN_INCR; \ ++ newset = realloc(saveset, sizeof(BITCMD) * setlen); \ ++ if (newset == NULL) { \ ++ free(saveset); \ ++ return (NULL); \ ++ } \ ++ set = newset + (set - saveset); \ ++ saveset = newset; \ ++ endset = newset + (setlen - 2); \ ++ } \ ++ set = addcmd(set, (a), (b), (c), (d)); \ ++} while (/*CONSTCOND*/0) ++ ++#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) ++ ++void * ++setmode(p) ++ const char *p; ++{ ++ int perm, who; ++ char op, *ep; ++ BITCMD *set, *saveset, *endset; ++ sigset_t sigset, sigoset; ++ mode_t mask; ++ int equalopdone = 0; /* pacify gcc */ ++ int permXbits, setlen; ++ ++ if (!*p) ++ return (NULL); ++ ++ /* ++ * Get a copy of the mask for the permissions that are mask relative. ++ * Flip the bits, we want what's not set. Since it's possible that ++ * the caller is opening files inside a signal handler, protect them ++ * as best we can. ++ */ ++ sigfillset(&sigset); ++ (void)sigprocmask(SIG_BLOCK, &sigset, &sigoset); ++ (void)umask(mask = umask(0)); ++ mask = ~mask; ++ (void)sigprocmask(SIG_SETMASK, &sigoset, NULL); ++ ++ setlen = SET_LEN + 2; ++ ++ if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL) ++ return (NULL); ++ saveset = set; ++ endset = set + (setlen - 2); ++ ++ /* ++ * If an absolute number, get it and return; disallow non-octal digits ++ * or illegal bits. ++ */ ++ if (isdigit((unsigned char)*p)) { ++ perm = (mode_t)strtol(p, &ep, 8); ++ if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) { ++ free(saveset); ++ return (NULL); ++ } ++ ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); ++ set->cmd = 0; ++ return (saveset); ++ } ++ ++ /* ++ * Build list of structures to set/clear/copy bits as described by ++ * each clause of the symbolic mode. ++ */ ++ for (;;) { ++ /* First, find out which bits might be modified. */ ++ for (who = 0;; ++p) { ++ switch (*p) { ++ case 'a': ++ who |= STANDARD_BITS; ++ break; ++ case 'u': ++ who |= S_ISUID|S_IRWXU; ++ break; ++ case 'g': ++ who |= S_ISGID|S_IRWXG; ++ break; ++ case 'o': ++ who |= S_IRWXO; ++ break; ++ default: ++ goto getop; ++ } ++ } ++ ++getop: if ((op = *p++) != '+' && op != '-' && op != '=') { ++ free(saveset); ++ return (NULL); ++ } ++ if (op == '=') ++ equalopdone = 0; ++ ++ who &= ~S_ISTXT; ++ for (perm = 0, permXbits = 0;; ++p) { ++ switch (*p) { ++ case 'r': ++ perm |= S_IRUSR|S_IRGRP|S_IROTH; ++ break; ++ case 's': ++ /* ++ * If specific bits where requested and ++ * only "other" bits ignore set-id. ++ */ ++ if (who == 0 || (who & ~S_IRWXO)) ++ perm |= S_ISUID|S_ISGID; ++ break; ++ case 't': ++ /* ++ * If specific bits where requested and ++ * only "other" bits ignore set-id. ++ */ ++ if (who == 0 || (who & ~S_IRWXO)) { ++ who |= S_ISTXT; ++ perm |= S_ISTXT; ++ } ++ break; ++ case 'w': ++ perm |= S_IWUSR|S_IWGRP|S_IWOTH; ++ break; ++ case 'X': ++ permXbits = S_IXUSR|S_IXGRP|S_IXOTH; ++ break; ++ case 'x': ++ perm |= S_IXUSR|S_IXGRP|S_IXOTH; ++ break; ++ case 'u': ++ case 'g': ++ case 'o': ++ /* ++ * When ever we hit 'u', 'g', or 'o', we have ++ * to flush out any partial mode that we have, ++ * and then do the copying of the mode bits. ++ */ ++ if (perm) { ++ ADDCMD(op, who, perm, mask); ++ perm = 0; ++ } ++ if (op == '=') ++ equalopdone = 1; ++ if (op == '+' && permXbits) { ++ ADDCMD('X', who, permXbits, mask); ++ permXbits = 0; ++ } ++ ADDCMD(*p, who, op, mask); ++ break; ++ ++ default: ++ /* ++ * Add any permissions that we haven't already ++ * done. ++ */ ++ if (perm || (op == '=' && !equalopdone)) { ++ if (op == '=') ++ equalopdone = 1; ++ ADDCMD(op, who, perm, mask); ++ perm = 0; ++ } ++ if (permXbits) { ++ ADDCMD('X', who, permXbits, mask); ++ permXbits = 0; ++ } ++ goto apply; ++ } ++ } ++ ++apply: if (!*p) ++ break; ++ if (*p != ',') ++ goto getop; ++ ++p; ++ } ++ set->cmd = 0; ++#ifdef SETMODE_DEBUG ++ (void)printf("Before compress_mode()\n"); ++ dumpmode(saveset); ++#endif ++ compress_mode(saveset); ++#ifdef SETMODE_DEBUG ++ (void)printf("After compress_mode()\n"); ++ dumpmode(saveset); ++#endif ++ return (saveset); ++} ++ ++static BITCMD * ++addcmd(set, op, who, oparg, mask) ++ BITCMD *set; ++ int oparg, who; ++ int op; ++ u_int mask; ++{ ++ ++ _DIAGASSERT(set != NULL); ++ ++ switch (op) { ++ case '=': ++ set->cmd = '-'; ++ set->bits = who ? who : STANDARD_BITS; ++ set++; ++ ++ op = '+'; ++ /* FALLTHROUGH */ ++ case '+': ++ case '-': ++ case 'X': ++ set->cmd = op; ++ set->bits = (who ? who : mask) & oparg; ++ break; ++ ++ case 'u': ++ case 'g': ++ case 'o': ++ set->cmd = op; ++ if (who) { ++ set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) | ++ ((who & S_IRGRP) ? CMD2_GBITS : 0) | ++ ((who & S_IROTH) ? CMD2_OBITS : 0); ++ set->bits = (mode_t)~0; ++ } else { ++ set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS; ++ set->bits = mask; ++ } ++ ++ if (oparg == '+') ++ set->cmd2 |= CMD2_SET; ++ else if (oparg == '-') ++ set->cmd2 |= CMD2_CLR; ++ else if (oparg == '=') ++ set->cmd2 |= CMD2_SET|CMD2_CLR; ++ break; ++ } ++ return (set + 1); ++} ++ ++#ifdef SETMODE_DEBUG ++static void ++dumpmode(set) ++ BITCMD *set; ++{ ++ ++ _DIAGASSERT(set != NULL); ++ ++ for (; set->cmd; ++set) ++ (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n", ++ set->cmd, set->bits, set->cmd2 ? " cmd2:" : "", ++ set->cmd2 & CMD2_CLR ? " CLR" : "", ++ set->cmd2 & CMD2_SET ? " SET" : "", ++ set->cmd2 & CMD2_UBITS ? " UBITS" : "", ++ set->cmd2 & CMD2_GBITS ? " GBITS" : "", ++ set->cmd2 & CMD2_OBITS ? " OBITS" : ""); ++} ++#endif ++ ++/* ++ * Given an array of bitcmd structures, compress by compacting consecutive ++ * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u', ++ * 'g' and 'o' commands continue to be separate. They could probably be ++ * compacted, but it's not worth the effort. ++ */ ++static void ++compress_mode(set) ++ BITCMD *set; ++{ ++ BITCMD *nset; ++ int setbits, clrbits, Xbits, op; ++ ++ _DIAGASSERT(set != NULL); ++ ++ for (nset = set;;) { ++ /* Copy over any 'u', 'g' and 'o' commands. */ ++ while ((op = nset->cmd) != '+' && op != '-' && op != 'X') { ++ *set++ = *nset++; ++ if (!op) ++ return; ++ } ++ ++ for (setbits = clrbits = Xbits = 0;; nset++) { ++ if ((op = nset->cmd) == '-') { ++ clrbits |= nset->bits; ++ setbits &= ~nset->bits; ++ Xbits &= ~nset->bits; ++ } else if (op == '+') { ++ setbits |= nset->bits; ++ clrbits &= ~nset->bits; ++ Xbits &= ~nset->bits; ++ } else if (op == 'X') ++ Xbits |= nset->bits & ~setbits; ++ else ++ break; ++ } ++ if (clrbits) { ++ set->cmd = '-'; ++ set->cmd2 = 0; ++ set->bits = clrbits; ++ set++; ++ } ++ if (setbits) { ++ set->cmd = '+'; ++ set->cmd2 = 0; ++ set->bits = setbits; ++ set++; ++ } ++ if (Xbits) { ++ set->cmd = 'X'; ++ set->cmd2 = 0; ++ set->bits = Xbits; ++ set++; ++ } ++ } ++} + diff --git a/ash/patches/ash-sighup.patch b/ash/patches/ash-sighup.patch @@ -0,0 +1,18 @@ +--- ash-0.4.0/jobs.c.orig Tue Jul 3 19:10:28 2001 ++++ ash-0.4.0/jobs.c Tue Jul 3 19:12:11 2001 +@@ -712,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); +@@ -723,6 +724,7 @@ + if (mode == FORK_BG) { + ignoresig(SIGINT); + ignoresig(SIGQUIT); ++ ignoresig(SIGHUP); + if ((jp == NULL || jp->nprocs == 0) && + ! fd0_redirected_p ()) { + close(0); diff --git a/ash/patches/ash-syntax.patch b/ash/patches/ash-syntax.patch @@ -0,0 +1,270 @@ +diff -urN netbsd-sh/mksyntax.c ash-0.3.7.orig/mksyntax.c +--- netbsd-sh/mksyntax.c Fri Jan 12 17:50:38 2001 ++++ ash-0.3.7.orig/mksyntax.c Mon Apr 23 22:16:46 2001 +@@ -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 -urN netbsd-sh/parser.c ash-0.3.7.orig/parser.c +--- netbsd-sh/parser.c Fri Jan 12 17:50:39 2001 ++++ ash-0.3.7.orig/parser.c Mon Apr 23 22:16:46 2001 +@@ -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); +@@ -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 --git a/ash/patches/ash-test.patch b/ash/patches/ash-test.patch @@ -0,0 +1,588 @@ +diff -urN netbsd-sh/bltin/test.c ash-0.3.7.orig/bltin/test.c +--- netbsd-sh/bltin/test.c Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/bltin/test.c Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,583 @@ ++/* $NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $ */ ++ ++/* ++ * test(1); version 7-like -- author Erik Baalbergen ++ * modified by Eric Gisin to be used as built-in. ++ * modified by Arnold Robbins to add SVR3 compatibility ++ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). ++ * modified by J.T. Conklin for NetBSD. ++ * ++ * This program is in the Public Domain. ++ */ ++ ++#include <sys/cdefs.h> ++#ifndef lint ++__RCSID("$NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $"); ++#endif ++ ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <unistd.h> ++#include <ctype.h> ++#include <errno.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <err.h> ++#ifdef __STDC__ ++#include <stdarg.h> ++#else ++#include <varargs.h> ++#endif ++ ++/* test(1) accepts the following grammar: ++ oexpr ::= aexpr | aexpr "-o" oexpr ; ++ aexpr ::= nexpr | nexpr "-a" aexpr ; ++ nexpr ::= primary | "!" primary ++ primary ::= unary-operator operand ++ | operand binary-operator operand ++ | operand ++ | "(" oexpr ")" ++ ; ++ unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| ++ "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; ++ ++ binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| ++ "-nt"|"-ot"|"-ef"; ++ operand ::= <any legal UNIX file name> ++*/ ++ ++enum token { ++ EOI, ++ FILRD, ++ FILWR, ++ FILEX, ++ FILEXIST, ++ FILREG, ++ FILDIR, ++ FILCDEV, ++ FILBDEV, ++ FILFIFO, ++ FILSOCK, ++ FILSYM, ++ FILGZ, ++ FILTT, ++ FILSUID, ++ FILSGID, ++ FILSTCK, ++ FILNT, ++ FILOT, ++ FILEQ, ++ FILUID, ++ FILGID, ++ STREZ, ++ STRNZ, ++ STREQ, ++ STRNE, ++ STRLT, ++ STRGT, ++ INTEQ, ++ INTNE, ++ INTGE, ++ INTGT, ++ INTLE, ++ INTLT, ++ UNOT, ++ BAND, ++ BOR, ++ LPAREN, ++ RPAREN, ++ OPERAND ++}; ++ ++enum token_types { ++ UNOP, ++ BINOP, ++ BUNOP, ++ BBINOP, ++ PAREN ++}; ++ ++static struct t_op { ++ const char *op_text; ++ short op_num, op_type; ++} const ops [] = { ++ {"-r", FILRD, UNOP}, ++ {"-w", FILWR, UNOP}, ++ {"-x", FILEX, UNOP}, ++ {"-e", FILEXIST,UNOP}, ++ {"-f", FILREG, UNOP}, ++ {"-d", FILDIR, UNOP}, ++ {"-c", FILCDEV,UNOP}, ++ {"-b", FILBDEV,UNOP}, ++ {"-p", FILFIFO,UNOP}, ++ {"-u", FILSUID,UNOP}, ++ {"-g", FILSGID,UNOP}, ++ {"-k", FILSTCK,UNOP}, ++ {"-s", FILGZ, UNOP}, ++ {"-t", FILTT, UNOP}, ++ {"-z", STREZ, UNOP}, ++ {"-n", STRNZ, UNOP}, ++ {"-h", FILSYM, UNOP}, /* for backwards compat */ ++ {"-O", FILUID, UNOP}, ++ {"-G", FILGID, UNOP}, ++ {"-L", FILSYM, UNOP}, ++ {"-S", FILSOCK,UNOP}, ++ {"=", STREQ, BINOP}, ++ {"!=", STRNE, BINOP}, ++ {"<", STRLT, BINOP}, ++ {">", STRGT, BINOP}, ++ {"-eq", INTEQ, BINOP}, ++ {"-ne", INTNE, BINOP}, ++ {"-ge", INTGE, BINOP}, ++ {"-gt", INTGT, BINOP}, ++ {"-le", INTLE, BINOP}, ++ {"-lt", INTLT, BINOP}, ++ {"-nt", FILNT, BINOP}, ++ {"-ot", FILOT, BINOP}, ++ {"-ef", FILEQ, BINOP}, ++ {"!", UNOT, BUNOP}, ++ {"-a", BAND, BBINOP}, ++ {"-o", BOR, BBINOP}, ++ {"(", LPAREN, PAREN}, ++ {")", RPAREN, PAREN}, ++ {0, 0, 0} ++}; ++ ++static char **t_wp; ++static struct t_op const *t_wp_op; ++static gid_t *group_array = NULL; ++static int ngroups; ++ ++static void syntax __P((const char *, const char *)); ++static int oexpr __P((enum token)); ++static int aexpr __P((enum token)); ++static int nexpr __P((enum token)); ++static int primary __P((enum token)); ++static int binop __P((void)); ++static int filstat __P((char *, enum token)); ++static enum token t_lex __P((char *)); ++static int isoperand __P((void)); ++static int getn __P((const char *)); ++static int newerf __P((const char *, const char *)); ++static int olderf __P((const char *, const char *)); ++static int equalf __P((const char *, const char *)); ++static int test_eaccess(); ++static int bash_group_member(); ++static void initialize_group_array(); ++ ++#if defined(SHELL) ++extern void error __P((const char *, ...)) __attribute__((__noreturn__)); ++#else ++static void error __P((const char *, ...)) __attribute__((__noreturn__)); ++ ++static void ++#ifdef __STDC__ ++error(const char *msg, ...) ++#else ++error(va_alist) ++ va_dcl ++#endif ++{ ++ va_list ap; ++#ifndef __STDC__ ++ const char *msg; ++ ++ va_start(ap); ++ msg = va_arg(ap, const char *); ++#else ++ va_start(ap, msg); ++#endif ++ verrx(2, msg, ap); ++ /*NOTREACHED*/ ++ va_end(ap); ++} ++#endif ++ ++#ifdef SHELL ++int testcmd __P((int, char **)); ++ ++int ++testcmd(argc, argv) ++ int argc; ++ char **argv; ++#else ++int main __P((int, char **)); ++ ++int ++main(argc, argv) ++ int argc; ++ char **argv; ++#endif ++{ ++ int res; ++ ++ ++ if (strcmp(argv[0], "[") == 0) { ++ if (strcmp(argv[--argc], "]")) ++ error("missing ]"); ++ argv[argc] = NULL; ++ } ++ ++ if (argc < 2) ++ return 1; ++ ++ t_wp = &argv[1]; ++ res = !oexpr(t_lex(*t_wp)); ++ ++ if (*t_wp != NULL && *++t_wp != NULL) ++ syntax(*t_wp, "unexpected operator"); ++ ++ return res; ++} ++ ++static void ++syntax(op, msg) ++ const char *op; ++ const char *msg; ++{ ++ if (op && *op) ++ error("%s: %s", op, msg); ++ else ++ error("%s", msg); ++} ++ ++static int ++oexpr(n) ++ enum token n; ++{ ++ int res; ++ ++ res = aexpr(n); ++ if (t_lex(*++t_wp) == BOR) ++ return oexpr(t_lex(*++t_wp)) || res; ++ t_wp--; ++ return res; ++} ++ ++static int ++aexpr(n) ++ enum token n; ++{ ++ int res; ++ ++ res = nexpr(n); ++ if (t_lex(*++t_wp) == BAND) ++ return aexpr(t_lex(*++t_wp)) && res; ++ t_wp--; ++ return res; ++} ++ ++static int ++nexpr(n) ++ enum token n; /* token */ ++{ ++ if (n == UNOT) ++ return !nexpr(t_lex(*++t_wp)); ++ return primary(n); ++} ++ ++static int ++primary(n) ++ enum token n; ++{ ++ enum token nn; ++ int res; ++ ++ if (n == EOI) ++ return 0; /* missing expression */ ++ if (n == LPAREN) { ++ if ((nn = t_lex(*++t_wp)) == RPAREN) ++ return 0; /* missing expression */ ++ res = oexpr(nn); ++ if (t_lex(*++t_wp) != RPAREN) ++ syntax(NULL, "closing paren expected"); ++ return res; ++ } ++ if (t_wp_op && t_wp_op->op_type == UNOP) { ++ /* unary expression */ ++ if (*++t_wp == NULL) ++ syntax(t_wp_op->op_text, "argument expected"); ++ switch (n) { ++ case STREZ: ++ return strlen(*t_wp) == 0; ++ case STRNZ: ++ return strlen(*t_wp) != 0; ++ case FILTT: ++ return isatty(getn(*t_wp)); ++ default: ++ return filstat(*t_wp, n); ++ } ++ } ++ ++ if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { ++ return binop(); ++ } ++ ++ return strlen(*t_wp) > 0; ++} ++ ++static int ++binop() ++{ ++ const char *opnd1, *opnd2; ++ struct t_op const *op; ++ ++ opnd1 = *t_wp; ++ (void) t_lex(*++t_wp); ++ op = t_wp_op; ++ ++ if ((opnd2 = *++t_wp) == (char *)0) ++ syntax(op->op_text, "argument expected"); ++ ++ switch (op->op_num) { ++ case STREQ: ++ return strcmp(opnd1, opnd2) == 0; ++ case STRNE: ++ return strcmp(opnd1, opnd2) != 0; ++ case STRLT: ++ return strcmp(opnd1, opnd2) < 0; ++ case STRGT: ++ return strcmp(opnd1, opnd2) > 0; ++ case INTEQ: ++ return getn(opnd1) == getn(opnd2); ++ case INTNE: ++ return getn(opnd1) != getn(opnd2); ++ case INTGE: ++ return getn(opnd1) >= getn(opnd2); ++ case INTGT: ++ return getn(opnd1) > getn(opnd2); ++ case INTLE: ++ return getn(opnd1) <= getn(opnd2); ++ case INTLT: ++ return getn(opnd1) < getn(opnd2); ++ case FILNT: ++ return newerf (opnd1, opnd2); ++ case FILOT: ++ return olderf (opnd1, opnd2); ++ case FILEQ: ++ return equalf (opnd1, opnd2); ++ default: ++ abort(); ++ /* NOTREACHED */ ++ } ++} ++ ++static int ++filstat(nm, mode) ++ char *nm; ++ enum token mode; ++{ ++ struct stat s; ++ ++ if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s)) ++ return 0; ++ ++ switch (mode) { ++ case FILRD: ++ return test_eaccess(nm, R_OK) == 0; ++ case FILWR: ++ return test_eaccess(nm, W_OK) == 0; ++ case FILEX: ++ return test_eaccess(nm, X_OK) == 0; ++ case FILEXIST: ++ return 1; ++ case FILREG: ++ return S_ISREG(s.st_mode); ++ case FILDIR: ++ return S_ISDIR(s.st_mode); ++ case FILCDEV: ++ return S_ISCHR(s.st_mode); ++ case FILBDEV: ++ return S_ISBLK(s.st_mode); ++ case FILFIFO: ++ return S_ISFIFO(s.st_mode); ++ case FILSOCK: ++ return S_ISSOCK(s.st_mode); ++ case FILSYM: ++ return S_ISLNK(s.st_mode); ++ case FILSUID: ++ return (s.st_mode & S_ISUID) != 0; ++ case FILSGID: ++ return (s.st_mode & S_ISGID) != 0; ++ case FILSTCK: ++ return (s.st_mode & S_ISVTX) != 0; ++ case FILGZ: ++ return s.st_size > (off_t)0; ++ case FILUID: ++ return s.st_uid == geteuid(); ++ case FILGID: ++ return s.st_gid == getegid(); ++ default: ++ return 1; ++ } ++} ++ ++static enum token ++t_lex(s) ++ char *s; ++{ ++ struct t_op const *op = ops; ++ ++ if (s == 0) { ++ t_wp_op = (struct t_op *)0; ++ return EOI; ++ } ++ while (op->op_text) { ++ if (strcmp(s, op->op_text) == 0) { ++ if ((op->op_type == UNOP && isoperand()) || ++ (op->op_num == LPAREN && *(t_wp+1) == 0)) ++ break; ++ t_wp_op = op; ++ return op->op_num; ++ } ++ op++; ++ } ++ t_wp_op = (struct t_op *)0; ++ return OPERAND; ++} ++ ++static int ++isoperand() ++{ ++ struct t_op const *op = ops; ++ char *s; ++ char *t; ++ ++ if ((s = *(t_wp+1)) == 0) ++ return 1; ++ if ((t = *(t_wp+2)) == 0) ++ return 0; ++ while (op->op_text) { ++ if (strcmp(s, op->op_text) == 0) ++ return op->op_type == BINOP && ++ (t[0] != ')' || t[1] != '\0'); ++ op++; ++ } ++ return 0; ++} ++ ++/* atoi with error detection */ ++static int ++getn(s) ++ const char *s; ++{ ++ char *p; ++ long r; ++ ++ errno = 0; ++ r = strtol(s, &p, 10); ++ ++ if (errno != 0) ++ error("%s: out of range", s); ++ ++ while (isspace((unsigned char)*p)) ++ p++; ++ ++ if (*p) ++ error("%s: bad number", s); ++ ++ return (int) r; ++} ++ ++static int ++newerf (f1, f2) ++const char *f1, *f2; ++{ ++ struct stat b1, b2; ++ ++ return (stat (f1, &b1) == 0 && ++ stat (f2, &b2) == 0 && ++ b1.st_mtime > b2.st_mtime); ++} ++ ++static int ++olderf (f1, f2) ++const char *f1, *f2; ++{ ++ struct stat b1, b2; ++ ++ return (stat (f1, &b1) == 0 && ++ stat (f2, &b2) == 0 && ++ b1.st_mtime < b2.st_mtime); ++} ++ ++static int ++equalf (f1, f2) ++const char *f1, *f2; ++{ ++ struct stat b1, b2; ++ ++ return (stat (f1, &b1) == 0 && ++ stat (f2, &b2) == 0 && ++ b1.st_dev == b2.st_dev && ++ b1.st_ino == b2.st_ino); ++} ++ ++/* Do the same thing access(2) does, but use the effective uid and gid, ++ and don't make the mistake of telling root that any file is ++ executable. */ ++static int ++test_eaccess (path, mode) ++char *path; ++int mode; ++{ ++ struct stat st; ++ int euid = geteuid(); ++ ++ if (stat (path, &st) < 0) ++ return (-1); ++ ++ if (euid == 0) { ++ /* Root can read or write any file. */ ++ if (mode != X_OK) ++ return (0); ++ ++ /* Root can execute any file that has any one of the execute ++ bits set. */ ++ if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) ++ return (0); ++ } ++ ++ if (st.st_uid == euid) /* owner */ ++ mode <<= 6; ++ else if (bash_group_member (st.st_gid)) ++ mode <<= 3; ++ ++ if (st.st_mode & mode) ++ return (0); ++ ++ return (-1); ++} ++ ++static void ++initialize_group_array () ++{ ++ ngroups = getgroups(0, NULL); ++ group_array = malloc(ngroups * sizeof(gid_t)); ++ if (!group_array) ++ error(strerror(ENOMEM)); ++ getgroups(ngroups, group_array); ++} ++ ++/* Return non-zero if GID is one that we have in our groups list. */ ++static int ++bash_group_member (gid) ++gid_t gid; ++{ ++ register int i; ++ ++ /* Short-circuit if possible, maybe saving a call to getgroups(). */ ++ if (gid == getgid() || gid == getegid()) ++ return (1); ++ ++ if (ngroups == 0) ++ initialize_group_array (); ++ ++ /* Search through the list looking for GID. */ ++ for (i = 0; i < ngroups; i++) ++ if (gid == group_array[i]) ++ return (1); ++ ++ return (0); ++} + diff --git a/ash/patches/ash-times.patch b/ash/patches/ash-times.patch @@ -0,0 +1,42 @@ +diff -urN netbsd-sh/bltin/times.c ash-0.3.7.orig/bltin/times.c +--- netbsd-sh/bltin/times.c Thu Jan 1 01:00:00 1970 ++++ ash-0.3.7.orig/bltin/times.c Mon Apr 23 22:16:46 2001 +@@ -0,0 +1,30 @@ ++#ifdef _GNU_SOURCE ++/* ++ * Copyright (c) 1999 Herbert Xu <herbert@debian.org> ++ * This file contains code for the times builtin. ++ * $Id: times.c,v 1.4 2000/04/01 09:23:02 herbert Exp $ ++ */ ++ ++#include <stdio.h> ++#include <sys/times.h> ++#include <unistd.h> ++ ++#define main timescmd ++ ++int main() { ++ struct tms buf; ++ long int clk_tck = sysconf(_SC_CLK_TCK); ++ ++ times(&buf); ++ printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", ++ (int) (buf.tms_utime / clk_tck / 60), ++ ((double) buf.tms_utime) / clk_tck, ++ (int) (buf.tms_stime / clk_tck / 60), ++ ((double) buf.tms_stime) / clk_tck, ++ (int) (buf.tms_cutime / clk_tck / 60), ++ ((double) buf.tms_cutime) / clk_tck, ++ (int) (buf.tms_cstime / clk_tck / 60), ++ ((double) buf.tms_cstime) / clk_tck); ++ return 0; ++} ++#endif /* _GNU_SOURCE */ +diff -urN netbsd-sh/builtins.def ash-0.3.7.orig/builtins.def +--- netbsd-sh/builtins.def Mon Apr 10 13:02:58 2000 ++++ ash-0.3.7.orig/builtins.def Mon Apr 23 22:16:46 2001 +@@ -91,3 +93,4 @@ + aliascmd alias + ulimitcmd ulimit + testcmd test [ ++timescmd times