summaryrefslogtreecommitdiffstats
path: root/source/ap/ash/patches
diff options
context:
space:
mode:
Diffstat (limited to 'source/ap/ash/patches')
-rw-r--r--source/ap/ash/patches/ash-builtin.patch843
-rw-r--r--source/ap/ash/patches/ash-debian.patch702
-rw-r--r--source/ap/ash/patches/ash-echo.patch91
-rw-r--r--source/ap/ash/patches/ash-freebsd.patch60
-rw-r--r--source/ap/ash/patches/ash-getcwd.patch13
-rw-r--r--source/ap/ash/patches/ash-getopt.patch198
-rw-r--r--source/ap/ash/patches/ash-glob.patch445
-rw-r--r--source/ap/ash/patches/ash-hetio.patch559
-rw-r--r--source/ap/ash/patches/ash-jobs.patch108
-rw-r--r--source/ap/ash/patches/ash-kill.patch675
-rw-r--r--source/ap/ash/patches/ash-makefile.patch115
-rw-r--r--source/ap/ash/patches/ash-manpage.patch42
-rw-r--r--source/ap/ash/patches/ash-memout.patch333
-rw-r--r--source/ap/ash/patches/ash-misc.patch122
-rw-r--r--source/ap/ash/patches/ash-ppid.patch21
-rw-r--r--source/ap/ash/patches/ash-redir.patch463
-rw-r--r--source/ap/ash/patches/ash-setmode.patch510
-rw-r--r--source/ap/ash/patches/ash-sighup.patch18
-rw-r--r--source/ap/ash/patches/ash-syntax.patch270
-rw-r--r--source/ap/ash/patches/ash-test.patch588
-rw-r--r--source/ap/ash/patches/ash-times.patch42
21 files changed, 6218 insertions, 0 deletions
diff --git a/source/ap/ash/patches/ash-builtin.patch b/source/ap/ash/patches/ash-builtin.patch
new file mode 100644
index 000000000..b812e6375
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-debian.patch b/source/ap/ash/patches/ash-debian.patch
new file mode 100644
index 000000000..d3e79bfcd
--- /dev/null
+++ b/source/ap/ash/patches/ash-debian.patch
@@ -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/source/ap/ash/patches/ash-echo.patch b/source/ap/ash/patches/ash-echo.patch
new file mode 100644
index 000000000..89d93472f
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-freebsd.patch b/source/ap/ash/patches/ash-freebsd.patch
new file mode 100644
index 000000000..b0b114470
--- /dev/null
+++ b/source/ap/ash/patches/ash-freebsd.patch
@@ -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/source/ap/ash/patches/ash-getcwd.patch b/source/ap/ash/patches/ash-getcwd.patch
new file mode 100644
index 000000000..f98f487e3
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-getopt.patch b/source/ap/ash/patches/ash-getopt.patch
new file mode 100644
index 000000000..df88ba0df
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-glob.patch b/source/ap/ash/patches/ash-glob.patch
new file mode 100644
index 000000000..70013536e
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-hetio.patch b/source/ap/ash/patches/ash-hetio.patch
new file mode 100644
index 000000000..c416cde53
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-jobs.patch b/source/ap/ash/patches/ash-jobs.patch
new file mode 100644
index 000000000..9e89118f5
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-kill.patch b/source/ap/ash/patches/ash-kill.patch
new file mode 100644
index 000000000..f2972d94c
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-makefile.patch b/source/ap/ash/patches/ash-makefile.patch
new file mode 100644
index 000000000..c3b16a1f5
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-manpage.patch b/source/ap/ash/patches/ash-manpage.patch
new file mode 100644
index 000000000..458367e79
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-memout.patch b/source/ap/ash/patches/ash-memout.patch
new file mode 100644
index 000000000..1bfedadaa
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-misc.patch b/source/ap/ash/patches/ash-misc.patch
new file mode 100644
index 000000000..9845a2325
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-ppid.patch b/source/ap/ash/patches/ash-ppid.patch
new file mode 100644
index 000000000..954b509d4
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-redir.patch b/source/ap/ash/patches/ash-redir.patch
new file mode 100644
index 000000000..40cdbe9ac
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-setmode.patch b/source/ap/ash/patches/ash-setmode.patch
new file mode 100644
index 000000000..b9a26d9ca
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-sighup.patch b/source/ap/ash/patches/ash-sighup.patch
new file mode 100644
index 000000000..b4d1bc041
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-syntax.patch b/source/ap/ash/patches/ash-syntax.patch
new file mode 100644
index 000000000..43ce78660
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-test.patch b/source/ap/ash/patches/ash-test.patch
new file mode 100644
index 000000000..14c9f6802
--- /dev/null
+++ b/source/ap/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/source/ap/ash/patches/ash-times.patch b/source/ap/ash/patches/ash-times.patch
new file mode 100644
index 000000000..4c24f9a66
--- /dev/null
+++ b/source/ap/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