summaryrefslogtreecommitdiffstats
path: root/source/ap/ash/patches
diff options
context:
space:
mode:
author Patrick J Volkerding <volkerdi@slackware.com>2009-08-26 10:00:38 -0500
committer Eric Hameleers <alien@slackware.com>2018-05-31 22:41:17 +0200
commit5a12e7c134274dba706667107d10d231517d3e05 (patch)
tree55718d5acb710fde798d9f38d0bbaf594ed4b296 /source/ap/ash/patches
downloadcurrent-5a12e7c134274dba706667107d10d231517d3e05.tar.gz
current-5a12e7c134274dba706667107d10d231517d3e05.tar.xz
Slackware 13.0slackware-13.0
Wed Aug 26 10:00:38 CDT 2009 Slackware 13.0 x86_64 is released as stable! Thanks to everyone who helped make this release possible -- see the RELEASE_NOTES for the credits. The ISOs are off to the replicator. This time it will be a 6 CD-ROM 32-bit set and a dual-sided 32-bit/64-bit x86/x86_64 DVD. We're taking pre-orders now at store.slackware.com. Please consider picking up a copy to help support the project. Once again, thanks to the entire Slackware community for all the help testing and fixing things and offering suggestions during this development cycle. As always, have fun and enjoy! -P.
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