summaryrefslogtreecommitdiff
path: root/system/pdksh/patches
diff options
context:
space:
mode:
Diffstat (limited to 'system/pdksh/patches')
-rw-r--r--system/pdksh/patches/000_add_destdir.patch23
-rw-r--r--system/pdksh/patches/001_upstream-readonly-vars.patch172
-rw-r--r--system/pdksh/patches/010_OpenBSD-patches.patch1112
-rw-r--r--system/pdksh/patches/011_OpenBSD-alloc.patch199
-rw-r--r--system/pdksh/patches/020_PLD-patches.patch84
-rw-r--r--system/pdksh/patches/030_posh-eval.patch29
-rw-r--r--system/pdksh/patches/040_Debian-gcc-warnings.patch147
-rw-r--r--system/pdksh/patches/041_Debian-tilde-expansion.patch15
-rw-r--r--system/pdksh/patches/042_Debian-eaccess.patch140
-rw-r--r--system/pdksh/patches/043_Debian-siglist.patch23
-rw-r--r--system/pdksh/patches/044_Debian-emacs-crash.patch18
-rw-r--r--system/pdksh/patches/045_Debian-job-control.patch130
-rw-r--r--system/pdksh/patches/050_various-man-fixes.patch260
-rw-r--r--system/pdksh/patches/101_PLD-pdksh-EDITMODE.patch92
-rw-r--r--system/pdksh/patches/102_PLD-pdksh-ulimit-vmem.patch18
-rw-r--r--system/pdksh/patches/103_PLD-pdksh-unset.patch26
-rw-r--r--system/pdksh/patches/104_Debian-#415167-lack-of-dot-arguments.patch22
-rw-r--r--system/pdksh/patches/105_OpenBSD-heredoc-quote.patch53
-rw-r--r--system/pdksh/patches/106_Debian-man-hyphens.patch59
-rw-r--r--system/pdksh/patches/107_Debian-gcc-warnings2.patch23
-rw-r--r--system/pdksh/patches/108_Debian-sysconf_retval_check.patch41
-rw-r--r--system/pdksh/patches/109_mksh-delete_key.patch115
-rw-r--r--system/pdksh/patches/110_Debian-exit-negative-number.patch46
-rw-r--r--system/pdksh/patches/111_mksh-set-e.patch422
-rw-r--r--system/pdksh/patches/112_OpenBSD-test.patch58
-rw-r--r--system/pdksh/patches/113_OpenBSD-memory.patch148
-rw-r--r--system/pdksh/patches/114_OpenBSD-let-crash.patch37
-rw-r--r--system/pdksh/patches/115_OpenBSD-echo-posix.patch140
-rw-r--r--system/pdksh/patches/116_OpenBSD-history.patch47
-rw-r--r--system/pdksh/patches/117_Debian-test.patch78
30 files changed, 3777 insertions, 0 deletions
diff --git a/system/pdksh/patches/000_add_destdir.patch b/system/pdksh/patches/000_add_destdir.patch
new file mode 100644
index 0000000000..fba38ea1b3
--- /dev/null
+++ b/system/pdksh/patches/000_add_destdir.patch
@@ -0,0 +1,23 @@
+diff -Nur pdksh-5.2.14.orig/Makefile.in pdksh-5.2.14/Makefile.in
+--- pdksh-5.2.14.orig/Makefile.in 1999-07-13 12:06:53.000000000 -0500
++++ pdksh-5.2.14/Makefile.in 2009-09-26 19:09:46.183509569 -0500
+@@ -80,8 +80,8 @@
+ $(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) $(CFLAGS) $<
+
+ install: installdirs all
+- $(INSTALL_PROGRAM) $(SHELL_PROG)$(exe_suffix) $(bindir)/`echo $(SHELL_PROG)|sed '$(transform)'`$(exe_suffix)
+- -$(INSTALL_DATA) $(SHELL_PROG).1 $(mandir)/`echo $(SHELL_PROG)|sed '$(transform)'`.$(manext)
++ $(INSTALL_PROGRAM) $(SHELL_PROG)$(exe_suffix) $(DESTDIR)/$(bindir)/`echo $(SHELL_PROG)|sed '$(transform)'`$(exe_suffix)
++ -$(INSTALL_DATA) $(SHELL_PROG).1 $(DESTDIR)/$(mandir)/`echo $(SHELL_PROG)|sed '$(transform)'`.$(manext)
+ -@prog=$(bindir)/`echo $(SHELL_PROG)|sed '$(transform)'`$(exe_suffix);\
+ test -f /etc/shells \
+ && (grep "^$$prog\$$" /etc/shells > /dev/null \
+@@ -90,7 +90,7 @@
+ you should add it if you want to set your shell to $(SHELL_PROG)")
+
+ installdirs:
+- $(srcdir)/mkinstalldirs $(bindir) $(mandir)
++ $(srcdir)/mkinstalldirs $(DESTDIR)/$(bindir) $(DESTDIR)/$(mandir)
+
+ uninstall:
+ rm -f $(bindir)/`echo $(SHELL_PROG)|sed '$(transform)'`$(exe_suffix)
diff --git a/system/pdksh/patches/001_upstream-readonly-vars.patch b/system/pdksh/patches/001_upstream-readonly-vars.patch
new file mode 100644
index 0000000000..616a5102d9
--- /dev/null
+++ b/system/pdksh/patches/001_upstream-readonly-vars.patch
@@ -0,0 +1,172 @@
+ * Applied patch from upstream ftp site to fix problem with readonly
+ variables (closes: #57727).
+Index: pdksh-5.2.14/jobs.c
+===================================================================
+--- pdksh-5.2.14.orig/jobs.c 2008-04-15 20:47:52.000000000 +0200
++++ pdksh-5.2.14/jobs.c 2008-04-15 20:48:46.000000000 +0200
+@@ -219,8 +219,7 @@
+ static void check_job ARGS((Job *j));
+ static void put_job ARGS((Job *j, int where));
+ static void remove_job ARGS((Job *j, const char *where));
+-static void kill_job ARGS((Job *j));
+-static void fill_command ARGS((char *c, int len, struct op *t));
++static int kill_job ARGS((Job *j, int sig));
+
+ /* initialize job control */
+ void
+@@ -294,10 +293,17 @@
+ && procpid == kshpid)))))
+ {
+ killed = 1;
+- killpg(j->pgrp, SIGHUP);
++ if (j->pgrp == 0)
++ kill_job(j, SIGHUP);
++ else
++ killpg(j->pgrp, SIGHUP);
+ #ifdef JOBS
+- if (j->state == PSTOPPED)
+- killpg(j->pgrp, SIGCONT);
++ if (j->state == PSTOPPED) {
++ if (j->pgrp == 0)
++ kill_job(j, SIGCONT);
++ else
++ killpg(j->pgrp, SIGCONT);
++ }
+ #endif /* JOBS */
+ }
+ }
+@@ -497,7 +503,7 @@
+ put_job(j, PJ_PAST_STOPPED);
+ }
+
+- fill_command(p->command, sizeof(p->command), t);
++ snptreef(p->command, sizeof(p->command), "%T", t);
+
+ /* create child process */
+ forksleep = 1;
+@@ -508,7 +514,7 @@
+ forksleep <<= 1;
+ }
+ if (i < 0) {
+- kill_job(j);
++ kill_job(j, SIGKILL);
+ remove_job(j, "fork failed");
+ #ifdef NEED_PGRP_SYNC
+ if (j_sync_open) {
+@@ -823,11 +829,10 @@
+ }
+
+ if (j->pgrp == 0) { /* started when !Flag(FMONITOR) */
+- for (p=j->proc_list; p != (Proc *) 0; p = p->next)
+- if (kill(p->pid, sig) < 0) {
+- bi_errorf("%s: %s", cp, strerror(errno));
+- rv = 1;
+- }
++ if (kill_job(j, sig) < 0) {
++ bi_errorf("%s: %s", cp, strerror(errno));
++ rv = 1;
++ }
+ } else {
+ #ifdef JOBS
+ if (j->state == PSTOPPED && (sig == SIGTERM || sig == SIGHUP))
+@@ -1825,50 +1830,17 @@
+ *
+ * If jobs are compiled in then this routine expects sigchld to be blocked.
+ */
+-static void
+-kill_job(j)
++static int
++kill_job(j, sig)
+ Job *j;
++ int sig;
+ {
+ Proc *p;
++ int rval = 0;
+
+ for (p = j->proc_list; p != (Proc *) 0; p = p->next)
+ if (p->pid != 0)
+- (void) kill(p->pid, SIGKILL);
+-}
+-
+-/* put a more useful name on a process than snptreef does (in certain cases) */
+-static void
+-fill_command(c, len, t)
+- char *c;
+- int len;
+- struct op *t;
+-{
+- int alen;
+- char **ap;
+-
+- if (t->type == TEXEC || t->type == TCOM) {
+- /* Causes problems when set -u is in effect, can also
+- cause problems when array indices evaluated (may have
+- side effects, eg, assignment, incr, etc.)
+- if (t->type == TCOM)
+- ap = eval(t->args, DOBLANK|DONTRUNCOMMAND);
+- else
+- */
+- ap = t->args;
+- --len; /* save room for the null */
+- while (len > 0 && *ap != (char *) 0) {
+- alen = strlen(*ap);
+- if (alen > len)
+- alen = len;
+- memcpy(c, *ap, alen);
+- c += alen;
+- len -= alen;
+- if (len > 0) {
+- *c++ = ' '; len--;
+- }
+- ap++;
+- }
+- *c = '\0';
+- } else
+- snptreef(c, len, "%T", t);
++ if (kill(p->pid, sig) < 0)
++ rval = -1;
++ return rval;
+ }
+Index: pdksh-5.2.14/shf.c
+===================================================================
+--- pdksh-5.2.14.orig/shf.c 2008-04-15 20:47:52.000000000 +0200
++++ pdksh-5.2.14/shf.c 2008-04-15 20:48:46.000000000 +0200
+@@ -355,7 +355,6 @@
+ shf->rp = nbuf + (shf->rp - shf->buf);
+ shf->wp = nbuf + (shf->wp - shf->buf);
+ shf->rbsize += shf->wbsize;
+- shf->wbsize += shf->wbsize;
+ shf->wnleft += shf->wbsize;
+ shf->wbsize *= 2;
+ shf->buf = nbuf;
+Index: pdksh-5.2.14/var.c
+===================================================================
+--- pdksh-5.2.14.orig/var.c 2008-04-15 20:47:52.000000000 +0200
++++ pdksh-5.2.14/var.c 2008-04-15 20:48:46.000000000 +0200
+@@ -353,7 +353,9 @@
+ const char *s;
+ int error_ok;
+ {
+- if (vq->flag & RDONLY) {
++ int no_ro_check = error_ok & 0x4;
++ error_ok &= ~0x4;
++ if ((vq->flag & RDONLY) && !no_ro_check) {
+ warningf(TRUE, "%s: is read only", vq->name);
+ if (!error_ok)
+ errorf(null);
+@@ -715,13 +717,13 @@
+ if (val != NULL) {
+ if (vp->flag&INTEGER) {
+ /* do not zero base before assignment */
+- setstr(vp, val, KSH_UNWIND_ERROR);
++ setstr(vp, val, KSH_UNWIND_ERROR | 0x4);
+ /* Done after assignment to override default */
+ if (base > 0)
+ vp->type = base;
+ } else
+ /* setstr can't fail (readonly check already done) */
+- setstr(vp, val, KSH_RETURN_ERROR);
++ setstr(vp, val, KSH_RETURN_ERROR | 0x4);
+ }
+
+ /* only x[0] is ever exported, so use vpbase */
diff --git a/system/pdksh/patches/010_OpenBSD-patches.patch b/system/pdksh/patches/010_OpenBSD-patches.patch
new file mode 100644
index 0000000000..ebb3c9e64c
--- /dev/null
+++ b/system/pdksh/patches/010_OpenBSD-patches.patch
@@ -0,0 +1,1112 @@
+ * Applied some patches from OpenBSD:
+ + Use mkstemp to create temporary files
+ + Kill -s now works
+ + Escapes special characters in tab completitions
+ + Introduce FSH flag, which is set when the shell is called as `sh'.
+ + tree.c: Fix three off-by-one errors.
+ + c_sh.c: don't set close-on-exec flag on file descriptors in FSH mode
+ (closes: #154540). Documented the change in ksh(1).
+ + history.c: Compare the return from mmap with MAP_FAILED, do not cast it
+ to int and compare with -1.
+ + main.c: set edit mode to emacs by default, may be overridden by the
+ environment or the user. Also, we want tab completion in vi by default.
+ + misc.c: use strtol() in getn().
+ + emacs.c:
+ - bind TAB (^I) to complete-list by default
+ - complete-list first completes; if that does not work, it lists
+ - fix a memleak in do_complete()
+ + edit.c:
+ - completion now works after '=' (dd), and ':' (ssh) and ` (backtick)
+ - add '#' to the list of escaped characters during vi/emacs filename
+ completion
+
+ + exec.c: Found and fixed yet another problem with `set -e' scripts
+ (see a changelog entry for 5.2.14-3), which caused `dpkg-buildpackage -B'
+ to fail on systems where /bin/sh is ksh.
+
+ + c_sh.c: Make `set' command return 0 always, not only in the POSIX mode.
+ According to Jeff Sheinberg <jeffsh@localnet.com>, this new behaviour
+ is more compatible with SUSv2 standard and other shells (esp. ksh93)
+ (closes: #118476). Documented the change in ksh(1) man page.
+
+ + c_test.c: The special case code for "test -x" over NFS was
+ incorrect. The right thing to do is to try access(2) first
+ (since that occurs on the NFS server side) and only check for the
+ absence of an execute bit when access(2) succeeds.
+ + edit.c: in word location, fix forward scanning so it correctly
+ account for any escaped char and not only spaces. for "foo
+ (bar.a)" and "foo (bar a)", cd foo\ \(bar.<tab> will correctly
+ expand to foo\ \(bar.a\).
+
+ + vi.c: Buffers are not strings so use memcpy(), not strlcpy() to copy
+ them. Also add some further bounds checks in the name of paranoia.
+ + exec.c: Unbreak parameter assignment when calling bourne style
+ functions.
+ + exec.c: For the >& and <& operators, add a check for "dup from" ==
+ "dup to" and just return success if they are the same. Fixes the
+ "ls 2>&2" problem.
+ + eval.c, exec.c, io.c, jobs.c: If "from fd" == "to fd" don't call
+ dup2() or close "from fd".
+
+Index: pdksh-5.2.14/c_ksh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_ksh.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/c_ksh.c 2009-09-17 00:32:08.000000000 +0200
+@@ -1208,6 +1208,7 @@
+ builtin_opt.optarg);
+ return 1;
+ }
++ break;
+ case '?':
+ return 1;
+ }
+Index: pdksh-5.2.14/edit.c
+===================================================================
+--- pdksh-5.2.14.orig/edit.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/edit.c 2009-09-17 00:32:08.000000000 +0200
+@@ -15,6 +15,9 @@
+ # include <sys/stream.h> /* needed for <sys/ptem.h> */
+ # include <sys/ptem.h> /* needed for struct winsize */
+ #endif /* OS_SCO */
++#ifdef DEBIAN
++#include <sys/ioctl.h>
++#endif /* DEBIAN */
+ #include <ctype.h>
+ #include "ksh_stat.h"
+
+@@ -552,7 +555,11 @@
+ {
+ char *toglob;
+ char **words;
++#ifndef DEBIAN
+ int nwords;
++#else /* DEBIAN */ /* patch from OpenBSD */
++ int nwords, i, idx, escaping;
++#endif /* DEBIAN */
+ XPtrV w;
+ struct source *s, *sold;
+
+@@ -561,6 +568,22 @@
+
+ toglob = add_glob(str, slen);
+
++#ifdef DEBIAN /* patch from OpenBSD */
++ /* remove all escaping backward slashes */
++ escaping = 0;
++ for(i = 0, idx = 0; toglob[i]; i++) {
++ if (toglob[i] == '\\' && !escaping) {
++ escaping = 1;
++ continue;
++ }
++
++ toglob[idx] = toglob[i];
++ idx++;
++ if (escaping) escaping = 0;
++ }
++ toglob[idx] = '\0';
++
++#endif /* DEBIAN */
+ /*
+ * Convert "foo*" (toglob) to an array of strings (words)
+ */
+@@ -722,7 +745,12 @@
+ return nwords;
+ }
+
++#ifndef DEBIAN
+ #define IS_WORDC(c) !(ctype(c, C_LEX1) || (c) == '\'' || (c) == '"')
++#else /* patch from OpenBSD */
++#define IS_WORDC(c) !( ctype(c, C_LEX1) || (c) == '\'' || (c) == '"' \
++ || (c) == '`' || (c) == '=' || (c) == ':' )
++#endif
+
+ static int
+ x_locate_word(buf, buflen, pos, startp, is_commandp)
+@@ -747,11 +775,23 @@
+ /* Keep going backwards to start of word (has effect of allowing
+ * one blank after the end of a word)
+ */
++#ifndef DEBIAN
+ for (; start > 0 && IS_WORDC(buf[start - 1]); start--)
++#else /* DEBIAN */ /* patch from OpenBSD */
++ for (; (start > 0 && IS_WORDC(buf[start - 1]))
++ || (start > 1 && buf[start-2] == '\\'); start--)
++#endif /* DEBIAN */
+ ;
+ /* Go forwards to end of word */
++#ifndef DEBIAN
+ for (end = start; end < buflen && IS_WORDC(buf[end]); end++)
+ ;
++#else /* DEBIAN */ /* patch from OpenBSD */
++ for (end = start; end < buflen && IS_WORDC(buf[end]); end++) {
++ if (buf[end] == '\\' && (end+1) < buflen)
++ end++;
++ }
++#endif /* DEBIAN */
+
+ if (is_commandp) {
+ int iscmd;
+@@ -759,7 +799,11 @@
+ /* Figure out if this is a command */
+ for (p = start - 1; p >= 0 && isspace(buf[p]); p--)
+ ;
++#ifndef DEBIAN
+ iscmd = p < 0 || strchr(";|&()", buf[p]);
++#else /* DEBIAN */ /* patch from OpenBSD */
++ iscmd = p < 0 || strchr(";|&()`", buf[p]);
++#endif
+ if (iscmd) {
+ /* If command has a /, path, etc. is not searched;
+ * only current directory is searched, which is just
+@@ -961,6 +1005,9 @@
+ {
+ const char *sp, *p;
+ char *xp;
++#ifdef DEBIAN /* patch from OpenBSD */
++ int staterr;
++#endif /* DEBIAN */
+ int pathlen;
+ int patlen;
+ int oldsize, newsize, i, j;
+@@ -995,13 +1042,23 @@
+ memcpy(xp, pat, patlen);
+
+ oldsize = XPsize(*wp);
++#ifndef DEBIAN
+ glob_str(Xstring(xs, xp), wp, 0);
++#else /* DEBIAN */ /* patch from OpenBSD */
++ glob_str(Xstring(xs, xp), wp, 1); /* mark dirs */
++#endif
+ newsize = XPsize(*wp);
+
+ /* Check that each match is executable... */
+ words = (char **) XPptrv(*wp);
+ for (i = j = oldsize; i < newsize; i++) {
++#ifndef DEBIAN
+ if (search_access(words[i], X_OK, (int *) 0) >= 0) {
++#else /* DEBIAN */ /* patch from OpenBSD */
++ staterr = 0;
++ if ((search_access(words[i], X_OK, &staterr) >= 0)
++ || (staterr == EISDIR)) {
++#endif
+ words[j] = words[i];
+ if (!(flags & XCF_FULLPATH))
+ memmove(words[j], words[j] + pathlen,
+@@ -1018,4 +1075,42 @@
+ Xfree(xs, xp);
+ }
+
++#ifdef DEBIAN /* patch from OpenBSD */
++/*
++ * if argument string contains any special characters, they will
++ * be escaped and the result will be put into edit buffer by
++ * keybinding-specific function
++ */
++int
++x_escape(s, len, putbuf_func)
++ const char *s;
++ size_t len;
++ int putbuf_func ARGS((const char *s, size_t len));
++{
++ size_t add, wlen;
++ const char *ifs = str_val(local("IFS", 0));
++ int rval=0;
++
++ for (add = 0, wlen = len; wlen - add > 0; add++) {
++ if (strchr("\\$(){}*&;#|<>\"'`", s[add]) || strchr(ifs, s[add])) {
++ if (putbuf_func(s, add) != 0) {
++ rval = -1;
++ break;
++ }
++
++ putbuf_func("\\", 1);
++ putbuf_func(&s[add], 1);
++
++ add++;
++ wlen -= add;
++ s += add;
++ add = -1; /* after the increment it will go to 0 */
++ }
++ }
++ if (wlen > 0 && rval == 0)
++ rval = putbuf_func(s, wlen);
++
++ return (rval);
++}
++#endif /* DEBIAN */
+ #endif /* EDIT */
+Index: pdksh-5.2.14/edit.h
+===================================================================
+--- pdksh-5.2.14.orig/edit.h 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/edit.h 2009-09-17 00:32:08.000000000 +0200
+@@ -55,6 +55,9 @@
+ int x_longest_prefix ARGS((int nwords, char *const *words));
+ int x_basename ARGS((const char *s, const char *se));
+ void x_free_words ARGS((int nwords, char **words));
++#ifdef DEBIAN /* patch from OpenBSD */
++int x_escape ARGS((const char *, size_t, int (*)(const char *s, size_t len)));
++#endif /* DEBIAN */
+ /* emacs.c */
+ int x_emacs ARGS((char *buf, size_t len));
+ void x_init_emacs ARGS((void));
+Index: pdksh-5.2.14/emacs.c
+===================================================================
+--- pdksh-5.2.14.orig/emacs.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/emacs.c 2009-09-17 00:32:08.000000000 +0200
+@@ -138,6 +138,10 @@
+ static int x_e_getc ARGS((void));
+ static void x_e_putc ARGS((int c));
+ static void x_e_puts ARGS((const char *s));
++#ifdef DEBIAN /* patch from OpenBSD */
++static int x_comment ARGS((int c));
++static int x_emacs_putbuf ARGS((const char *s, size_t len));
++#endif /* DEBIAN */
+ static int x_fold_case ARGS((int c));
+ static char *x_lastcp ARGS((void));
+ static void do_complete ARGS((int flags, Comp_type type));
+@@ -269,6 +273,9 @@
+ { XFUNC_transpose, 0, CTRL('T') },
+ #endif
+ { XFUNC_complete, 1, CTRL('[') },
++#ifdef DEBIAN /* patch from OpenBSD */
++ { XFUNC_comp_list, 0, CTRL('I') },
++#endif /* DEBIAN */
+ { XFUNC_comp_list, 1, '=' },
+ { XFUNC_enumerate, 1, '?' },
+ { XFUNC_expand, 1, '*' },
+@@ -313,6 +320,9 @@
+ * entries.
+ */
+ { XFUNC_meta2, 1, '[' },
++#ifdef DEBIAN /* patch from OpenBSD */
++ { XFUNC_meta2, 1, 'O' },
++#endif /* DEBIAN */
+ { XFUNC_prev_com, 2, 'A' },
+ { XFUNC_next_com, 2, 'B' },
+ { XFUNC_mv_forw, 2, 'C' },
+@@ -468,6 +478,23 @@
+ return 0;
+ }
+
++#ifdef DEBIAN /* patch from OpenBSD */
++/*
++ * this is used for x_escape() in do_complete()
++ */
++static int
++x_emacs_putbuf(s, len)
++ const char *s;
++ size_t len;
++{
++ int rval;
++
++ if ((rval = x_do_ins(s, len)) != 0)
++ return (rval);
++ return (rval);
++}
++
++#endif /* DEBIAN */
+ static int
+ x_del_back(c)
+ int c;
+@@ -1485,7 +1512,11 @@
+ for (j = 0; j < X_TABSZ; j++)
+ x_tab[i][j] = XFUNC_error;
+ for (i = 0; i < NELEM(x_defbindings); i++)
++#ifndef DEBIAN
+ x_tab[x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char]
++#else /* DEBIAN */ /* patch from OpenBSD */
++ x_tab[(unsigned char)x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char]
++#endif /* DEBIAN */
+ = x_defbindings[i].xdb_func;
+
+ x_atab = (char *(*)[X_TABSZ]) alloc(sizeofN(*x_atab, X_NTABS), AEDIT);
+@@ -1754,6 +1785,7 @@
+ int flags; /* XCF_{COMMAND,FILE,COMMAND_FILE} */
+ Comp_type type;
+ {
++#ifndef DEBIAN
+ char **words;
+ int nwords = 0;
+ int start, end;
+@@ -1828,8 +1860,13 @@
+ if (nlen > 0) {
+ x_goto(xbuf + start);
+ x_delete(end - start, FALSE);
++#ifndef DEBIAN
+ words[0][nlen] = '\0';
+ x_ins(words[0]);
++#else /* DEBIAN */ /* patch from OpenBSD */
++ x_escape(words[0], nlen, x_emacs_putbuf);
++ x_adjust();
++#endif /* DEBIAN */
+ /* If single match is not a directory, add a
+ * space to the end...
+ */
+@@ -1841,6 +1878,54 @@
+ }
+ break;
+ }
++#else /* patch from OpenBSD */
++ char **words;
++ int nwords;
++ int start, end, nlen, olen;
++ int is_command;
++ int completed = 0;
++
++ nwords = x_cf_glob(flags, xbuf, xep - xbuf, xcp - xbuf,
++ &start, &end, &words, &is_command);
++ /* no match */
++ if (nwords == 0) {
++ x_e_putc(BEL);
++ return;
++ }
++
++ if (type == CT_LIST) {
++ x_print_expansions(nwords, words, is_command);
++ x_redraw(0);
++ x_free_words(nwords, words);
++ return;
++ }
++
++ olen = end - start;
++ nlen = x_longest_prefix(nwords, words);
++ /* complete */
++ if (nlen > olen) {
++ x_goto(xbuf + start);
++ x_delete(olen, FALSE);
++ x_escape(words[0], nlen, x_emacs_putbuf);
++ x_adjust();
++ completed = 1;
++ }
++ /* add space if single non-dir match */
++ if ((nwords == 1) && (!ISDIRSEP(words[0][nlen - 1]))) {
++ x_ins(space);
++ completed = 1;
++ }
++
++ if (type == CT_COMPLIST && !completed) {
++ x_print_expansions(nwords, words, is_command);
++ completed = 1;
++ }
++
++ if (completed)
++ x_redraw(0);
++
++ x_free_words(nwords, words);
++#endif /* DEBIAN */
+ }
+
+ /* NAME:
+Index: pdksh-5.2.14/io.c
+===================================================================
+--- pdksh-5.2.14.orig/io.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/io.c 2009-09-17 00:32:08.000000000 +0200
+@@ -318,7 +318,7 @@
+ shf_flush(&shf_iob[fd]);
+ if (ofd < 0) /* original fd closed */
+ close(fd);
+- else {
++ else if (fd != ofd) {
+ ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
+ close(ofd);
+ }
+@@ -502,7 +502,9 @@
+ Temp_type type;
+ struct temp **tlist;
+ {
++#ifndef DEBIAN
+ static unsigned int inc;
++#endif
+ struct temp *tp;
+ int len;
+ int fd;
+@@ -516,6 +518,14 @@
+ tp->name = path = (char *) &tp[1];
+ tp->shf = (struct shf *) 0;
+ tp->type = type;
++#ifdef DEBIAN /* based on patch from OpenBSD */
++ shf_snprintf(path, len, "%s/kshXXXXXX", dir);
++ fd = mkstemp(path);
++ if (fd >= 0)
++ tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
++ if (fd >= 0)
++ fchmod(fd, 0600);
++#else /* DEBIAN */
+ while (1) {
+ /* Note that temp files need to fit 8.3 DOS limits */
+ shf_snprintf(path, len, "%s/sh%05u.%03x",
+@@ -542,6 +552,7 @@
+ break;
+ }
+ tp->next = NULL;
++#endif /* DEBIAN */
+ tp->pid = procpid;
+
+ tp->next = *tlist;
+Index: pdksh-5.2.14/vi.c
+===================================================================
+--- pdksh-5.2.14.orig/vi.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/vi.c 2009-09-17 00:32:08.000000000 +0200
+@@ -63,6 +63,9 @@
+ static void vi_pprompt ARGS((int full));
+ static void vi_error ARGS((void));
+ static void vi_macro_reset ARGS((void));
++#ifdef DEBIAN /* patch from OpenBSD */
++static int x_vi_putbuf ARGS((const char *s, size_t len));
++#endif /* DEBIAN */
+
+ #define C_ 0x1 /* a valid command that isn't a M_, E_, U_ */
+ #define M_ 0x2 /* movement command (h, l, etc.) */
+@@ -235,7 +238,7 @@
+
+ x_putc('\r'); x_putc('\n'); x_flush();
+
+- if (c == -1)
++ if (c == -1 || len <= es->linelen)
+ return -1;
+
+ if (es->cbuf != buf)
+@@ -459,15 +462,22 @@
+ else {
+ locpat[srchlen++] = ch;
+ if ((ch & 0x80) && Flag(FVISHOW8)) {
++ if (es->linelen + 2 > es->cbufsize)
++ vi_error();
+ es->cbuf[es->linelen++] = 'M';
+ es->cbuf[es->linelen++] = '-';
+ ch &= 0x7f;
+ }
+ if (ch < ' ' || ch == 0x7f) {
++ if (es->linelen + 2 > es->cbufsize)
++ vi_error();
+ es->cbuf[es->linelen++] = '^';
+ es->cbuf[es->linelen++] = ch ^ '@';
+- } else
++ } else {
++ if (es->linelen >= es->cbufsize)
++ vi_error();
+ es->cbuf[es->linelen++] = ch;
++ }
+ es->cursor = es->linelen;
+ refresh(0);
+ }
+@@ -690,7 +700,7 @@
+ /* End nonstandard vi commands } */
+
+ default:
+- if (es->linelen == es->cbufsize - 1)
++ if (es->linelen >= es->cbufsize - 1)
+ return -1;
+ ibuf[inslen++] = ch;
+ if (insert == INSERT) {
+@@ -1403,7 +1413,7 @@
+ new = (struct edstate *)alloc(sizeof(struct edstate), APERM);
+ new->cbuf = alloc(old->cbufsize, APERM);
+ new->cbufsize = old->cbufsize;
+- strcpy(new->cbuf, old->cbuf);
++ memcpy(new->cbuf, old->cbuf, old->linelen);
+ new->linelen = old->linelen;
+ new->cursor = old->cursor;
+ new->winleft = old->winleft;
+@@ -1414,7 +1424,7 @@
+ restore_edstate(new, old)
+ struct edstate *old, *new;
+ {
+- strncpy(new->cbuf, old->cbuf, old->linelen);
++ memcpy(new->cbuf, old->cbuf, old->linelen);
+ new->linelen = old->linelen;
+ new->cursor = old->cursor;
+ new->winleft = old->winleft;
+@@ -1470,6 +1480,19 @@
+ holdlen = 0;
+ }
+
++#ifdef DEBIAN /* patch from OpenBSD */
++/*
++ * this is used for calling x_escape() in complete_word()
++ */
++static int
++x_vi_putbuf(s, len)
++ const char *s;
++ size_t len;
++{
++ return putbuf(s, len, 0);
++}
++
++#endif /* DEBIAN */
+ static int
+ putbuf(buf, len, repl)
+ const char *buf;
+@@ -1965,7 +1988,11 @@
+ del_range(start, end);
+ es->cursor = start;
+ for (i = 0; i < nwords; ) {
++#ifndef DEBIAN
+ if (putbuf(words[i], (int) strlen(words[i]), 0) != 0) {
++#else /* DEBIAN */ /* patch from OpenBSD */
++ if (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 0) {
++#endif /* DEBIAN */
+ rval = -1;
+ break;
+ }
+@@ -2068,9 +2095,18 @@
+ buf = save_edstate(es);
+ del_range(start, end);
+ es->cursor = start;
++#ifndef DEBIAN
+ if (putbuf(match, match_len, 0) != 0)
+ rval = -1;
+ else if (is_unique) {
++#else /* DEBIAN */ /* patch from OpenBSD */
++
++ /* escape all shell-sensitive characters and put the result into
++ * command buffer */
++ rval = x_escape(match, match_len, x_vi_putbuf);
++
++ if (rval == 0 && is_unique) {
++#endif /* DEBIAN */
+ /* If exact match, don't undo. Allows directory completions
+ * to be used (ie, complete the next portion of the path).
+ */
+Index: pdksh-5.2.14/c_sh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_sh.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/c_sh.c 2009-09-17 00:32:08.000000000 +0200
+@@ -643,6 +643,7 @@
+ for (wp = l->argv; (*wp++ = *owp++) != NULL; )
+ ;
+ }
++#ifndef DEBIAN
+ /* POSIX says set exit status is 0, but old scripts that use
+ * getopt(1), use the construct: set -- `getopt ab:c "$@"`
+ * which assumes the exit value set will be that of the ``
+@@ -650,6 +651,12 @@
+ * if there are no command substitutions).
+ */
+ return Flag(FPOSIX) ? 0 : subst_exstat;
++#else
++ /* On Debian we always want set to return 0 like ksh93 does.
++ * See: Bug#118476.
++ */
++ return 0;
++#endif /* DEBIAN */
+ }
+
+ int
+@@ -844,7 +851,7 @@
+ * keeps them open).
+ */
+ #ifdef KSH
+- if (i > 2 && e->savefd[i])
++ if (!Flag(FSH) &&i > 2 && e->savefd[i])
+ fd_clexec(i);
+ #endif /* KSH */
+ }
+Index: pdksh-5.2.14/exec.c
+===================================================================
+--- pdksh-5.2.14.orig/exec.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/exec.c 2009-09-17 00:32:31.000000000 +0200
+@@ -228,8 +228,10 @@
+ e->savefd[1] = savefd(1, 0);
+
+ openpipe(pv);
+- ksh_dup2(pv[0], 0, FALSE);
+- close(pv[0]);
++ if (pv[0] != 0) {
++ ksh_dup2(pv[0], 0, FALSE);
++ close(pv[0]);
++ }
+ coproc.write = pv[1];
+ coproc.job = (void *) 0;
+
+@@ -448,18 +450,19 @@
+ int volatile flags;
+ {
+ int i;
+- int rv = 0;
++ volatile int rv = 0;
+ register char *cp;
+ register char **lastp;
+ static struct op texec; /* Must be static (XXX but why?) */
+ int type_flags;
+ int keepasn_ok;
+ int fcflags = FC_BI|FC_FUNC|FC_PATH;
++ int bourne_function_call = 0;
+
+ #ifdef KSH
+ /* snag the last argument for $_ XXX not the same as at&t ksh,
+ * which only seems to set $_ after a newline (but not in
+- * functions/dot scripts, but in interactive and scipt) -
++ * functions/dot scripts, but in interactive and script) -
+ * perhaps save last arg here and set it in shell()?.
+ */
+ if (Flag(FTALKING) && *(lastp = ap)) {
+@@ -544,9 +547,10 @@
+ newblock();
+ /* ksh functions don't keep assignments, POSIX functions do. */
+ if (keepasn_ok && tp && tp->type == CFUNC
+- && !(tp->flag & FKSH))
+- type_flags = 0;
+- else
++ && !(tp->flag & FKSH)) {
++ bourne_function_call = 1;
++ type_flags = 0;
++ } else
+ type_flags = LOCAL|LOCAL_COPY|EXPORT;
+ }
+ if (Flag(FEXPORT))
+@@ -563,6 +567,8 @@
+ shf_flush(shl_out);
+ }
+ typeset(cp, type_flags, 0, 0, 0);
++ if (bourne_function_call && !(type_flags & EXPORT))
++ typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
+ }
+
+ if ((cp = *ap) == NULL) {
+@@ -710,10 +716,12 @@
+ }
+
+ #ifdef KSH
+- /* set $_ to program's full path */
+- /* setstr() can't fail here */
+- setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), tp->val.s,
+- KSH_RETURN_ERROR);
++ if (!Flag(FSH)) {
++ /* set $_ to program's full path */
++ /* setstr() can't fail here */
++ setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), tp->val.s,
++ KSH_RETURN_ERROR);
++ }
+ #endif /* KSH */
+
+ if (flags&XEXEC) {
+@@ -1351,6 +1359,8 @@
+ snptreef((char *) 0, 32, "%R", &iotmp), emsg);
+ return -1;
+ }
++ if (u == iop->unit)
++ return 0; /* "dup from" == "dup to" */
+ break;
+ }
+ }
+@@ -1375,13 +1385,20 @@
+ return -1;
+ }
+ /* Do not save if it has already been redirected (i.e. "cat >x >y"). */
+- if (e->savefd[iop->unit] == 0)
+- /* c_exec() assumes e->savefd[fd] set for any redirections.
+- * Ask savefd() not to close iop->unit - allows error messages
+- * to be seen if iop->unit is 2; also means we can't lose
+- * the fd (eg, both dup2 below and dup2 in restfd() failing).
+- */
+- e->savefd[iop->unit] = savefd(iop->unit, 1);
++ if (e->savefd[iop->unit] == 0) {
++#ifdef DEBIAN /* patch from OpenBSD */
++ /* If these are the same, it means unit was previously closed */
++ if (u == iop->unit)
++ e->savefd[iop->unit] = -1;
++ else
++#endif
++ /* c_exec() assumes e->savefd[fd] set for any redirections.
++ * Ask savefd() not to close iop->unit - allows error messages
++ * to be seen if iop->unit is 2; also means we can't lose
++ * the fd (eg, both dup2 below and dup2 in restfd() failing).
++ */
++ e->savefd[iop->unit] = savefd(iop->unit, 1);
++ }
+
+ if (do_close)
+ close(iop->unit);
+Index: pdksh-5.2.14/history.c
+===================================================================
+--- pdksh-5.2.14.orig/history.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/history.c 2009-09-17 00:32:08.000000000 +0200
+@@ -858,8 +858,8 @@
+ /*
+ * check on its validity
+ */
+- if ((int)base == -1 || *base != HMAGIC1 || base[1] != HMAGIC2) {
+- if ((int)base != -1)
++ if (base == MAP_FAILED || *base != HMAGIC1 || base[1] != HMAGIC2) {
++ if (base != MAP_FAILED)
+ munmap((caddr_t)base, hsize);
+ hist_finish();
+ unlink(hname);
+@@ -893,7 +893,7 @@
+ static int
+ hist_count_lines(base, bytes)
+ register unsigned char *base;
+- register int bytes;
++ int bytes;
+ {
+ State state = shdr;
+ register lines = 0;
+@@ -1015,8 +1015,8 @@
+ register int bytes;
+ {
+ State state;
+- int lno;
+- unsigned char *line;
++ int lno = -1;
++ unsigned char *line = NULL;
+
+ for (state = shdr; bytes-- > 0; base++) {
+ switch (state) {
+@@ -1105,7 +1105,7 @@
+ /* someone has added some lines */
+ bytes = sizenow - hsize;
+ base = (unsigned char *)mmap(0, sizenow, PROT_READ, MAP_FLAGS, histfd, 0);
+- if ((int)base == -1)
++ if (base == MAP_FAILED)
+ goto bad;
+ new = base + hsize;
+ if (*new != COMMAND) {
+Index: pdksh-5.2.14/jobs.c
+===================================================================
+--- pdksh-5.2.14.orig/jobs.c 2009-09-17 00:32:06.000000000 +0200
++++ pdksh-5.2.14/jobs.c 2009-09-17 00:32:08.000000000 +0200
+@@ -627,8 +627,10 @@
+ SS_RESTORE_IGN|SS_FORCE);
+ if (!(flags & (XPIPEI | XCOPROC))) {
+ int fd = open("/dev/null", 0);
+- (void) ksh_dup2(fd, 0, TRUE);
+- close(fd);
++ if (fd != 0) {
++ (void) ksh_dup2(fd, 0, TRUE);
++ close(fd);
++ }
+ }
+ }
+ remove_job(j, "child"); /* in case of `jobs` command */
+@@ -811,7 +813,7 @@
+ int sig;
+ {
+ Job *j;
+- Proc *p;
++/* Proc *p; */ /* unused */
+ int rv = 0;
+ int ecode;
+ #ifdef JOB_SIGS
+Index: pdksh-5.2.14/lex.c
+===================================================================
+--- pdksh-5.2.14.orig/lex.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/lex.c 2009-09-17 00:32:08.000000000 +0200
+@@ -699,11 +699,13 @@
+
+ case '(': /*)*/
+ #ifdef KSH
+- if ((c2 = getsc()) == '(') /*)*/
+- /* XXX need to handle ((...); (...)) */
+- c = MDPAREN;
+- else
+- ungetsc(c2);
++ if (!Flag(FSH)) {
++ if ((c2 = getsc()) == '(') /*)*/
++ /* XXX need to handle ((...); (...)) */
++ c = MDPAREN;
++ else
++ ungetsc(c2);
++ }
+ #endif /* KSH */
+ return c;
+ /*(*/
+@@ -1119,7 +1121,7 @@
+ */
+ {
+ struct shf *shf;
+- char *ps1;
++ char * volatile ps1;
+ Area *saved_atemp;
+
+ ps1 = str_val(global("PS1"));
+Index: pdksh-5.2.14/main.c
+===================================================================
+--- pdksh-5.2.14.orig/main.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/main.c 2009-09-17 00:32:08.000000000 +0200
+@@ -201,7 +201,24 @@
+ change_flag(FPOSIX, OF_SPECIAL, 1);
+ #endif /* POSIXLY_CORRECT */
+
+- /* import enviroment */
++#ifdef DEBIAN /* patch from OpenBSD */
++ /* Check to see if we're /bin/sh. */
++ if (!strcmp(&kshname[strlen(kshname) - 3], "/sh")
++ || !strcmp(kshname, "sh") || !strcmp(kshname, "-sh"))
++ Flag(FSH) = 1;
++
++ /* Set edit mode to emacs by default, may be overridden
++ * by the environment or the user. Also, we want tab completion
++ * on in vi by default. */
++#if defined(EDIT) && defined(EMACS)
++ change_flag(FEMACS, OF_SPECIAL, 1);
++#endif /* EDIT && EMACS */
++ #if defined(EDIT) && defined(VI)
++ Flag(FVITABCOMPLETE) = 1;
++#endif /* EDIT && VI */
++#endif /* DEBIAN */
++
++ /* import environment */
+ if (environ != NULL)
+ for (wp = environ; *wp != NULL; wp++)
+ typeset(*wp, IMPORT|EXPORT, 0, 0, 0);
+Index: pdksh-5.2.14/misc.c
+===================================================================
+--- pdksh-5.2.14.orig/misc.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/misc.c 2009-09-17 00:32:08.000000000 +0200
+@@ -159,6 +159,7 @@
+ { "posix", 0, OF_ANY }, /* non-standard */
+ { "privileged", 'p', OF_ANY },
+ { "restricted", 'r', OF_CMDLINE },
++ { "sh", 0, OF_ANY }, /* non-standard */ /* from OpenBSD */
+ { "stdin", 's', OF_CMDLINE }, /* pseudo non-standard */
+ { "trackall", 'h', OF_ANY },
+ { "verbose", 'v', OF_ANY },
+@@ -309,8 +310,15 @@
+ #ifdef OS2
+ ;
+ #else /* OS2 */
++#ifndef DEBIAN
+ setuid(ksheuid = getuid());
+ setgid(getgid());
++#else /* patch from OpenBSD */
++ seteuid(ksheuid = getuid());
++ setuid(ksheuid);
++ setegid(getgid());
++ setgid(getgid());
++#endif /* DEBIAN */
+ #endif /* OS2 */
+ } else if (f == FPOSIX && newval) {
+ #ifdef BRACE_EXPAND
+@@ -471,6 +479,7 @@
+ const char *as;
+ int *ai;
+ {
++#ifndef DEBIAN
+ const char *s;
+ register int n;
+ int sawdigit = 0;
+@@ -484,6 +493,19 @@
+ if (*s || !sawdigit)
+ return 0;
+ return 1;
++#else /* patch from OpenBSD */
++ char *p;
++ long n;
++
++ n = strtol(as, &p, 10);
++
++ if (!*as || *p || INT_MIN >= n || n >= INT_MAX)
++ return 0;
++
++ *ai = (int)n;
++ return 1;
++#endif
++
+ }
+
+ /* getn() that prints error */
+Index: pdksh-5.2.14/sh.h
+===================================================================
+--- pdksh-5.2.14.orig/sh.h 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/sh.h 2009-09-17 00:32:08.000000000 +0200
+@@ -382,7 +382,11 @@
+ */
+
+ typedef struct Area {
++#ifndef DEBIAN
+ struct Block *freelist; /* free list */
++#else /* patch from OpenBSD */
++ struct link *freelist; /* free list */
++#endif
+ } Area;
+
+ EXTERN Area aperm; /* permanent object space */
+@@ -501,6 +505,7 @@
+ FPOSIX, /* -o posix: be posixly correct */
+ FPRIVILEGED, /* -p: use suid_profile */
+ FRESTRICTED, /* -r: restricted shell */
++ FSH, /* -o sh: favor sh behavour */
+ FSTDIN, /* -s: (invocation) parse stdin */
+ FTRACKALL, /* -h: create tracked aliases for all commands */
+ FVERBOSE, /* -v: echo input */
+Index: pdksh-5.2.14/tests/th
+===================================================================
+--- pdksh-5.2.14.orig/tests/th 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/tests/th 2009-09-17 00:32:08.000000000 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+
+ #
+ # Test harness for pdksh tests.
+@@ -131,7 +131,7 @@
+ $os = defined $^O ? $^O : 'unknown';
+
+ require 'signal.ph' unless $os eq 'os2';
+-require 'errno.ph' unless $os eq 'os2';
++# require 'errno.ph' unless $os eq 'os2';
+ require 'getopts.pl';
+
+ ($prog = $0) =~ s#.*/##;
+Index: pdksh-5.2.14/trap.c
+===================================================================
+--- pdksh-5.2.14.orig/trap.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/trap.c 2009-09-17 00:32:08.000000000 +0200
+@@ -68,6 +68,8 @@
+ alarm_catcher(sig)
+ int sig;
+ {
++ int errno_ = errno;
++
+ if (ksh_tmout_state == TMOUT_READING) {
+ int left = alarm(0);
+
+@@ -77,6 +79,7 @@
+ } else
+ alarm(left);
+ }
++ errno = errno_;
+ return RETSIGVAL;
+ }
+ #endif /* KSH */
+@@ -111,6 +114,7 @@
+ int i;
+ {
+ Trap *p = &sigtraps[i];
++ int errno_ = errno;
+
+ trap = p->set = 1;
+ if (p->flags & TF_DFL_INTR)
+@@ -125,6 +129,7 @@
+ if (sigtraps[i].cursig == trapsig) /* this for SIGCHLD,SIGALRM */
+ sigaction(i, &Sigact_trap, (struct sigaction *) 0);
+ #endif /* V7_SIGNALS */
++ errno = errno_;
+ return RETSIGVAL;
+ }
+
+Index: pdksh-5.2.14/tree.c
+===================================================================
+--- pdksh-5.2.14.orig/tree.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/tree.c 2009-09-17 00:32:08.000000000 +0200
+@@ -506,7 +506,7 @@
+ for (tw = t->vars; *tw++ != NULL; )
+ ;
+ rw = r->vars = (char **)
+- alloc((int)(tw - t->vars) * sizeof(*tw), ap);
++ alloc((tw - t->vars + 1) * sizeof(*tw), ap);
+ for (tw = t->vars; *tw != NULL; )
+ *rw++ = wdcopy(*tw++, ap);
+ *rw = NULL;
+@@ -518,7 +518,7 @@
+ for (tw = t->args; *tw++ != NULL; )
+ ;
+ rw = r->args = (char **)
+- alloc((int)(tw - t->args) * sizeof(*tw), ap);
++ alloc((tw - t->args + 1) * sizeof(*tw), ap);
+ for (tw = t->args; *tw != NULL; )
+ *rw++ = wdcopy(*tw++, ap);
+ *rw = NULL;
+@@ -679,7 +679,7 @@
+
+ for (ior = iow; *ior++ != NULL; )
+ ;
+- ior = (struct ioword **) alloc((int)(ior - iow) * sizeof(*ior), ap);
++ ior = (struct ioword **) alloc((ior - iow + 1) * sizeof(*ior), ap);
+
+ for (i = 0; iow[i] != NULL; i++) {
+ register struct ioword *p, *q;
+Index: pdksh-5.2.14/c_test.c
+===================================================================
+--- pdksh-5.2.14.orig/c_test.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/c_test.c 2009-09-17 00:32:08.000000000 +0200
+@@ -124,10 +124,10 @@
+ te.pos.wp = wp + 1;
+ te.wp_end = wp + argc;
+
+- /*
++ /*
+ * Handle the special cases from POSIX.2, section 4.62.4.
+- * Implementation of all the rules isn't necessary since
+- * our parser does the right thing for the ommited steps.
++ * Implementation of all the rules isn't necessary since
++ * our parser does the right thing for the omitted steps.
+ */
+ if (argc <= 5) {
+ char **owp = wp;
+@@ -238,7 +238,7 @@
+ if (not)
+ res = !res;
+ }
+- return res;
++ return res;
+ case TO_FILRD: /* -r */
+ return test_eaccess(opnd1, R_OK) == 0;
+ case TO_FILWR: /* -w */
+@@ -456,10 +456,12 @@
+ }
+ #endif /* !HAVE_DEV_FD */
+
+- /* On most (all?) unixes, access() says everything is executable for
++ res = eaccess(path, mode);
++ /*
++ * On most (all?) unixes, access() says everything is executable for
+ * root - avoid this on files by using stat().
+ */
+- if ((mode & X_OK) && ksheuid == 0) {
++ if (res == 0 && ksheuid == 0 && (mode & X_OK)) {
+ struct stat statb;
+
+ if (stat(path, &statb) < 0)
+@@ -469,13 +471,7 @@
+ else
+ res = (statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
+ ? 0 : -1;
+- /* Need to check other permissions? If so, use access() as
+- * this will deal with root on NFS.
+- */
+- if (res == 0 && (mode & (R_OK|W_OK)))
+- res = eaccess(path, mode);
+- } else
+- res = eaccess(path, mode);
++ }
+
+ return res;
+ }
+Index: pdksh-5.2.14/eval.c
+===================================================================
+--- pdksh-5.2.14.orig/eval.c 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/eval.c 2009-09-17 00:32:08.000000000 +0200
+@@ -870,8 +870,11 @@
+ openpipe(pv);
+ shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0);
+ ofd1 = savefd(1, 0); /* fd 1 may be closed... */
+- ksh_dup2(pv[1], 1, FALSE);
+- close(pv[1]);
++ if (pv[1] != 1) {
++ ksh_dup2(pv[1], 1, FALSE);
++ close(pv[1]);
++ }
++
+ execute(t, XFORK|XXCOM|XPIPEO);
+ restfd(1, ofd1);
+ startlast();
+Index: pdksh-5.2.14/tests/regress.t
+===================================================================
+--- pdksh-5.2.14.orig/tests/regress.t 2009-09-17 00:31:58.000000000 +0200
++++ pdksh-5.2.14/tests/regress.t 2009-09-17 00:32:08.000000000 +0200
+@@ -156,11 +156,12 @@
+ echo $?
+ shoud not print 0. (according to /bin/sh, at&t ksh88, and the
+ getopt(1) man page - not according to POSIX)
++ For Debian - it should print 0, cf. bug#118476.
+ stdin:
+ set -- `false`
+ echo $?
+ expected-stdout:
+- 1
++ 0
+ ---
+
+
diff --git a/system/pdksh/patches/011_OpenBSD-alloc.patch b/system/pdksh/patches/011_OpenBSD-alloc.patch
new file mode 100644
index 0000000000..ec272897e2
--- /dev/null
+++ b/system/pdksh/patches/011_OpenBSD-alloc.patch
@@ -0,0 +1,199 @@
+ + alloc.c: Kill hand-made memory allocation code, that is definitely
+ buggy. Replace with simple wrapper around malloc, at least this works,
+ and it's easier to debug anyways.
+ + alloc.c: Don't allow alloc() and aresize() to fail. Their return
+ value was only checked in two place (both in conjunction with
+ str_save). Upon malloc/realloc failure we call internal_errorf()
+ which pops throws and error and pops back to the last good state.
+Index: pdksh-5.2.14/alloc.c
+===================================================================
+--- pdksh-5.2.14.orig/alloc.c 2008-04-15 20:46:56.000000000 +0200
++++ pdksh-5.2.14/alloc.c 2008-04-15 20:50:18.000000000 +0200
+@@ -1,3 +1,5 @@
++#ifndef DEBIAN
++
+ /*
+ * area-based allocation built on malloc/free
+ */
+@@ -110,6 +112,13 @@
+ Block *block;
+ struct {int _;} junk; /* alignment */
+ double djunk; /* alignment */
++#ifdef DEBIAN /* patch from RedHat */
++#ifdef __ia64__
++ /* IA64 requires 16 byte alignment for some objects, so make
++ * this the minimum allocation size */
++ char ajunk[16];
++#endif
++#endif
+ };
+
+ struct Block {
+@@ -282,7 +291,9 @@
+ * working (as it assumes size < ICELLS means it is not
+ * a `large object').
+ */
+- if (oldcells > ICELLS && cells > ICELLS) {
++ if (oldcells > ICELLS && cells > ICELLS
++ && ((dp-2)->block->last == dp+oldcells) /* don't destroy blocks which have grown! */
++ ) {
+ Block *bp = (dp-2)->block;
+ Block *nbp;
+ /* Saved in case realloc fails.. */
+@@ -332,7 +343,7 @@
+ * (need to check that cells < ICELLS so we don't make an
+ * object a `large' - that would mess everything up).
+ */
+- if (dp && cells > oldcells && cells <= ICELLS) {
++ if (dp && cells > oldcells) {
+ Cell *fp, *fpp;
+ Block *bp = (dp-2)->block;
+ int need = cells - oldcells - NOBJECT_FIELDS;
+@@ -363,7 +374,7 @@
+ * it to malloc...)
+ * Note: this also handles cells == oldcells (a no-op).
+ */
+- if (dp && cells <= oldcells && oldcells <= ICELLS) {
++ if (dp && cells <= oldcells) {
+ int split;
+
+ split = oldcells - cells;
+@@ -411,7 +422,9 @@
+
+ /* If this is a large object, just free it up... */
+ /* Release object... */
+- if ((dp-1)->size > ICELLS) {
++ if ((dp-1)->size > ICELLS
++ && (bp->last == dp + (dp-1)->size) /* don't free non-free blocks which have grown! */
++ ) {
+ ablockfree(bp, ap);
+ ACHECK(ap);
+ return;
+@@ -774,3 +787,127 @@
+ # endif /* TEST_ALLOC */
+
+ #endif /* MEM_DEBUG */
++
++#else /* DEBIAN */ /* patch from OpenBSD */
++
++/* $OpenBSD: alloc.c,v 1.6 2003/08/05 20:52:27 millert Exp $ */
++/*
++ * Copyright (c) 2002 Marc Espie.
++ *
++ * 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.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT 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 OPENBSD
++ * PROJECT 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.
++ */
++
++/*
++ * area-based allocation built on malloc/free
++ */
++
++#include "sh.h"
++
++struct link {
++ struct link *prev;
++ struct link *next;
++};
++
++Area *
++ainit(Area *ap)
++{
++ ap->freelist = NULL;
++ return ap;
++}
++
++void
++afreeall(Area *ap)
++{
++ struct link *l, *l2;
++
++ for (l = ap->freelist; l != NULL; l = l2) {
++ l2 = l->next;
++ free(l);
++ }
++ ap->freelist = NULL;
++}
++
++#define L2P(l) ( (void *)(((char *)(l)) + sizeof(struct link)) )
++#define P2L(p) ( (struct link *)(((char *)(p)) - sizeof(struct link)) )
++
++void *
++alloc(size_t size, Area *ap)
++{
++ struct link *l;
++
++ l = malloc(size + sizeof(struct link));
++ if (l == NULL)
++ internal_errorf(1, "unable to allocate memory");
++ l->next = ap->freelist;
++ l->prev = NULL;
++ if (ap->freelist)
++ ap->freelist->prev = l;
++ ap->freelist = l;
++
++ return L2P(l);
++}
++
++void *
++aresize(void *ptr, size_t size, Area *ap)
++{
++ struct link *l, *l2, *lprev, *lnext;
++
++ if (ptr == NULL)
++ return alloc(size, ap);
++
++ l = P2L(ptr);
++ lprev = l->prev;
++ lnext = l->next;
++
++ l2 = realloc(l, size+sizeof(struct link));
++ if (l2 == NULL)
++ internal_errorf(1, "unable to allocate memory");
++ if (lprev)
++ lprev->next = l2;
++ else
++ ap->freelist = l2;
++ if (lnext)
++ lnext->prev = l2;
++
++ return L2P(l2);
++}
++
++void
++afree(void *ptr, Area *ap)
++{
++ struct link *l;
++
++ if (!ptr)
++ return;
++
++ l = P2L(ptr);
++
++ if (l->prev)
++ l->prev->next = l->next;
++ else
++ ap->freelist = l->next;
++ if (l->next)
++ l->next->prev = l->prev;
++
++ free(l);
++}
++#endif /* DEBIAN */
diff --git a/system/pdksh/patches/020_PLD-patches.patch b/system/pdksh/patches/020_PLD-patches.patch
new file mode 100644
index 0000000000..81c189f243
--- /dev/null
+++ b/system/pdksh/patches/020_PLD-patches.patch
@@ -0,0 +1,84 @@
+ * Apply patches from PLD distribution (pdksh-5.2.14-23.src.rpm)
+ + pdksh-eval-segv.patch, fixes one more segfault bug
+ + pdksh-rlimit_locks.patch, adds flocks support to ulimit.
+ * c_ulimit.c: enclose all uses of RLIMIT_LOCKS with appropriate #ifdefs
+ (closes: #307323).
+Index: pdksh-5.2.14/c_sh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_sh.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/c_sh.c 2008-04-15 20:50:48.000000000 +0200
+@@ -422,7 +422,8 @@
+ c_eval(wp)
+ char **wp;
+ {
+- register struct source *s;
++ register struct source *s,*olds=source;
++ int retval;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+@@ -456,7 +457,9 @@
+ exstat = subst_exstat;
+ }
+
+- return shell(s, FALSE);
++ retval=shell(s, FALSE);
++ source=olds;
++ return retval;
+ }
+
+ int
+Index: pdksh-5.2.14/c_ulimit.c
+===================================================================
+--- pdksh-5.2.14.orig/c_ulimit.c 2008-04-15 20:46:56.000000000 +0200
++++ pdksh-5.2.14/c_ulimit.c 2008-04-15 20:50:48.000000000 +0200
+@@ -111,6 +111,9 @@
+ #ifdef RLIMIT_SWAP
+ { "swap(kbytes)", RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
+ #endif
++#ifdef RLIMIT_LOCKS
++ { "flocks", RLIMIT, RLIMIT_LOCKS, RLIMIT_LOCKS, -1, 'L' },
++#endif
+ { (char *) 0 }
+ };
+ static char options[3 + NELEM(limits)];
+@@ -189,7 +192,18 @@
+ for (l = limits; l->name; l++) {
+ #ifdef HAVE_SETRLIMIT
+ if (l->which == RLIMIT) {
+- getrlimit(l->gcmd, &limit);
++ int getreturn;
++
++ getreturn=getrlimit(l->gcmd, &limit);
++#ifdef RLIMIT_LOCKS
++ if ( getreturn < 0 ) {
++ if ( ( errno == EINVAL ) &&
++ ( l->gcmd == RLIMIT_LOCKS ) ) {
++ limit.rlim_cur = RLIM_INFINITY;
++ limit.rlim_max = RLIM_INFINITY;
++ }
++ }
++#endif
+ if (how & SOFT)
+ val = limit.rlim_cur;
+ else if (how & HARD)
+@@ -225,11 +239,17 @@
+ if (how & HARD)
+ limit.rlim_max = val;
+ if (setrlimit(l->scmd, &limit) < 0) {
+- if (errno == EPERM)
++ if (errno == EPERM) {
+ bi_errorf("exceeds allowable limit");
+- else
++#ifdef RLIMIT_LOCKS
++ } else if ( ( errno == EINVAL ) &&
++ ( l->scmd == RLIMIT_LOCKS ) ) {
++ bi_errorf("unable to set it on the current kernel");
++#endif
++ } else {
+ bi_errorf("bad limit: %s",
+ strerror(errno));
++ }
+ return 1;
+ }
+ } else {
diff --git a/system/pdksh/patches/030_posh-eval.patch b/system/pdksh/patches/030_posh-eval.patch
new file mode 100644
index 0000000000..e9f668493c
--- /dev/null
+++ b/system/pdksh/patches/030_posh-eval.patch
@@ -0,0 +1,29 @@
+pdksh (5.2.14-13) unstable; urgency=low
+
+ * c_sh.c: Apply patch from the posh package to make `eval false || true'
+ not exit with -e (closes: #269067).
+Index: pdksh-5.2.14/c_sh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_sh.c 2008-04-15 20:50:48.000000000 +0200
++++ pdksh-5.2.14/c_sh.c 2008-04-15 20:51:18.000000000 +0200
+@@ -423,7 +423,7 @@
+ char **wp;
+ {
+ register struct source *s,*olds=source;
+- int retval;
++ int retval, errexitflagtmp;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+@@ -456,8 +456,10 @@
+ */
+ exstat = subst_exstat;
+ }
+-
++ errexitflagtmp = Flag(FERREXIT);
++ Flag(FERREXIT) = 0;
+ retval=shell(s, FALSE);
++ Flag(FERREXIT) = errexitflagtmp;
+ source=olds;
+ return retval;
+ }
diff --git a/system/pdksh/patches/040_Debian-gcc-warnings.patch b/system/pdksh/patches/040_Debian-gcc-warnings.patch
new file mode 100644
index 0000000000..6970b4b4ea
--- /dev/null
+++ b/system/pdksh/patches/040_Debian-gcc-warnings.patch
@@ -0,0 +1,147 @@
+ * Compiled with -Wall, fixed some gcc warnings.
+Index: pdksh-5.2.14/c_ksh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_ksh.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/c_ksh.c 2008-04-15 20:51:49.000000000 +0200
+@@ -1110,13 +1110,14 @@
+ return 1;
+ }
+ wp += builtin_opt.optind;
+- if (!*wp)
++ if (!*wp) {
+ if (j_jobs((char *) 0, flag, nflag))
+ rv = 1;
+- else
++ } else {
+ for (; *wp; wp++)
+ if (j_jobs(*wp, flag, nflag))
+ rv = 1;
++ }
+ return rv;
+ }
+
+Index: pdksh-5.2.14/io.c
+===================================================================
+--- pdksh-5.2.14.orig/io.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/io.c 2008-04-15 20:51:49.000000000 +0200
+@@ -297,11 +297,12 @@
+
+ if (fd < FDBASE) {
+ nfd = ksh_dupbase(fd, FDBASE);
+- if (nfd < 0)
++ if (nfd < 0) {
+ if (errno == EBADF)
+ return -1;
+ else
+ errorf("too many files open in shell");
++ }
+ if (!noclose)
+ close(fd);
+ } else
+Index: pdksh-5.2.14/jobs.c
+===================================================================
+--- pdksh-5.2.14.orig/jobs.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/jobs.c 2008-04-15 20:51:49.000000000 +0200
+@@ -1566,11 +1566,12 @@
+ break;
+ }
+
+- if (how != JP_SHORT)
++ if (how != JP_SHORT) {
+ if (p == j->proc_list)
+ shf_fprintf(shf, "[%d] %c ", j->job, jobchar);
+ else
+ shf_fprintf(shf, "%s", filler);
++ }
+
+ if (how == JP_LONG)
+ shf_fprintf(shf, "%5d ", p->pid);
+Index: pdksh-5.2.14/lex.c
+===================================================================
+--- pdksh-5.2.14.orig/lex.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/lex.c 2008-04-15 20:51:49.000000000 +0200
+@@ -645,11 +645,12 @@
+ if (c == c2 || (c == '<' && c2 == '>')) {
+ iop->flag = c == c2 ?
+ (c == '>' ? IOCAT : IOHERE) : IORDWR;
+- if (iop->flag == IOHERE)
++ if (iop->flag == IOHERE) {
+ if ((c2 = getsc()) == '-')
+ iop->flag |= IOSKIP;
+ else
+ ungetsc(c2);
++ }
+ } else if (c2 == '&')
+ iop->flag = IODUP | (c == '<' ? IORDUP : 0);
+ else {
+Index: pdksh-5.2.14/main.c
+===================================================================
+--- pdksh-5.2.14.orig/main.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/main.c 2008-04-15 20:51:49.000000000 +0200
+@@ -593,11 +593,12 @@
+ if (trap)
+ runtraps(0);
+
+- if (s->next == NULL)
++ if (s->next == NULL) {
+ if (Flag(FVERBOSE))
+ s->flags |= SF_ECHO;
+ else
+ s->flags &= ~SF_ECHO;
++ }
+
+ if (interactive) {
+ j_notify();
+Index: pdksh-5.2.14/table.c
+===================================================================
+--- pdksh-5.2.14.orig/table.c 2008-04-15 20:46:56.000000000 +0200
++++ pdksh-5.2.14/table.c 2008-04-15 20:51:49.000000000 +0200
+@@ -53,7 +53,7 @@
+ if (otblp == NULL)
+ return;
+ for (i = 0; i < osize; i++)
+- if ((tblp = otblp[i]) != NULL)
++ if ((tblp = otblp[i]) != NULL) {
+ if ((tblp->flag&DEFINED)) {
+ for (p = &ntblp[hash(tblp->name)
+ & (tp->size-1)];
+@@ -65,6 +65,7 @@
+ } else if (!(tblp->flag & FINUSE)) {
+ afree((void*)tblp, tp->areap);
+ }
++ }
+ afree((void*)otblp, tp->areap);
+ }
+
+Index: pdksh-5.2.14/var.c
+===================================================================
+--- pdksh-5.2.14.orig/var.c 2008-04-15 20:48:46.000000000 +0200
++++ pdksh-5.2.14/var.c 2008-04-15 20:51:49.000000000 +0200
+@@ -63,11 +63,12 @@
+
+ e->loc = l->next; /* pop block */
+ for (i = l->vars.size; --i >= 0; )
+- if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
++ if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) {
+ if ((vq = global(vp->name))->flag & ISSET)
+ setspec(vq);
+ else
+ unsetspec(vq);
++ }
+ if (l->flags & BF_DOGETOPTS)
+ user_opt = l->getopts_state;
+ afreeall(&l->area);
+@@ -217,11 +218,12 @@
+ }
+ for (l = e->loc; ; l = l->next) {
+ vp = tsearch(&l->vars, n, h);
+- if (vp != NULL)
++ if (vp != NULL) {
+ if (array)
+ return arraysearch(vp, val);
+ else
+ return vp;
++ }
+ if (l->next == NULL)
+ break;
+ }
diff --git a/system/pdksh/patches/041_Debian-tilde-expansion.patch b/system/pdksh/patches/041_Debian-tilde-expansion.patch
new file mode 100644
index 0000000000..30741eb470
--- /dev/null
+++ b/system/pdksh/patches/041_Debian-tilde-expansion.patch
@@ -0,0 +1,15 @@
+ * Don't do tilde expansion after `=' sign in non-assignments.
+ Patch stolen from the posh package (closes: #187839).
+Index: pdksh-5.2.14/eval.c
+===================================================================
+--- pdksh-5.2.14.orig/eval.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/eval.c 2008-04-15 20:52:19.000000000 +0200
+@@ -627,7 +627,7 @@
+ #endif /* BRACE_EXPAND */
+ case '=':
+ /* Note first unquoted = for ~ */
+- if (!(f & DOTEMP_) && !saw_eq) {
++ if (!(f & DOTEMP_) && !saw_eq && (f & DOASNTILDE)) {
+ saw_eq = 1;
+ tilde_ok = 1;
+ }
diff --git a/system/pdksh/patches/042_Debian-eaccess.patch b/system/pdksh/patches/042_Debian-eaccess.patch
new file mode 100644
index 0000000000..c859dd459a
--- /dev/null
+++ b/system/pdksh/patches/042_Debian-eaccess.patch
@@ -0,0 +1,140 @@
+ * Wrote function eaccess (used to be a macro defined as `access'),
+ which swaps real uid and gid with the effective ones, calls access,
+ and reverts the uid/gid. This fixes the test builtin command not
+ working properly when shell is privileged (closes: #245213).
+Index: pdksh-5.2.14/c_test.c
+===================================================================
+--- pdksh-5.2.14.orig/c_test.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/c_test.c 2008-04-15 20:52:50.000000000 +0200
+@@ -338,7 +338,7 @@
+ case TO_FILUID: /* -O */
+ return test_stat(opnd1, &b1) == 0 && b1.st_uid == ksheuid;
+ case TO_FILGID: /* -G */
+- return test_stat(opnd1, &b1) == 0 && b1.st_gid == getegid();
++ return test_stat(opnd1, &b1) == 0 && b1.st_gid == kshegid;
+ /*
+ * Binary Operators
+ */
+@@ -656,3 +656,36 @@
+ else
+ bi_errorf("%s", msg);
+ }
++
++
++#ifdef DEBIAN
++int eaccess(const char *pathname, int mode) {
++ int need_setreuid, need_setregid;
++ int result;
++ int _errno;
++
++
++
++ if (( need_setregid = ( kshgid != kshegid ) )) {
++ setregid( kshegid, kshgid );
++ }
++
++ if (( need_setreuid = ( kshuid != ksheuid ) )) {
++ setreuid( ksheuid, kshuid );
++ }
++
++ result = access( pathname, mode );
++ _errno = errno;
++
++ if ( need_setregid ) {
++ setregid( kshgid, kshegid );
++ }
++
++ if ( need_setreuid ) {
++ setreuid( kshuid, ksheuid );
++ }
++
++ errno = _errno;
++ return result;
++}
++#endif
+Index: pdksh-5.2.14/main.c
+===================================================================
+--- pdksh-5.2.14.orig/main.c 2008-04-15 20:51:49.000000000 +0200
++++ pdksh-5.2.14/main.c 2008-04-15 20:52:50.000000000 +0200
+@@ -269,6 +269,9 @@
+
+
+ ksheuid = geteuid();
++ kshuid = getuid();
++ kshgid = getgid();
++ kshegid = getegid();
+ safe_prompt = ksheuid ? "$ " : "# ";
+ {
+ struct tbl *vp = global("PS1");
+@@ -283,7 +286,7 @@
+ }
+
+ /* Set this before parsing arguments */
+- Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid();
++ Flag(FPRIVILEGED) = kshuid != ksheuid || kshgid != kshegid;
+
+ /* this to note if monitor is set on command line (see below) */
+ Flag(FMONITOR) = 127;
+Index: pdksh-5.2.14/misc.c
+===================================================================
+--- pdksh-5.2.14.orig/misc.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/misc.c 2008-04-15 20:52:50.000000000 +0200
+@@ -19,6 +19,7 @@
+ int isfile));
+ static const unsigned char *cclass ARGS((const unsigned char *p, int sub));
+
++
+ /*
+ * Fast character classes
+ */
+@@ -311,13 +312,13 @@
+ ;
+ #else /* OS2 */
+ #ifndef DEBIAN
+- setuid(ksheuid = getuid());
+- setgid(getgid());
++ setuid(ksheuid = kshuid = getuid());
++ setgid(kshegid = kshgid = getgid());
+ #else /* patch from OpenBSD */
+- seteuid(ksheuid = getuid());
++ seteuid(ksheuid = kshuid = getuid());
+ setuid(ksheuid);
+- setegid(getgid());
+- setgid(getgid());
++ setegid(kshegid = kshgid = getgid());
++ setgid(kshegid);
+ #endif /* DEBIAN */
+ #endif /* OS2 */
+ } else if (f == FPOSIX && newval) {
+@@ -1365,3 +1366,4 @@
+ return b;
+ #endif /* HAVE_GETCWD */
+ }
++
+Index: pdksh-5.2.14/sh.h
+===================================================================
+--- pdksh-5.2.14.orig/sh.h 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/sh.h 2008-04-15 20:52:50.000000000 +0200
+@@ -353,8 +353,12 @@
+ #define NUFILE 10 /* Number of user-accessible files */
+ #define FDBASE 10 /* First file usable by Shell */
+
++#ifndef DEBIAN
+ /* you're not going to run setuid shell scripts, are you? */
+ #define eaccess(path, mode) access(path, mode)
++#else
++EXTERN int eaccess( const char * pathname, int mode );
++#endif
+
+ /* Make MAGIC a char that might be printed to make bugs more obvious, but
+ * not a char that is used often. Also, can't use the high bit as it causes
+@@ -372,6 +376,9 @@
+ EXTERN pid_t kshpid; /* $$, shell pid */
+ EXTERN pid_t procpid; /* pid of executing process */
+ EXTERN int ksheuid; /* effective uid of shell */
++EXTERN int kshegid; /* effective gid of shell */
++EXTERN int kshuid; /* real uid of shell */
++EXTERN int kshgid; /* real gid of shell */
+ EXTERN int exstat; /* exit status */
+ EXTERN int subst_exstat; /* exit status of last $(..)/`..` */
+ EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
diff --git a/system/pdksh/patches/043_Debian-siglist.patch b/system/pdksh/patches/043_Debian-siglist.patch
new file mode 100644
index 0000000000..bd7a9af805
--- /dev/null
+++ b/system/pdksh/patches/043_Debian-siglist.patch
@@ -0,0 +1,23 @@
+ * siglist.sh: fix sed command line
+ * siglist.sh: pass `-' to trap call, fixes FTBFS on sparc.
+Index: pdksh-5.2.14/siglist.sh
+===================================================================
+--- pdksh-5.2.14.orig/siglist.sh 2008-04-15 20:46:55.000000000 +0200
++++ pdksh-5.2.14/siglist.sh 2008-04-15 20:53:20.000000000 +0200
+@@ -16,14 +16,14 @@
+ CPP="${1-cc -E}"
+
+ # The trap here to make up for a bug in bash (1.14.3(1)) that calls the trap
+-(trap $trapsigs;
++(trap - $trapsigs;
+ echo '#include "sh.h"';
+ echo ' { QwErTy SIGNALS , "DUMMY" , "hook for number of signals" },';
+ sed -e '/^[ ]*#/d' -e 's/^[ ]*\([^ ][^ ]*\)[ ][ ]*\(.*[^ ]\)[ ]*$/#ifdef SIG\1\
+ { QwErTy SIG\1 , "\1", "\2" },\
+ #endif/') > $in
+ $CPP $in > $out
+-sed -n 's/{ QwErTy/{/p' < $out | awk '{print NR, $0}' | sort +2n +0n |
++sed -n 's/{ QwErTy/{/p' < $out | awk '{print NR, $0}' | sort -k 3n -k 1n |
+ sed 's/^[0-9]* //' |
+ awk 'BEGIN { last=0; nsigs=0; }
+ {
diff --git a/system/pdksh/patches/044_Debian-emacs-crash.patch b/system/pdksh/patches/044_Debian-emacs-crash.patch
new file mode 100644
index 0000000000..047302811b
--- /dev/null
+++ b/system/pdksh/patches/044_Debian-emacs-crash.patch
@@ -0,0 +1,18 @@
+ * emacs.c: Fix segmentation fault bug when ksh used bash history file
+ (closes: #284358).
+Index: pdksh-5.2.14/emacs.c
+===================================================================
+--- pdksh-5.2.14.orig/emacs.c 2008-04-15 20:49:47.000000000 +0200
++++ pdksh-5.2.14/emacs.c 2008-04-15 20:53:50.000000000 +0200
+@@ -883,9 +883,9 @@
+ }
+ x_histp = hp;
+ oldsize = x_size_str(xbuf);
+- (void)strcpy(xbuf, *hp);
++ (void)strncpy(xbuf, *hp, xend - xbuf - 1);
+ xbp = xbuf;
+- xep = xcp = xbuf + strlen(*hp);
++ xep = xcp = xbuf + strlen(xbuf);
+ xlp_valid = FALSE;
+ if (xep > x_lastcp())
+ x_goto(xep);
diff --git a/system/pdksh/patches/045_Debian-job-control.patch b/system/pdksh/patches/045_Debian-job-control.patch
new file mode 100644
index 0000000000..4e1696265a
--- /dev/null
+++ b/system/pdksh/patches/045_Debian-job-control.patch
@@ -0,0 +1,130 @@
+ * Fix job control bug in non-interactive scripts (closes: #296446)
+ Many thanks to Paul Stroud <pstroud@gmail.com> for the patch.
+ * lex.c: Don't expand aliases if there's an opening bracket just after
+ the token. Fixes unreported problem with pdksh reporting syntax error
+ on the init scripts that define function named `stop' (clashing
+ with an built-in alias.)
+Index: pdksh-5.2.14/jobs.c
+===================================================================
+--- pdksh-5.2.14.orig/jobs.c 2009-07-18 15:20:19.000000000 +0200
++++ pdksh-5.2.14/jobs.c 2009-07-18 15:20:27.000000000 +0200
+@@ -340,12 +340,17 @@
+ int i;
+
+ if (Flag(FMONITOR)) {
+- /* Don't call get_tty() 'til we own the tty process group */
+- tty_init(FALSE);
++ int use_tty;
++ if (Flag(FTALKING)) {
++ /* Don't call get_tty() 'til we own the tty process group */
++ use_tty = 1;
++ tty_init(FALSE);
++ } else
++ use_tty = 0;
+
+ # ifdef TTY_PGRP
+ /* no controlling tty, no SIGT* */
+- ttypgrp_ok = tty_fd >= 0 && tty_devtty;
++ ttypgrp_ok = use_tty && tty_fd >= 0 && tty_devtty;
+
+ if (ttypgrp_ok && (our_pgrp = getpgID()) < 0) {
+ warningf(FALSE, "j_init: getpgrp() failed: %s",
+@@ -401,8 +406,10 @@
+ strerror(errno));
+ }
+ # endif /* NTTYDISC && TIOCSETD */
+- if (!ttypgrp_ok)
+- warningf(FALSE, "warning: won't have full job control");
++ if (Flag(FTALKING)) {
++ if (!ttypgrp_ok)
++ warningf(FALSE, "warning: won't have full job control");
++ }
+ # endif /* TTY_PGRP */
+ if (tty_fd >= 0)
+ get_tty(tty_fd, &tty_state);
+Index: pdksh-5.2.14/lex.c
+===================================================================
+--- pdksh-5.2.14.orig/lex.c 2009-07-18 15:20:19.000000000 +0200
++++ pdksh-5.2.14/lex.c 2009-07-18 15:20:27.000000000 +0200
+@@ -723,7 +723,15 @@
+ #endif /* KSH */
+ ) /* ONEWORD? */
+ return LWORD;
+- ungetsc(c); /* unget terminator */
++
++ /* unget terminator */
++ ungetsc(c);
++
++ /*
++ * note: the alias-vs-function code below depends on several
++ * interna: starting from here, source->str is not modified;
++ * the way getsc() and ungetsc() operate; etc.
++ */
+
+ /* copy word to unprefixed string ident */
+ for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
+@@ -747,6 +755,33 @@
+ if ((cf & ALIAS) && (p = tsearch(&aliases, ident, h))
+ && (p->flag & ISSET))
+ {
++ /*
++ * this still points to the same character as the
++ * ungetsc'd terminator from above
++ */
++ const char *cp = source->str;
++
++ /* prefer POSIX but not Korn functions over aliases */
++ while (*cp == ' ' || *cp == '\t')
++ /*
++ * this is like getsc() without skipping
++ * over Source boundaries (including not
++ * parsing ungetsc'd characters that got
++ * pushed into an SREREAD) which is what
++ * we want here anyway: find out whether
++ * the alias name is followed by a POSIX
++ * function definition (only the opening
++ * parenthesis is checked though)
++ */
++ ++cp;
++ /* prefer functions over aliases */
++ if (*cp == '(' /*)*/) {
++ /*
++ * delete alias upon encountering function
++ * definition
++ */
++ tdelete(p);
++ } else {
+ register Source *s;
+
+ for (s = source; s->type == SALIAS; s = s->next)
+@@ -760,6 +795,7 @@
+ source = s;
+ afree(yylval.cp, ATEMP);
+ goto Again;
++ }
+ }
+ }
+
+Index: pdksh-5.2.14/ksh.Man
+===================================================================
+--- pdksh-5.2.14.orig/ksh.Man 2009-07-18 15:20:07.000000000 +0200
++++ pdksh-5.2.14/ksh.Man 2009-07-18 15:21:11.000000000 +0200
+@@ -390,6 +390,7 @@
+ .IP "\fIname\fP \fB()\fP \fIcommand\fP"
+ Mostly the same as \fBfunction\fP.
+ See Functions below.
++Whitespace (space or tab) after \fIname\fP will be ignored most of the time.
+ .\"}}}
+ .\"{{{ time [-p] [ pipeline ]
+ .IP "\fBtime\fP [ \fB-p\fP ] [ \fIpipeline\fP ]"
+@@ -1457,6 +1458,10 @@
+ so \fBgetopts\fP can be used properly both inside and outside the function
+ (Bourne-style functions leave \fBOPTIND\fP untouched, so using \fBgetopts\fP
+ inside a function interferes with using \fBgetopts\fP outside the function).
++.br
++Bourne-style function definitions take precedence over alias dereferences
++and remove alias definitions upon encounter, while aliases take precedence
++over Korn-style functions.
+ .nr PD \n(P2
+ In the future, the following differences will also be added:
+ .nr P2 \n(PD
diff --git a/system/pdksh/patches/050_various-man-fixes.patch b/system/pdksh/patches/050_various-man-fixes.patch
new file mode 100644
index 0000000000..8504f3eca7
--- /dev/null
+++ b/system/pdksh/patches/050_various-man-fixes.patch
@@ -0,0 +1,260 @@
+Various fixes (typos, references, etc.) to ksh(1) man page.
+Index: pdksh-5.2.14/ksh.Man
+===================================================================
+--- pdksh-5.2.14.orig/ksh.Man 2009-09-16 23:23:42.000000000 +0200
++++ pdksh-5.2.14/ksh.Man 2009-09-16 23:23:46.000000000 +0200
+@@ -18,7 +18,7 @@
+ .\"}}}
+ .\"{{{ Title
+ .ksh(
+-.TH KSH 1 "August 19, 1996" "" "User commands"
++.TH PDKSH 1 "August 19, 1996" "" "User commands"
+ .ksh)
+ .sh(
+ .TH SH 1 "August 19, 1996" "" "User commands"
+@@ -27,7 +27,7 @@
+ .\"{{{ Name
+ .SH NAME
+ .ksh(
+-ksh \- Public domain Korn shell
++pdksh \- Public domain Korn shell
+ .ksh)
+ .sh(
+ sh \- Public domain Bourne shell
+@@ -37,12 +37,12 @@
+ .SH SYNOPSIS
+ .ad l
+ .ksh(
+-\fBksh\fP
++\fBpdksh\fP
+ .ksh)
+ .sh(
+ \fBsh\fP
+ .sh)
+-[\fB\(+-abCefhikmnprsuvxX\fP] [\fB\(+-o\fP \fIoption\fP] [ [ \fB\-c\fP \fIcommand-string\fP [\fIcommand-name\fP] | \fB\-s\fP | \fIfile\fP ] [\fIargument\fP ...] ]
++[\fB+\-abCefhikmnprsuvxX\fP] [\fB+\-o\fP \fIoption\fP] [ [ \fB\-c\fP \fIcommand-string\fP [\fIcommand-name\fP] | \fB\-s\fP | \fIfile\fP ] [\fIargument\fP ...] ]
+ .ad b
+ .\"}}}
+ .\"{{{ Description
+@@ -602,7 +602,7 @@
+ The later form can be treated as arrays by appending an array
+ index of the form: \fB[\fP\fIexpr\fP\fB]\fP where \fIexpr\fP is
+ an arithmetic expression.
+-Array indicies are currently limited to the range 0 through 1023, inclusive.
++Array indices are currently limited to the range 0 through 1023, inclusive.
+ Parameter substitutions take the form \fB$\fP\fIname\fP,
+ \fB${\fP\fIname\fP\fB}\fP or
+ \fB${\fP\fIname\fP\fB[\fP\fIexpr\fP\fB]}\fP, where \fIname\fP is a
+@@ -640,7 +640,7 @@
+ .\"{{{ environment
+ Parameters with the export attribute (set using the \fBexport\fP or
+ \fBtypeset \-x\fP commands, or by parameter assignments followed by simple
+-commands) are put in the environment (see \fIenviron\fP(5)) of commands
++commands) are put in the environment (see \fIenviron\fP(7)) of commands
+ run by the shell as \fIname\fP\fB=\fP\fIvalue\fP pairs.
+ The order in which parameters appear in the environment of a command
+ is unspecified.
+@@ -1119,12 +1119,12 @@
+ like \fB[\fP..\fB]\fP, except it matches any character not inside the brackets.
+ .ksh(
+ .IP "\fB*(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP"
+-matches any string of characters that matches zero or more occurances
++matches any string of characters that matches zero or more occurrences
+ of the specified patterns.
+ Example: the pattern \fB*(foo|bar)\fP matches the strings
+ `', `foo', `bar', `foobarfoo', \fIetc.\fP.
+ .IP "\fB+(\fP\fIpattern\fP\fB|\fP ... \fP|\fP\fIpattern\fP\fB)\fP"
+-matches any string of characters that matches one or more occurances
++matches any string of characters that matches one or more occurrences
+ of the specified patterns.
+ Example: the pattern \fB+(foo|bar)\fP matches the strings
+ `foo', `bar', `foobarfoo', \fIetc.\fP.
+@@ -1306,8 +1306,8 @@
+ When used as a prefix operator, the result is the incremented value of
+ the parameter, when used as a postfix operator, the result is the
+ original value of the parameter.
+-.IP "\fB++\fP"
+-similar to \fB++\fP, except the paramter is decremented by 1.
++.IP "\fB--\fP"
++similar to \fB++\fP, except the parameter is decremented by 1.
+ .IP "\fB,\fP"
+ separates two arithmetic expressions; the left hand side is evaluated first,
+ then the right. The result is value of the expression on the right hand side.
+@@ -1383,7 +1383,7 @@
+ This can be avoided by redirecting the output to a numbered
+ file descriptor (as this also causes the shell to close its copy).
+ Note that this behaviour is slightly different from the original Korn shell
+-which closes its copy of the write portion of the co-processs output when the
++which closes its copy of the write portion of the co-process's output when the
+ most recently started co-process (instead of when all sharing co-processes)
+ exits.
+ .IP \ \ \(bu
+@@ -1450,7 +1450,7 @@
+ the \fB$0\fP parameter is set to the name of the function
+ (Bourne-style functions leave \fB$0\fP untouched).
+ .IP \ \ \(bu
+-parameter assignments preceeding function calls are not kept in
++parameter assignments preceding function calls are not kept in
+ the shell environment
+ (executing Bourne-style functions will keep assignments).
+ .IP \ \ \(bu
+@@ -1540,6 +1540,10 @@
+ For example, `\fBset \-\- `false`; echo $?\fP' prints 0 in posix mode,
+ 1 in non-posix mode. This construct is used in most shell scripts that
+ use the old \fIgetopt\fP(1) command.
++.br
++(\fBDEBIAN NOTE\fP: This is no longer true on Debian systems. For compatibility
++with ksh93, \fBset\fP command always returns exit status set to 0, regardless
++of posix or non-posix mode.)
+ .IP \ \ \(bu
+ argument expansion of \fBalias\fP, \fBexport\fP, \fBreadonly\fP, and
+ \fBtypeset\fP commands: in posix mode, normal argument expansion done;
+@@ -1585,7 +1589,7 @@
+ Just to confuse things, if the posix option is turned off (see \fBset\fP
+ command below) some special commands are very special in that
+ no field splitting, file globing, brace expansion nor tilde expansion
+-is preformed on arguments that look like assignments.
++is performed on arguments that look like assignments.
+ Regular built-in commands are different only in that the \fBPATH\fP
+ parameter is not used to find them.
+ .PP
+@@ -1644,7 +1648,7 @@
+ Exit status is set to zero.
+ .\"}}}
+ .\"{{{ alias [ -d | +-t [ -r ] ] [+-px] [+-] [name1[=value1] ...]
+-.IP "\fBalias\fP [ \fB\-d\fP | \fB\(+-t\fP [\fB\-r\fP] ] [\fB\(+-px\fP] [\fB\(+-\fP] [\fIname1\fP[\fB=\fP\fIvalue1\fP] ...]"
++.IP "\fBalias\fP [ \fB\-d\fP | \fB+\-t\fP [\fB\-r\fP] ] [\fB+\-px\fP] [\fB+\-\fP] [\fIname1\fP[\fB=\fP\fIvalue1\fP] ...]"
+ Without arguments, \fBalias\fP lists all aliases.
+ For any name without a value, the existing alias is listed.
+ Any name with a value defines an alias (see Aliases above).
+@@ -1694,7 +1698,7 @@
+ .IP "\fBcd\fP [\fB\-LP\fP] [\fIdir\fP]"
+ Set the working directory to \fIdir\fP. If the parameter \fBCDPATH\fP
+ is set, it lists directories to search in for \fIdir\fP.
+-\fIdir\fP. An empty entry in the \fBCDPATH\fP entry means the current
++An empty entry in the \fBCDPATH\fP entry means the current
+ directory.
+ If a non-empty directory from \fBCDPATH\fP is used, the resulting full
+ path is printed to standard output.
+@@ -1788,6 +1792,9 @@
+ commands that are not built-in to the shell).
+ Note that the Bourne shell differs here: it does pass these
+ file descriptors on.
++.br
++(\fBDEBIAN NOTE\fP: when the shell is called as \fI/bin/sh\fP, it does pass
++these file descriptors on, like the Bourne shell.)
+ .ksh)
+ .sh(
+ Any file descriptors which are opened or \fIdup\fP(2)-ed
+@@ -2008,12 +2015,12 @@
+ while the original Korn shell only treats profiles as \fB.\fP scripts.
+ .\"}}}
+ .\"{{{ set [+-abCefhkmnpsuvxX] [+-o [option]] [+-A name] [--] [arg ...]
+-.IP "\fBset\fP [\fB\(+-abCefhkmnpsuvxX\fP] [\fB\(+-o\fP [\fIoption\fP]] [\fB\(+-A\fP \fIname\fP] [\fB\-\-\fP] [\fIarg\fP ...]"
++.IP "\fBset\fP [\fB+\-abCefhkmnpsuvxX\fP] [\fB+\-o\fP [\fIoption\fP]] [\fB+\-A\fP \fIname\fP] [\fB\-\-\fP] [\fIarg\fP ...]"
+ The set command can be used to set (\fB\-\fP) or clear (\fB+\fP) shell options,
+ set the positional parameters, or set an array parameter.
+-Options can be changed using the \fB\(+-o\fP \fIoption\fP syntax,
++Options can be changed using the \fB+\-o\fP \fIoption\fP syntax,
+ where \fIoption\fP is the long name of an option, or using
+-the \fB\(+-\fP\fIletter\fP syntax, where \fIletter\fP is the
++the \fB+\-\fP\fIletter\fP syntax, where \fIletter\fP is the
+ option's single letter name (not all options have a single letter name).
+ The following table lists both option letters (if they exist) and long names
+ along with a description of what the option does.
+@@ -2144,7 +2151,7 @@
+ Causes the \fBcd\fP and \fBpwd\fP commands to use `physical'
+ (\fIi.e.\fP, the filesystem's) \fB..\fP directories instead of `logical'
+ directories (\fIi.e.\fP, the shell handles \fB..\fP, which allows the user
+-to be obliveous of symlink links to directories).
++to be oblivious of symlink links to directories).
+ Clear by default. Note that setting
+ this option does not effect the current value of the \fBPWD\fP parameter;
+ only the \fBcd\fP command changes \fBPWD\fP.
+@@ -2153,6 +2160,10 @@
+ posix T{
+ Enable posix mode. See POSIX Mode above.
+ T}
++ sh T{
++This option is set only when ksh was called as a standard \fI/bin/sh\fP shell.
++(Note: This option is a Debian and OpenBSD addition).
++T}
+ vi T{
+ Enable vi-like command line editing (interactive shells only).
+ T}
+@@ -2419,7 +2430,7 @@
+ are received.
+ \fBHandler\fP is either a null string, indicating the signals are to
+ be ignored, a minus (\fB\-\fP), indicating that the default action is to
+-be taken for the signals (see signal(2 or 3)), or a string containing shell
++be taken for the signals (see signal(2)), or a string containing shell
+ commands to be evaluated and executed at the first opportunity (\fIi.e.\fP,
+ when the current command completes, or before printing the next \fBPS1\fP
+ prompt) after receipt of one of the signals.
+@@ -2450,7 +2461,7 @@
+ A command that exits with a zero value.
+ .\"}}}
+ .\"{{{ typeset [[+-Ulprtux] [-L[n]] [-R[n]] [-Z[n]] [-i[n]] | -f [-tux]] [name[=value] ...]
+-.IP "\fBtypeset\fP [[\(+-Ulprtux] [\fB\-L\fP[\fIn\fP]] [\fB\-R\fP[\fIn\fP]] [\fB\-Z\fP[\fIn\fP]] [\fB\-i\fP[\fIn\fP]] | \fB\-f\fP [\fB\-tux\fP]] [\fIname\fP[\fB=\fP\fIvalue\fP] ...]"
++.IP "\fBtypeset\fP [[+\-Ulprtux] [\fB\-L\fP[\fIn\fP]] [\fB\-R\fP[\fIn\fP]] [\fB\-Z\fP[\fIn\fP]] [\fB\-i\fP[\fIn\fP]] | \fB\-f\fP [\fB\-tux\fP]] [\fIname\fP[\fB=\fP\fIvalue\fP] ...]"
+ Display or set parameter attributes.
+ With no \fIname\fP arguments, parameter attributes are displayed: if no options
+ arg used, the current attributes of all parameters are printed as typeset
+@@ -2517,7 +2528,7 @@
+ \-p T{
+ Print complete typeset commands that can be used to re-create the
+ attributes (but not the values) of parameters.
+-This is the default action (option exists for ksh93 compatability).
++This is the default action (option exists for ksh93 compatibility).
+ T}
+ \-r T{
+ Readonly attribute: parameters with the this attribute may not be assigned to
+@@ -2546,8 +2557,8 @@
+ T}
+ .TE
+ .\"}}}
+-.\"{{{ ulimit [-acdfHlmnpsStvw] [value]
+-.IP "\fBulimit\fP [\fB\-acdfHlmnpsStvw\fP] [\fIvalue\fP]"
++.\"{{{ ulimit [-acdfHlmnpsStvwL] [value]
++.IP "\fBulimit\fP [\fB\-acdfHlmnpsStvwL\fP] [\fIvalue\fP]"
+ Display or set process limits.
+ If no options are used, the file size limit (\fB\-f\fP) is assumed.
+ \fBvalue\fP, if specified, may be either be an arithmetic expression or the
+@@ -2592,6 +2603,8 @@
+ not kbytes).
+ .IP \fB\-w\fP
+ Impose a limit of \fIn\fP kbytes on the amount of swap space used.
++.IP \fB\-L\fP
++Impose a limit of \fIn\fP locks that can be held on files.
+ .PP
+ As far as \fBulimit\fP is concerned, a block is 512 bytes.
+ .RE
+@@ -3091,12 +3104,12 @@
+ .\"}}}
+ .\"{{{ search-character-backward n ^[^]
+ .IP "\fBsearch-character-backward\fP \fIn\fP \fB^[^]\fP"
+-Search backward in the current line for the \fIn\fPth occurance of the
++Search backward in the current line for the \fIn\fPth occurrence of the
+ next character typed.
+ .\"}}}
+ .\"{{{ search-character-forward n ^]
+ .IP "\fBsearch-character-forward\fP \fIn\fP \fB^]\fP"
+-Search forward in the current line for the \fIn\fPth occurance of the
++Search forward in the current line for the \fIn\fPth occurrence of the
+ next character typed.
+ .\"}}}
+ .\"{{{ search-history ^R
+@@ -3523,7 +3536,7 @@
+ csh(1), ed(1), getconf(1), getopt(1), sed(1), stty(1), vi(1),
+ dup(2), execve(2), getgid(2), getuid(2), open(2), pipe(2), wait(2),
+ getopt(3), rand(3), signal(3), system(3),
+-environ(5)
++environ(7)
+ .PP
+ .IR "The KornShell Command and Programming Language" ,
+ Morris Bolsky and David Korn, 1989, ISBN 0-13-516972-0.
+@@ -3535,3 +3548,4 @@
+ .IR "IEEE Standard for information Technology \- Portable Operating System Interface (POSIX) \- Part 2: Shell and Utilities" ,
+ IEEE Inc, 1993, ISBN 1-55937-255-9.
+ .\"}}}
++.\" vim:ft=nroff
diff --git a/system/pdksh/patches/101_PLD-pdksh-EDITMODE.patch b/system/pdksh/patches/101_PLD-pdksh-EDITMODE.patch
new file mode 100644
index 0000000000..f40d572804
--- /dev/null
+++ b/system/pdksh/patches/101_PLD-pdksh-EDITMODE.patch
@@ -0,0 +1,92 @@
+add EDITMODE variable
+(from PLD)
+
+Index: pdksh-5.2.14/ksh.Man
+===================================================================
+--- pdksh-5.2.14.orig/ksh.Man 2009-09-16 23:24:45.000000000 +0200
++++ pdksh-5.2.14/ksh.Man 2009-09-16 23:24:49.000000000 +0200
+@@ -791,13 +791,21 @@
+ \fBselect\fP, \fBset \-o\fP and \fBkill \-l\fP commands
+ to format information in columns.
+ .\"}}}
++.\"{{{ EDITMODE
++.ksh(
++.IP \fBEDITMODE\fP
++If set, this parameter controls the command line editing mode for
++interactive shells. If the last component of the path specified in this
++parameter contains the string \fBvi\fP, \fBemacs\fP or \fBgmacs\fP, the
++vi, emacs or gmacs (Gosling emacs) editing mode is enabled, respectively.
++.\"}}}
++.ksh)
+ .\"{{{ EDITOR
+ .ksh(
+ .IP \fBEDITOR\fP
+ If the \fBVISUAL\fP parameter is not set, this parameter controls the
+ command line editing mode for interactive shells.
+-See \fBVISUAL\fP parameter below for how this works.
+-.ksh)
++See \fBEDITMODE\fP parameter above for how this works.
+ .\"}}}
+ .\"{{{ ENV
+ .IP \fBENV\fP
+@@ -1044,7 +1052,7 @@
+ .\"{{{ VISUAL
+ .ksh(
+ .IP \fBVISUAL\fP
+-If set, this parameter controls the command line editing mode for
++If set, and \fBEDITMODE\fP is unset, this parameter controls the command line editing mode for
+ interactive shells. If the last component of the path specified in this
+ parameter contains the string \fBvi\fP, \fBemacs\fP or \fBgmacs\fP, the
+ vi, emacs or gmacs (Gosling emacs) editing mode is enabled, respectively.
+Index: pdksh-5.2.14/table.h
+===================================================================
+--- pdksh-5.2.14.orig/table.h 2009-09-16 23:24:45.000000000 +0200
++++ pdksh-5.2.14/table.h 2009-09-16 23:24:49.000000000 +0200
+@@ -168,6 +168,7 @@
+ #define V_TMOUT 15
+ #define V_TMPDIR 16
+ #define V_LINENO 17
++#define V_EDITMODE 18
+
+ /* values for set_prompt() */
+ #define PS1 0 /* command */
+Index: pdksh-5.2.14/var.c
+===================================================================
+--- pdksh-5.2.14.orig/var.c 2009-09-16 23:24:45.000000000 +0200
++++ pdksh-5.2.14/var.c 2009-09-16 23:24:49.000000000 +0200
+@@ -95,6 +95,7 @@
+ #endif /* HISTORY */
+ #ifdef EDIT
+ { "EDITOR", V_EDITOR },
++ { "EDITMODE", V_EDITMODE },
+ { "VISUAL", V_VISUAL },
+ #endif /* EDIT */
+ #ifdef KSH
+@@ -111,7 +112,7 @@
+ int i;
+ struct tbl *tp;
+
+- tinit(&specials, APERM, 32); /* must be 2^n (currently 17 specials) */
++ tinit(&specials, APERM, 32); /* must be 2^n (currently 18 specials) */
+ for (i = 0; names[i].name; i++) {
+ tp = tenter(&specials, names[i].name, hash(names[i].name));
+ tp->flag = DEFINED|ISSET;
+@@ -1017,11 +1018,15 @@
+ #endif /* HISTORY */
+ #ifdef EDIT
+ case V_VISUAL:
+- set_editmode(str_val(vp));
++ if (!(global("EDITMODE")->flag & ISSET))
++ set_editmode(str_val(vp));
+ break;
+ case V_EDITOR:
+- if (!(global("VISUAL")->flag & ISSET))
+- set_editmode(str_val(vp));
++ if (!(global("EDITMODE")->flag & ISSET))
++ if(!(global("VISUAL")->flag & ISSET))
++ set_editmode(str_val(vp));
++ case V_EDITMODE:
++ set_editmode(str_val(vp));
+ break;
+ case V_COLUMNS:
+ if ((x_cols = intval(vp)) <= MIN_COLS)
diff --git a/system/pdksh/patches/102_PLD-pdksh-ulimit-vmem.patch b/system/pdksh/patches/102_PLD-pdksh-ulimit-vmem.patch
new file mode 100644
index 0000000000..483226c7a3
--- /dev/null
+++ b/system/pdksh/patches/102_PLD-pdksh-ulimit-vmem.patch
@@ -0,0 +1,18 @@
+support for `ulimit -v'
+(from PLD)
+
+Index: pdksh-5.2.14/c_ulimit.c
+===================================================================
+--- pdksh-5.2.14.orig/c_ulimit.c 2008-04-15 20:50:48.000000000 +0200
++++ pdksh-5.2.14/c_ulimit.c 2008-04-15 20:55:52.000000000 +0200
+@@ -38,6 +38,10 @@
+ # define KSH_RLIM_INFINITY ((rlim_t) 1 << (sizeof(rlim_t) * 8 - 1) - 1)
+ #endif /* RLIM_INFINITY */
+
++#if !defined(RLIMIT_VMEM) && defined(RLIMIT_AS)
++# define RLIMIT_VMEM RLIMIT_AS
++#endif
++
+ int
+ c_ulimit(wp)
+ char **wp;
diff --git a/system/pdksh/patches/103_PLD-pdksh-unset.patch b/system/pdksh/patches/103_PLD-pdksh-unset.patch
new file mode 100644
index 0000000000..9f17b9409b
--- /dev/null
+++ b/system/pdksh/patches/103_PLD-pdksh-unset.patch
@@ -0,0 +1,26 @@
+unset on unknown variable is not an error,
+see http://www.opengroup.org/onlinepubs/009695399/utilities/unset.html
+(from PLD)
+
+Index: pdksh-5.2.14/c_sh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_sh.c 2008-04-15 20:51:18.000000000 +0200
++++ pdksh-5.2.14/c_sh.c 2008-04-15 20:56:22.000000000 +0200
+@@ -688,16 +688,13 @@
+ if (unset_var) { /* unset variable */
+ struct tbl *vp = global(id);
+
+- if (!(vp->flag & ISSET))
+- ret = 1;
+ if ((vp->flag&RDONLY)) {
+ bi_errorf("%s is read only", vp->name);
+ return 1;
+ }
+ unset(vp, strchr(id, '[') ? 1 : 0);
+ } else { /* unset function */
+- if (define(id, (struct op *) NULL))
+- ret = 1;
++ define(id, (struct op *) NULL);
+ }
+ return ret;
+ }
diff --git a/system/pdksh/patches/104_Debian-#415167-lack-of-dot-arguments.patch b/system/pdksh/patches/104_Debian-#415167-lack-of-dot-arguments.patch
new file mode 100644
index 0000000000..ee3eca2ff0
--- /dev/null
+++ b/system/pdksh/patches/104_Debian-#415167-lack-of-dot-arguments.patch
@@ -0,0 +1,22 @@
+unset on unknown variable is not an error,
+see http://www.opengroup.org/onlinepubs/009695399/utilities/unset.html
+(from PLD)
+
+@DPATCH@
+Index: pdksh-5.2.14/c_sh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_sh.c 2008-04-15 20:56:22.000000000 +0200
++++ pdksh-5.2.14/c_sh.c 2008-04-15 20:56:53.000000000 +0200
+@@ -183,8 +183,10 @@
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+
+- if ((cp = wp[builtin_opt.optind]) == NULL)
+- return 0;
++ if ((cp = wp[builtin_opt.optind]) == NULL) {
++ bi_errorf("missing argument");
++ return 1;
++ }
+ file = search(cp, path, R_OK, &err);
+ if (file == NULL) {
+ bi_errorf("%s: %s", cp, err ? strerror(err) : "not found");
diff --git a/system/pdksh/patches/105_OpenBSD-heredoc-quote.patch b/system/pdksh/patches/105_OpenBSD-heredoc-quote.patch
new file mode 100644
index 0000000000..1cb8577437
--- /dev/null
+++ b/system/pdksh/patches/105_OpenBSD-heredoc-quote.patch
@@ -0,0 +1,53 @@
+Fix for `Bug#219343 backslash is swallowed in HERE document' from OpenBSD:
+ * exec.c (1.42), lex.c (1.37), lex.h (1.10): Fix " handling in here
+ documents. POSIX says they are not special, so cat << EOF \" EOF
+ should print \" Fixes PR 4472; testing jmc@ and Adam Montague. ok
+(from OpenBSD)
+
+Index: pdksh-5.2.14/exec.c
+===================================================================
+--- pdksh-5.2.14.orig/exec.c 2009-09-17 00:32:31.000000000 +0200
++++ pdksh-5.2.14/exec.c 2009-09-17 00:32:59.000000000 +0200
+@@ -1480,7 +1480,7 @@
+ s = pushs(SSTRING, ATEMP);
+ s->start = s->str = content;
+ source = s;
+- if (yylex(ONEWORD) != LWORD)
++ if (yylex(ONEWORD|HEREDOC) != LWORD)
+ internal_errorf(1, "herein: yylex");
+ source = osource;
+ shf_puts(evalstr(yylval.cp, 0), shf);
+Index: pdksh-5.2.14/lex.c
+===================================================================
+--- pdksh-5.2.14.orig/lex.c 2009-09-17 00:32:52.000000000 +0200
++++ pdksh-5.2.14/lex.c 2009-09-17 00:32:59.000000000 +0200
+@@ -240,10 +240,16 @@
+ case '\\':
+ c = getsc();
+ switch (c) {
+- case '"': case '\\':
++ case '\\':
+ case '$': case '`':
+ *wp++ = QCHAR, *wp++ = c;
+ break;
++ case '"':
++ if ((cf & HEREDOC) == 0) {
++ *wp++ = QCHAR, *wp++ = c;
++ break;
++ }
++ /* FALLTROUGH */
+ default:
+ Xcheck(ws, wp);
+ if (c) { /* trailing \ is lost */
+Index: pdksh-5.2.14/lex.h
+===================================================================
+--- pdksh-5.2.14.orig/lex.h 2009-09-17 00:31:55.000000000 +0200
++++ pdksh-5.2.14/lex.h 2009-09-17 00:32:59.000000000 +0200
+@@ -113,6 +113,7 @@
+ #define ESACONLY BIT(7) /* only accept esac keyword */
+ #define CMDWORD BIT(8) /* parsing simple command (alias related) */
+ #define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
++#define HEREDOC BIT(10) /* parsing heredoc */
+
+ #define HERES 10 /* max << in line */
+
diff --git a/system/pdksh/patches/106_Debian-man-hyphens.patch b/system/pdksh/patches/106_Debian-man-hyphens.patch
new file mode 100644
index 0000000000..f541719fc9
--- /dev/null
+++ b/system/pdksh/patches/106_Debian-man-hyphens.patch
@@ -0,0 +1,59 @@
+Quote '-' chars in man page to make lintian happy.
+Index: pdksh-5.2.14/ksh.Man
+===================================================================
+--- pdksh-5.2.14.orig/ksh.Man 2009-07-18 15:18:29.000000000 +0200
++++ pdksh-5.2.14/ksh.Man 2009-07-18 15:18:30.000000000 +0200
+@@ -445,7 +445,7 @@
+ the \fB&&\fP and \fB||\fP operators.
+ This means that in the statement
+ .ce
+-\fB[[ -r foo && $(< foo) = b*r ]]\fP
++\fB[[ \-r foo && $(< foo) = b*r ]]\fP
+ the \fB$(< foo)\fP is evaluated if and only if the file \fBfoo\fP exists
+ and is readable.
+ .nr PD \n(P2
+@@ -2092,7 +2092,7 @@
+ See Shell Startup above for a description of what this
+ means.
+ T}
+--r restricted T{
++\-r restricted T{
+ Enable restricted mode \(em this option can only be used when the shell is
+ invoked. See Shell Startup above for a description of what this
+ means.
+@@ -2198,7 +2198,7 @@
+ These options can also be used upon invocation of the shell. The current
+ set of options (with single letter names) can be found in the
+ parameter \fB\-\fP.
+-\fBset -o\fP with no option name will list all the options and whether each
++\fBset \-o\fP with no option name will list all the options and whether each
+ is on or off; \fBset +o\fP will print the long names of all options that
+ are currently on.
+ .sp
+@@ -2303,7 +2303,7 @@
+ As a non-standard extension, if the option starts with a \fB!\fP, the test
+ is negated; the test always fails if option doesn't exist (thus
+ .RS
+-\fB[ -o \fP\fIfoo\fP \fB-o -o !\fP\fIfoo\fP \fB]\fP
++\fB[ \-o \fP\fIfoo\fP \fB\-o \-o !\fP\fIfoo\fP \fB]\fP
+ .RE
+ returns true if and only if option \fIfoo\fP exists).
+ T}
+@@ -2380,7 +2380,7 @@
+ (where \fIn\fP is a file descriptor number),
+ the \fBtest\fP command will attempt to fake it for all tests that
+ operate on files (except the \fB-e\fP test).
+-I.e., \fB[ -w /dev/fd/2 ]\fP tests if file descriptor 2 is writable.
++I.e., \fB[ \-w /dev/fd/2 ]\fP tests if file descriptor 2 is writable.
+ .sp
+ Note that some special rules are applied (courtesy of POSIX) if the
+ number of arguments to \fBtest\fP or \fB[\fP \&... \fB]\fP is less than
+@@ -2410,7 +2410,7 @@
+ .nf
+ 0.00s real 0.00s user 0.00s system
+ .fi
+-unless the -p option is given (only possible if \fIpipeline\fP is a simple
++unless the \-p option is given (only possible if \fIpipeline\fP is a simple
+ command), in which case the output is slightly longer:
+ .nf
+ real 0.00
diff --git a/system/pdksh/patches/107_Debian-gcc-warnings2.patch b/system/pdksh/patches/107_Debian-gcc-warnings2.patch
new file mode 100644
index 0000000000..ea46ecb162
--- /dev/null
+++ b/system/pdksh/patches/107_Debian-gcc-warnings2.patch
@@ -0,0 +1,23 @@
+Fix gcc warnings.
+Index: pdksh-5.2.14/eval.c
+===================================================================
+--- pdksh-5.2.14.orig/eval.c 2008-04-15 21:11:04.000000000 +0200
++++ pdksh-5.2.14/eval.c 2008-04-15 21:15:24.000000000 +0200
+@@ -201,6 +201,8 @@
+ word = (f&DOBLANK) ? IFS_WS : IFS_WORD;
+ st_head.next = (SubType *) 0;
+ st = &st_head;
++ x.split = 0;
++ x.str = NULL;
+
+ while (1) {
+ Xcheck(ds, dp);
+@@ -280,7 +282,7 @@
+ {
+ char *varname = ++sp; /* skip the { or x (}) */
+ int stype;
+- int slen;
++ int slen = 0;
+
+ sp = strchr(sp, '\0') + 1; /* skip variable */
+ type = varsub(&x, varname, sp, &stype, &slen);
diff --git a/system/pdksh/patches/108_Debian-sysconf_retval_check.patch b/system/pdksh/patches/108_Debian-sysconf_retval_check.patch
new file mode 100644
index 0000000000..c0a710a90a
--- /dev/null
+++ b/system/pdksh/patches/108_Debian-sysconf_retval_check.patch
@@ -0,0 +1,41 @@
+Fix `internal error: j_async: bad nzombie (0)' that occured with `sudo pdksh -c "sleep 10&"'
+
+Sudo sets RLIMIT_NPROC to unlimited, and sysconf returns that value as -1.
+Index: pdksh-5.2.14/jobs.c
+===================================================================
+--- pdksh-5.2.14.orig/jobs.c 2008-05-26 21:46:41.000000000 +0200
++++ pdksh-5.2.14/jobs.c 2008-05-26 21:56:12.000000000 +0200
+@@ -174,9 +174,9 @@
+ static Job *async_job;
+ static pid_t async_pid;
+
+-static int nzombie; /* # of zombies owned by this process */
++static long nzombie; /* # of zombies owned by this process */
+ static INT32 njobs; /* # of jobs started */
+-static int child_max; /* CHILD_MAX */
++static long child_max; /* CHILD_MAX */
+
+
+ #ifdef JOB_SIGS
+@@ -227,6 +227,12 @@
+ int mflagset;
+ {
+ child_max = CHILD_MAX; /* so syscon() isn't always being called */
++#if defined(HAVE_SYSCONF) && defined(_SC_CHILD_MAX)
++ if (child_max < 0) {
++ child_max = LONG_MAX;
++ }
++#endif
++
+
+ #ifdef JOB_SIGS
+ sigemptyset(&sm_default);
+@@ -1131,7 +1137,7 @@
+ if (!oldest) {
+ /* XXX debugging */
+ if (!(async_job->flags & JF_ZOMBIE) || nzombie != 1) {
+- internal_errorf(0, "j_async: bad nzombie (%d)", nzombie);
++ internal_errorf(0, "j_async: bad nzombie (%ld)", nzombie);
+ nzombie = 0;
+ }
+ break;
diff --git a/system/pdksh/patches/109_mksh-delete_key.patch b/system/pdksh/patches/109_mksh-delete_key.patch
new file mode 100644
index 0000000000..b061758114
--- /dev/null
+++ b/system/pdksh/patches/109_mksh-delete_key.patch
@@ -0,0 +1,115 @@
+Patch from mksh to make delete key work (closes: #190566)
+Index: pdksh-5.2.14/emacs.c
+===================================================================
+--- pdksh-5.2.14.orig/emacs.c 2009-09-15 20:59:29.000000000 +0200
++++ pdksh-5.2.14/emacs.c 2009-09-15 21:06:50.000000000 +0200
+@@ -327,6 +327,26 @@
+ { XFUNC_next_com, 2, 'B' },
+ { XFUNC_mv_forw, 2, 'C' },
+ { XFUNC_mv_back, 2, 'D' },
++ /* These for ansi arrow keys: arguablely shouldn't be here by
++ * default, but its simpler/faster/smaller than using termcap
++ * entries.
++ */
++ { XFUNC_meta2, 1, '[' },
++ { XFUNC_meta2, 1, 'O' },
++ { XFUNC_prev_com, 2, 'A' },
++ { XFUNC_next_com, 2, 'B' },
++ { XFUNC_mv_forw, 2, 'C' },
++ { XFUNC_mv_back, 2, 'D' },
++ { XFUNC_mv_begin | 0x80, 2, '1' },
++ { XFUNC_mv_begin | 0x80, 2, '7' },
++ { XFUNC_mv_begin, 2, 'H' },
++ { XFUNC_mv_end | 0x80, 2, '4' },
++ { XFUNC_mv_end | 0x80, 2, '8' },
++ { XFUNC_mv_end, 2, 'F' },
++ { XFUNC_del_char | 0x80, 2, '3' },
++ { XFUNC_prev_com | 0x80, 2, '5' },
++ { XFUNC_next_com | 0x80, 2, '6' },
++
+ };
+
+ int
+@@ -371,7 +391,14 @@
+ return 0;
+
+ f = x_curprefix == -1 ? XFUNC_insert
+- : x_tab[x_curprefix][c&CHARMASK];
++ : x_tab[x_curprefix][c&CHARMASK] ;
++
++ if (f & 0x80) {
++ f &= 0x7F;
++ if ((i = x_e_getc()) != '~')
++ x_e_ungetc(i);
++ }
++
+
+ if (!(x_ftab[f].xf_flags & XF_PREFIX)
+ && x_last_command != XFUNC_set_arg)
+@@ -1385,6 +1412,7 @@
+ x_print(prefix, key)
+ int prefix, key;
+ {
++ int f = x_tab[prefix][key];
+ if (prefix == 1)
+ shprintf("%s", x_mapout(x_prefix1));
+ if (prefix == 2)
+@@ -1393,9 +1421,9 @@
+ if (prefix == 3)
+ shprintf("%s", x_mapout(x_prefix3));
+ #endif /* OS2 */
+- shprintf("%s = ", x_mapout(key));
+- if (x_tab[prefix][key] != XFUNC_ins_string)
+- shprintf("%s\n", x_ftab[x_tab[prefix][key]].xf_name);
++ shprintf("%s%s = ", x_mapout(key), (f & 0x80) ? "~" : "");
++ if ((f & 0x7F) != XFUNC_ins_string)
++ shprintf("%s\n", x_ftab[f & 0x7F].xf_name);
+ else
+ shprintf("'%s'\n", x_atab[prefix][key]);
+ }
+@@ -1410,6 +1438,7 @@
+ int prefix, key;
+ char *sp = NULL;
+ char *m1, *m2;
++ char hastilde;
+
+ if (x_tab == NULL) {
+ bi_errorf("cannot bind, not a tty");
+@@ -1437,7 +1466,7 @@
+ return 0;
+ }
+
+- m1 = x_mapin(a1);
++ m2 = m1 = x_mapin(a1);
+ prefix = key = 0;
+ for (;; m1++) {
+ key = *m1 & CHARMASK;
+@@ -1453,6 +1482,19 @@
+ break;
+ }
+
++ if (*++m1 && ((*m1 != '~') || *(m1+1))) {
++ char msg[256] = "key sequence '";
++ const char *c = a1;
++ m1 = msg + strlen(msg);
++ while (*c && m1 < (msg + sizeof(msg) - 3))
++ strcat(msg, x_mapout(*c++));
++ bi_errorf("%s' too long", msg);
++ return (1);
++ }
++
++ hastilde = *m1;
++ afree(m2, ATEMP);
++
+ if (a2 == NULL) {
+ x_print(prefix, key);
+ return 0;
+@@ -1483,7 +1525,7 @@
+
+ if (x_tab[prefix][key] == XFUNC_ins_string && x_atab[prefix][key])
+ afree((void *)x_atab[prefix][key], AEDIT);
+- x_tab[prefix][key] = f;
++ x_tab[prefix][key] = f | (hastilde ? 0x80 : 0);
+ x_atab[prefix][key] = sp;
+
+ /* Track what the user has bound so x_emacs_keys() won't toast things */
diff --git a/system/pdksh/patches/110_Debian-exit-negative-number.patch b/system/pdksh/patches/110_Debian-exit-negative-number.patch
new file mode 100644
index 0000000000..d7af113275
--- /dev/null
+++ b/system/pdksh/patches/110_Debian-exit-negative-number.patch
@@ -0,0 +1,46 @@
+Fix problem with `exit -1' giving `ksh: exit: -1: unknown option' (see bug#502934)
+
+Index: pdksh-5.2.14/c_sh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_sh.c 2009-09-19 11:38:39.000000000 +0200
++++ pdksh-5.2.14/c_sh.c 2009-09-19 11:39:33.000000000 +0200
+@@ -534,9 +534,14 @@
+ int n;
+ char *arg;
+
+- if (ksh_getopt(wp, &builtin_opt, null) == '?')
+- return 1;
+- arg = wp[builtin_opt.optind];
++ if (!Flag(FPOSIX) // not posix
++ && *wp && *(wp + 1) && !*(wp + 2)) // only one argument passed
++ arg=*(wp + 1); // code regardless of starting with '-' or not
++ else {
++ if (ksh_getopt(wp, &builtin_opt, null) == '?')
++ return 1;
++ arg = wp[builtin_opt.optind];
++ }
+
+ if (arg) {
+ if (!getn(arg, &n)) {
+Index: pdksh-5.2.14/tests/debian-110.t
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ pdksh-5.2.14/tests/debian-110.t 2009-09-19 11:41:59.000000000 +0200
+@@ -0,0 +1,17 @@
++name: debian-110-1
++description:
++ Check if exit -1 is allowed for ! posix
++stdin:
++ (set +o posix; exit -1); echo A $?
++expected-stdout:
++ A 255
++---
++name: debian-110-2
++description:
++ Check if exit -1 is not allowed for posix
++stdin:
++ (set -o posix; exit -1); echo A $?
++expected-stdout:
++ A 1
++expected-fail: yes
++---
diff --git a/system/pdksh/patches/111_mksh-set-e.patch b/system/pdksh/patches/111_mksh-set-e.patch
new file mode 100644
index 0000000000..ca6f42b18f
--- /dev/null
+++ b/system/pdksh/patches/111_mksh-set-e.patch
@@ -0,0 +1,422 @@
+Fix `set -e' handling from mksh (see bugs #71256, #546332, closes: #387755).
+Index: pdksh-5.2.14/exec.c
+===================================================================
+--- pdksh-5.2.14.orig/exec.c 2009-09-19 11:54:58.000000000 +0200
++++ pdksh-5.2.14/exec.c 2009-09-19 11:55:01.000000000 +0200
+@@ -15,7 +15,7 @@
+ #endif /* KSH */
+
+ static int comexec ARGS((struct op *t, struct tbl *volatile tp, char **ap,
+- int volatile flags));
++ int volatile flags, volatile int * volatile xerrok));
+ static void scriptexec ARGS((struct op *tp, char **ap));
+ static int call_builtin ARGS((struct tbl *tp, char **wp));
+ static int iosetup ARGS((struct ioword *iop, struct tbl *tp));
+@@ -70,12 +70,13 @@
+ * execute command tree
+ */
+ int
+-execute(t, flags)
++execute(t, flags, xerrok)
+ struct op * volatile t;
+ volatile int flags; /* if XEXEC don't fork */
++ volatile int * volatile xerrok;
+ {
+ int i;
+- volatile int rv = 0;
++ volatile int rv = 0, dummy = 0;
+ int pv[2];
+ char ** volatile ap;
+ char *s, *cp;
+@@ -85,6 +86,10 @@
+ if (t == NULL)
+ return 0;
+
++ /* Caller doesn't care if XERROK should propagate. */
++ if (xerrok == NULL)
++ xerrok = &dummy;
++
+ /* Is this the end of a pipeline? If so, we want to evaluate the
+ * command arguments
+ bool_t eval_done = FALSE;
+@@ -94,7 +99,7 @@
+ }
+ */
+ if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
+- return exchild(t, flags & ~XTIME, -1); /* run in sub-process */
++ return exchild(t, flags & ~XTIME, xerrok, -1); /* run in sub-process */
+
+ newenv(E_EXEC);
+ if (trap)
+@@ -152,11 +157,11 @@
+
+ switch(t->type) {
+ case TCOM:
+- rv = comexec(t, tp, ap, flags);
++ rv = comexec(t, tp, ap, flags, xerrok);
+ break;
+
+ case TPAREN:
+- rv = execute(t->left, flags|XFORK);
++ rv = execute(t->left, flags|XFORK, xerrok);
+ break;
+
+ case TPIPE:
+@@ -173,7 +178,7 @@
+ * (: ; cat /etc/termcap) | sleep 1
+ * will hang forever).
+ */
+- exchild(t->left, flags|XPIPEO|XCCLOSE, pv[0]);
++ exchild(t->left, flags|XPIPEO|XCCLOSE, NULL, pv[0]);
+ (void) ksh_dup2(pv[0], 0, FALSE); /* stdin of next */
+ closepipe(pv);
+ flags |= XPIPEI;
+@@ -182,17 +187,17 @@
+ restfd(1, e->savefd[1]); /* stdout of last */
+ e->savefd[1] = 0; /* no need to re-restore this */
+ /* Let exchild() close 0 in parent, after fork, before wait */
+- i = exchild(t, flags|XPCLOSE, 0);
++ i = exchild(t, flags|XPCLOSE, xerrok, 0);
+ if (!(flags&XBGND) && !(flags&XXCOM))
+ rv = i;
+ break;
+
+ case TLIST:
+ while (t->type == TLIST) {
+- execute(t->left, flags & XERROK);
++ execute(t->left, flags & XERROK, NULL);
+ t = t->right;
+ }
+- rv = execute(t, flags & XERROK);
++ rv = execute(t, flags & XERROK, xerrok);
+ break;
+
+ #ifdef KSH
+@@ -257,7 +262,7 @@
+ */
+ flags &= ~XEXEC;
+ exchild(t->left, flags|XBGND|XFORK|XCOPROC|XCCLOSE,
+- coproc.readw);
++ NULL, coproc.readw);
+ break;
+ }
+ #endif /* KSH */
+@@ -267,20 +272,24 @@
+ * forks again for async... parent should optimize
+ * this to "foo &"...
+ */
+- rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK);
++ rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK, xerrok);
+ break;
+
+ case TOR:
+ case TAND:
+- rv = execute(t->left, XERROK);
+- if (t->right != NULL && (rv == 0) == (t->type == TAND))
+- rv = execute(t->right, flags & XERROK);
+- else
+- flags |= XERROK;
++ rv = execute(t->left, XERROK, xerrok);
++ if ((rv == 0) == (t->type == TAND))
++ rv = execute(t->right, XERROK, xerrok);
++ flags |= XERROK;
++ if (xerrok)
++ *xerrok = 1;
+ break;
+
+ case TBANG:
+- rv = !execute(t->right, XERROK);
++ rv = !execute(t->right, XERROK, xerrok);
++ flags |= XERROK;
++ if (xerrok)
++ *xerrok = 1;
+ break;
+
+ #ifdef KSH
+@@ -328,7 +337,7 @@
+ if (t->type == TFOR) {
+ while (*ap != NULL) {
+ setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
+- rv = execute(t->left, flags & XERROK);
++ rv = execute(t->left, flags & XERROK, xerrok);
+ }
+ }
+ #ifdef KSH
+@@ -340,7 +349,7 @@
+ }
+ is_first = FALSE;
+ setstr(global(t->str), cp, KSH_UNWIND_ERROR);
+- rv = execute(t->left, flags & XERROK);
++ rv = execute(t->left, flags & XERROK, xerrok);
+ }
+ }
+ }
+@@ -365,17 +374,17 @@
+ }
+ }
+ rv = 0; /* in case of a continue */
+- while ((execute(t->left, XERROK) == 0) == (t->type == TWHILE))
+- rv = execute(t->right, flags & XERROK);
++ while ((execute(t->left, XERROK, NULL) == 0) == (t->type == TWHILE))
++ rv = execute(t->right, flags & XERROK, xerrok);
+ break;
+
+ case TIF:
+ case TELIF:
+ if (t->right == NULL)
+ break; /* should be error */
+- rv = execute(t->left, XERROK) == 0 ?
+- execute(t->right->left, flags & XERROK) :
+- execute(t->right->right, flags & XERROK);
++ rv = execute(t->left, XERROK, NULL) == 0 ?
++ execute(t->right->left, flags & XERROK, xerrok) :
++ execute(t->right->right, flags & XERROK, xerrok);
+ break;
+
+ case TCASE:
+@@ -387,11 +396,11 @@
+ goto Found;
+ break;
+ Found:
+- rv = execute(t->left, flags & XERROK);
++ rv = execute(t->left, flags & XERROK, xerrok);
+ break;
+
+ case TBRACE:
+- rv = execute(t->left, flags & XERROK);
++ rv = execute(t->left, flags & XERROK, xerrok);
+ break;
+
+ case TFUNCT:
+@@ -402,7 +411,7 @@
+ /* Clear XEXEC so nested execute() call doesn't exit
+ * (allows "ls -l | time grep foo").
+ */
+- rv = timex(t, flags & ~XEXEC);
++ rv = timex(t, flags & ~XEXEC, xerrok);
+ break;
+
+ case TEXEC: /* an eval'd TCOM */
+@@ -430,7 +439,8 @@
+ quitenv(); /* restores IO */
+ if ((flags&XEXEC))
+ unwind(LEXIT); /* exit child */
+- if (rv != 0 && !(flags & XERROK)) {
++ if (rv != 0 && !(flags & XERROK)
++ && (xerrok == NULL || !*xerrok)) {
+ if (Flag(FERREXIT))
+ unwind(LERROR);
+ trapsig(SIGERR_);
+@@ -443,11 +453,12 @@
+ */
+
+ static int
+-comexec(t, tp, ap, flags)
++comexec(t, tp, ap, flags, xerrok)
+ struct op *t;
+ struct tbl *volatile tp;
+ register char **ap;
+ int volatile flags;
++ volatile int * volatile xerrok;
+ {
+ int i;
+ volatile int rv = 0;
+@@ -660,7 +671,7 @@
+ i = ksh_sigsetjmp(e->jbuf, 0);
+ if (i == 0) {
+ /* seems odd to pass XERROK here, but at&t ksh does */
+- exstat = execute(tp->val.t, flags & XERROK);
++ exstat = execute(tp->val.t, flags & XERROK, xerrok);
+ i = LRETURN;
+ }
+ kshname = old_kshname;
+@@ -737,7 +748,7 @@
+ texec.left = t; /* for tprint */
+ texec.str = tp->val.s;
+ texec.args = ap;
+- rv = exchild(&texec, flags, -1);
++ rv = exchild(&texec, flags, xerrok, -1);
+ break;
+ }
+ Leave:
+Index: pdksh-5.2.14/c_sh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_sh.c 2009-09-19 11:54:58.000000000 +0200
++++ pdksh-5.2.14/c_sh.c 2009-09-19 11:55:01.000000000 +0200
+@@ -725,9 +725,10 @@
+ * time pipeline (really a statement, not a built-in command)
+ */
+ int
+-timex(t, f)
++timex(t, f, xerrok)
+ struct op *t;
+ int f;
++ volatile int * xerrok;
+ {
+ #define TF_NOARGS BIT(0)
+ #define TF_NOREAL BIT(1) /* don't report real time */
+@@ -753,7 +754,7 @@
+ if (t->left->type == TCOM)
+ t->left->str = opts;
+ opts[0] = 0;
+- rv = execute(t->left, f | XTIME);
++ rv = execute(t->left, f | XTIME, xerrok);
+ tf |= opts[0];
+ t1t = ksh_times(&t1);
+ } else
+Index: pdksh-5.2.14/eval.c
+===================================================================
+--- pdksh-5.2.14.orig/eval.c 2009-09-19 11:54:58.000000000 +0200
++++ pdksh-5.2.14/eval.c 2009-09-19 11:55:01.000000000 +0200
+@@ -877,7 +877,7 @@
+ close(pv[1]);
+ }
+
+- execute(t, XFORK|XXCOM|XPIPEO);
++ execute(t, XFORK|XXCOM|XPIPEO, NULL);
+ restfd(1, ofd1);
+ startlast();
+ xp->split = 1; /* waitlast() */
+Index: pdksh-5.2.14/jobs.c
+===================================================================
+--- pdksh-5.2.14.orig/jobs.c 2009-09-19 11:54:58.000000000 +0200
++++ pdksh-5.2.14/jobs.c 2009-09-19 11:55:01.000000000 +0200
+@@ -443,9 +443,10 @@
+
+ /* execute tree in child subprocess */
+ int
+-exchild(t, flags, close_fd)
++exchild(t, flags, xerrok, close_fd)
+ struct op *t;
+ int flags;
++ volatile int *xerrok;
+ int close_fd; /* used if XPCLOSE or XCCLOSE */
+ {
+ static Proc *last_proc; /* for pipelines */
+@@ -464,7 +465,7 @@
+ /* Clear XFORK|XPCLOSE|XCCLOSE|XCOPROC|XPIPEO|XPIPEI|XXCOM|XBGND
+ * (also done in another execute() below)
+ */
+- return execute(t, flags & (XEXEC | XERROK));
++ return execute(t, flags & (XEXEC | XERROK), xerrok);
+
+ #ifdef JOB_SIGS
+ /* no SIGCHLD's while messing with job and process lists */
+@@ -659,7 +660,7 @@
+ #endif /* OS2 */
+ tty_close();
+ cleartraps();
+- execute(t, (flags & XERROK) | XEXEC); /* no return */
++ execute(t, (flags & XERROK) | XEXEC, xerrok); /* no return */
+ internal_errorf(0, "exchild: execute() returned");
+ unwind(LLEAVE);
+ /* NOTREACHED */
+Index: pdksh-5.2.14/main.c
+===================================================================
+--- pdksh-5.2.14.orig/main.c 2009-09-19 11:54:58.000000000 +0200
++++ pdksh-5.2.14/main.c 2009-09-19 11:55:01.000000000 +0200
+@@ -634,7 +634,7 @@
+ }
+
+ if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
+- exstat = execute(t, 0);
++ exstat = execute(t, 0, NULL);
+
+ if (t != NULL && t->type != TEOF && interactive && really_exit)
+ really_exit = 0;
+Index: pdksh-5.2.14/proto.h
+===================================================================
+--- pdksh-5.2.14.orig/proto.h 2009-09-19 11:54:58.000000000 +0200
++++ pdksh-5.2.14/proto.h 2009-09-19 11:55:01.000000000 +0200
+@@ -42,7 +42,7 @@
+ int c_unset ARGS((char **wp));
+ int c_ulimit ARGS((char **wp));
+ int c_times ARGS((char **wp));
+-int timex ARGS((struct op *t, int f));
++int timex ARGS((struct op *t, int f, volatile int *xerrok));
+ void timex_hook ARGS((struct op *t, char ** volatile *app));
+ int c_exec ARGS((char **wp));
+ int c_builtin ARGS((char **wp));
+@@ -65,7 +65,7 @@
+ int glob_str ARGS((char *cp, XPtrV *wp, int markdirs));
+ /* exec.c */
+ int fd_clexec ARGS((int fd));
+-int execute ARGS((struct op * volatile t, volatile int flags));
++int execute ARGS((struct op * volatile t, volatile int flags, volatile int * volatile xerrok));
+ int shcomexec ARGS((char **wp));
+ struct tbl * findfunc ARGS((const char *name, unsigned int h, int create));
+ int define ARGS((const char *name, struct op *t));
+@@ -138,7 +138,7 @@
+ void j_init ARGS((int mflagset));
+ void j_exit ARGS((void));
+ void j_change ARGS((void));
+-int exchild ARGS((struct op *t, int flags, int close_fd));
++int exchild ARGS((struct op *t, int flags, volatile int * xerrok, int close_fd));
+ void startlast ARGS((void));
+ int waitlast ARGS((void));
+ int waitfor ARGS((const char *cp, int *sigp));
+Index: pdksh-5.2.14/tests/debian-111.t
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ pdksh-5.2.14/tests/debian-111.t 2009-09-19 12:02:51.000000000 +0200
+@@ -0,0 +1,60 @@
++name: debian-111-1
++description:
++ Check set -e regression
++stdin:
++ set -e; true; false && true; echo OK
++expected-stdout:
++ OK
++---
++name: debian-111-2
++description:
++ Regression for #387755
++stdin:
++ set -e
++ ! true
++ ! false
++ echo OK
++expected-stdout:
++ OK
++---
++name: debian-111-3
++description:
++ Regression for #387755
++stdin:
++ set -e; (false); echo here
++expected-stdout:
++expected-fail: yes
++---
++name: debian-111-4
++description:
++ Regression for #387755
++stdin:
++ set +e; (false); echo here
++expected-stdout:
++ here
++---
++name: debian-111-5
++description:
++ Regression for #71256
++stdin:
++ set -e
++ if true; then
++ false && echo something
++ fi
++ echo OK
++expected-stdout:
++ OK
++---
++name: debian-111-6
++description:
++ Regression for #71256
++stdin:
++ set +e
++ if true; then
++ false && echo something
++ fi
++ echo OK
++expected-stdout:
++ OK
++---
++
diff --git a/system/pdksh/patches/112_OpenBSD-test.patch b/system/pdksh/patches/112_OpenBSD-test.patch
new file mode 100644
index 0000000000..7058a2dac8
--- /dev/null
+++ b/system/pdksh/patches/112_OpenBSD-test.patch
@@ -0,0 +1,58 @@
+From OpenBSD:
+
+2009-03-01 21:11 otto
+
+ * c_test.c (1.18): Fix PR #723: test(1) operator precedence
+ inconsistent with POSIX Make sure ksh builtin test and test(1) do
+ not differ. From Christiano Farina Haesbaert. ok miod@
+
+
+Index: pdksh-5.2.14/c_test.c
+===================================================================
+--- pdksh-5.2.14.orig/c_test.c 2009-09-19 11:22:39.000000000 +0200
++++ pdksh-5.2.14/c_test.c 2009-09-19 12:03:25.000000000 +0200
+@@ -551,15 +551,23 @@
+ }
+ return res;
+ }
+- if ((op = (Test_op) (*te->isa)(te, TM_UNOP))) {
+- /* unary expression */
+- opnd1 = (*te->getopnd)(te, op, do_eval);
+- if (!opnd1) {
+- (*te->error)(te, -1, "missing argument");
+- return 0;
+- }
++ /*
++ * Binary should have precedence over unary in this case
++ * so that something like test \( -f = -f \) is accepted
++ */
++ if ((te->flags & TEF_DBRACKET) || (&te->pos.wp[1] < te->wp_end &&
++ !test_isop(te, TM_BINOP, te->pos.wp[1]))) {
++ if ((op = (Test_op) (*te->isa)(te, TM_UNOP))) {
++ /* unary expression */
++ opnd1 = (*te->getopnd)(te, op, do_eval);
++ if (!opnd1) {
++ (*te->error)(te, -1, "missing argument");
++ return 0;
++ }
+
+- return (*te->eval)(te, op, opnd1, (const char *) 0, do_eval);
++ return (*te->eval)(te, op, opnd1, (const char *) 0,
++ do_eval);
++ }
+ }
+ opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval);
+ if (!opnd1) {
+Index: pdksh-5.2.14/tests/debian-112.t
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ pdksh-5.2.14/tests/debian-112.t 2009-09-19 12:06:33.000000000 +0200
+@@ -0,0 +1,8 @@
++name: debian-112-1
++description:
++ Check test operator precedence
++stdin:
++ test \( -f = -f \) && echo OK
++expected-stdout:
++ OK
++---
diff --git a/system/pdksh/patches/113_OpenBSD-memory.patch b/system/pdksh/patches/113_OpenBSD-memory.patch
new file mode 100644
index 0000000000..79e7b59833
--- /dev/null
+++ b/system/pdksh/patches/113_OpenBSD-memory.patch
@@ -0,0 +1,148 @@
+From OpenBSD:
+
+2009-04-19 22:34 sthen
+
+ * misc.c (1.37): don't print extraneous padding characters when
+ tab-completion file/command lists encounter a name too long for
+ the width of the terminal.
+
+ from Matthew Haub, no objections krw@.
+
+2008-08-11 23:50 jaredy
+
+ * tree.c (1.19): plug a memleak when freeing io redirection in
+ commands. the leaked memory is actually reclaimed when the
+ command finishes but may grow until that happens, e.g. during
+ command execution.
+
+ ok phessler@. testing sobrado@ jmc@ oga@.
+
+2008-07-23 18:34 jaredy
+
+ * c_sh.c (1.38), syn.c (1.28): fix stack abuse in the `time'
+ commmand, using alloc()'d memory instead.
+
+ reported by Thorsten Glaser, thanks.
+
+ ok millert@, earlier version miod@
+
+2008-07-21 19:30 millert
+
+ * alloc.c (1.8): Extra sanity checking for afree(); OK deraadt@
+ and pvalchev@
+
+2008-07-12 14:33 miod
+
+ * misc.c (1.34): Fix a strlcpy() bound.
+
+
+
+Index: pdksh-5.2.14/tree.c
+===================================================================
+--- pdksh-5.2.14.orig/tree.c 2009-09-19 11:22:37.000000000 +0200
++++ pdksh-5.2.14/tree.c 2009-09-19 12:06:43.000000000 +0200
+@@ -755,4 +755,5 @@
+ afree((void*)p->heredoc, ap);
+ afree((void*)p, ap);
+ }
++ afree(iow, ap);
+ }
+Index: pdksh-5.2.14/syn.c
+===================================================================
+--- pdksh-5.2.14.orig/syn.c 2009-09-19 11:22:37.000000000 +0200
++++ pdksh-5.2.14/syn.c 2009-09-19 12:06:43.000000000 +0200
+@@ -375,6 +375,11 @@
+ case TIME:
+ syniocf &= ~(KEYWORD|ALIAS);
+ t = pipeline(0);
++ if (t) {
++ t->str = alloc(2, ATEMP);
++ t->str[0] = '\0'; /* TF_* flags */
++ t->str[1] = '\0';
++ }
+ t = block(TTIME, t, NOBLOCK, NOWORDS);
+ break;
+
+Index: pdksh-5.2.14/alloc.c
+===================================================================
+--- pdksh-5.2.14.orig/alloc.c 2009-09-19 11:22:37.000000000 +0200
++++ pdksh-5.2.14/alloc.c 2009-09-19 12:06:43.000000000 +0200
+@@ -894,13 +894,20 @@
+ void
+ afree(void *ptr, Area *ap)
+ {
+- struct link *l;
++ struct link *l, *l2;
+
+ if (!ptr)
+ return;
+
+ l = P2L(ptr);
+
++ for (l2 = ap->freelist; l2 != NULL; l2 = l2->next) {
++ if (l == l2)
++ break;
++ }
++ if (l2 == NULL)
++ internal_errorf(1, "afree: %p not present in area %p", ptr, ap);
++
+ if (l->prev)
+ l->prev->next = l->next;
+ else
+Index: pdksh-5.2.14/c_sh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_sh.c 2009-09-19 11:55:01.000000000 +0200
++++ pdksh-5.2.14/c_sh.c 2009-09-19 12:06:43.000000000 +0200
+@@ -738,7 +738,6 @@
+ clock_t t0t, t1t = 0;
+ int tf = 0;
+ extern clock_t j_usrtime, j_systime; /* computed by j_wait */
+- char opts[1];
+
+ t0t = ksh_times(&t0);
+ if (t->left) {
+@@ -751,11 +750,9 @@
+ * really work as it only counts the last job).
+ */
+ j_usrtime = j_systime = 0;
+- if (t->left->type == TCOM)
+- t->left->str = opts;
+- opts[0] = 0;
+ rv = execute(t->left, f | XTIME, xerrok);
+- tf |= opts[0];
++ if (t->left->type == TCOM)
++ tf |= t->left->str[0];
+ t1t = ksh_times(&t1);
+ } else
+ tf = TF_NOARGS;
+Index: pdksh-5.2.14/misc.c
+===================================================================
+--- pdksh-5.2.14.orig/misc.c 2009-09-19 11:22:37.000000000 +0200
++++ pdksh-5.2.14/misc.c 2009-09-19 12:06:43.000000000 +0200
+@@ -1123,6 +1123,7 @@
+ int r, c;
+ int rows, cols;
+ int nspace;
++ int col_width;
+
+ /* max_width + 1 for the space. Note that no space
+ * is printed after the last column to avoid problems
+@@ -1141,6 +1142,9 @@
+ rows = n;
+ }
+
++ col_width = max_width;
++ if (cols == 1)
++ col_width = 0; /* Don't pad entries in single column output. */
+ nspace = (x_cols - max_width * cols) / cols;
+ if (nspace <= 0)
+ nspace = 1;
+@@ -1149,7 +1153,7 @@
+ i = c * rows + r;
+ if (i < n) {
+ shf_fprintf(shf, "%-*s",
+- max_width,
++ col_width,
+ (*func)(arg, i, str, max_width + 1));
+ if (c + 1 < cols)
+ shf_fprintf(shf, "%*s", nspace, null);
diff --git a/system/pdksh/patches/114_OpenBSD-let-crash.patch b/system/pdksh/patches/114_OpenBSD-let-crash.patch
new file mode 100644
index 0000000000..b859a55f50
--- /dev/null
+++ b/system/pdksh/patches/114_OpenBSD-let-crash.patch
@@ -0,0 +1,37 @@
+From OpenBSD:
+
+2009-06-01 20:20 deraadt
+
+ * expr.c (1.20): "let --" was crashing ksh; found by
+ phy0@rambler.ru. Various other expressions involving ++ and --
+ also ran into this. Insufficient checks for end of parse in the
+ tokenizer made it assume that an lvalue had been found ok millert
+ otto
+
+Index: pdksh-5.2.14/expr.c
+===================================================================
+--- pdksh-5.2.14.orig/expr.c 2009-09-19 11:22:35.000000000 +0200
++++ pdksh-5.2.14/expr.c 2009-09-19 12:07:08.000000000 +0200
+@@ -558,7 +558,8 @@
+ enum token op;
+ struct tbl *vasn;
+ {
+- if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE))
++ if (es->tok == END ||
++ (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE)))
+ evalerr(es, ET_LVALUE, opinfo[(int) op].name);
+ else if (vasn->flag & RDONLY)
+ evalerr(es, ET_RDONLY, opinfo[(int) op].name);
+Index: pdksh-5.2.14/tests/debian-114.t
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ pdksh-5.2.14/tests/debian-114.t 2009-09-19 12:11:08.000000000 +0200
+@@ -0,0 +1,8 @@
++name: debian-114-1
++description:
++ Check if let crashes
++stdin:
++ let --
++ exit 0
++expected-stderr-pattern: /\-\- requires lvalue/
++---
diff --git a/system/pdksh/patches/115_OpenBSD-echo-posix.patch b/system/pdksh/patches/115_OpenBSD-echo-posix.patch
new file mode 100644
index 0000000000..47a9f37826
--- /dev/null
+++ b/system/pdksh/patches/115_OpenBSD-echo-posix.patch
@@ -0,0 +1,140 @@
+From OpenBSD:
+
+2009-02-07 15:03 kili
+
+ * c_ksh.c (1.33):
+ Ensure that *wp isn't NULL.
+
+ ok otto@
+
+2009-02-07 08:24 guenther
+
+ * c_ksh.c (1.32), ksh.1 (1.124), sh.1 (1.78): Make built-in echo
+ behave according to POSIX when set -o posix is in effect: the
+ only option is -n, and only one of those is parsed.
+
+ diff from Ingo Schwarze ok otto@ kili@; manpage changes ok jmc@
+
+
+Index: pdksh-5.2.14/c_ksh.c
+===================================================================
+--- pdksh-5.2.14.orig/c_ksh.c 2009-09-19 11:22:34.000000000 +0200
++++ pdksh-5.2.14/c_ksh.c 2009-09-19 12:13:54.000000000 +0200
+@@ -247,23 +247,30 @@
+ * by default.
+ */
+ wp += 1;
+- while ((s = *wp) && *s == '-' && s[1]) {
+- while (*++s)
+- if (*s == 'n')
+- nflags &= ~PO_NL;
+- else if (*s == 'e')
+- nflags |= PO_EXPAND;
+- else if (*s == 'E')
+- nflags &= ~PO_EXPAND;
+- else
+- /* bad option: don't use nflags, print
+- * argument
+- */
++ if (Flag(FPOSIX)) {
++ if (*wp && strcmp(*wp, "-n") == 0) {
++ flags &= ~PO_NL;
++ wp++;
++ }
++ } else {
++ while ((s = *wp) && *s == '-' && s[1]) {
++ while (*++s)
++ if (*s == 'n')
++ nflags &= ~PO_NL;
++ else if (*s == 'e')
++ nflags |= PO_EXPAND;
++ else if (*s == 'E')
++ nflags &= ~PO_EXPAND;
++ else
++ /* bad option: don't use
++ * nflags, print argument
++ */
++ break;
++ if (*s)
+ break;
+- if (*s)
+- break;
+- wp++;
+- flags = nflags;
++ wp++;
++ flags = nflags;
++ }
+ }
+ } else {
+ int optc;
+Index: pdksh-5.2.14/ksh.Man
+===================================================================
+--- pdksh-5.2.14.orig/ksh.Man 2009-09-19 11:22:34.000000000 +0200
++++ pdksh-5.2.14/ksh.Man 2009-09-19 12:13:54.000000000 +0200
+@@ -1521,6 +1521,13 @@
+ In future, a new option (\fB\-v\fP perhaps) will be added to distinguish
+ the two behaviours.
+ .IP \ \ \(bu
++\fBecho\fP
++options.
++In POSIX mode, \fB\-e\fP and \fB\-E\fP
++are not treated as options, but printed like other arguments;
++in non-POSIX mode, these options control the interpretation
++of backslash sequences.
++.IP \ \ \(bu
+ \fBfg\fP exit status: in posix mode, the exit status is 0 if no errors occur;
+ in non-posix mode, the exit status is that of the last foregrounded job.
+ .IP \ \ \(bu
+@@ -1780,6 +1787,9 @@
+ \fB\-n\fP suppresses the trailing newline, \fB\-e\fP enables backslash
+ interpretation (a no-op, since this is normally done), and \fB\-E\fP which
+ suppresses backslash interpretation.
++If the \fIposix\fP
++option is set, only the first argument is treated as an option, and only
++if it is exactly \fB-n\fP.
+ .\"}}}
+ .\"{{{ eval command ...
+ .IP "\fBeval\fP \fIcommand ...\fP"
+Index: pdksh-5.2.14/tests/debian-115.t
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ pdksh-5.2.14/tests/debian-115.t 2009-09-19 12:18:11.000000000 +0200
+@@ -0,0 +1,38 @@
++name: debian-115-1
++description:
++ Check if echo does not accept -e in posix mode
++stdin:
++ set -o posix
++ echo -e test
++expected-stdout:
++ -e test
++---
++name: debian-115-2
++description:
++ Check if echo accepts -e in non-posix mode
++stdin:
++ set +o posix
++ echo -e test
++expected-stdout:
++ test
++---
++name: debian-115-3
++description:
++ Check if echo accepts -n in posix mode
++stdin:
++ set -o posix
++ echo -n test
++ echo " OK"
++expected-stdout:
++ test OK
++---
++name: debian-115-4
++description:
++ Check if echo accepts -n in non-posix mode
++stdin:
++ set +o posix
++ echo -n test
++ echo " OK"
++expected-stdout:
++ test OK
++---
diff --git a/system/pdksh/patches/116_OpenBSD-history.patch b/system/pdksh/patches/116_OpenBSD-history.patch
new file mode 100644
index 0000000000..9be184b298
--- /dev/null
+++ b/system/pdksh/patches/116_OpenBSD-history.patch
@@ -0,0 +1,47 @@
+From OpenBSD:
+
+2008-07-03 19:52 otto
+
+ * lex.c (1.44): fix inifinite loop with set -o csh-history and
+ !<space> as input. report and testing by david@; ok millert@
+ jaredy@
+
+2008-05-20 02:30 fgsch
+
+ * history.c (1.36): cast pointer arithmetic to unsigned so we can
+ behave correctly on underflows. fixes fc -l 1 in my box where
+ line is 1667511151. krw@ ok.
+
+Index: pdksh-5.2.14/history.c
+===================================================================
+--- pdksh-5.2.14.orig/history.c 2009-09-17 22:18:37.000000000 +0200
++++ pdksh-5.2.14/history.c 2009-09-17 23:46:06.000000000 +0200
+@@ -385,7 +385,7 @@
+
+ if (getn(str, &n)) {
+ hp = histptr + (n < 0 ? n : (n - hist_source->line));
+- if (hp < history) {
++ if ((long)hp < (long)history) {
+ if (approx)
+ hp = hist_get_oldest();
+ else {
+@@ -862,7 +862,8 @@
+ if (base != MAP_FAILED)
+ munmap((caddr_t)base, hsize);
+ hist_finish();
+- unlink(hname);
++ if (unlink(hname) != 0)
++ return;
+ goto retry;
+ }
+ if (hsize > 2) {
+@@ -870,7 +871,8 @@
+ if (lines > histsize) {
+ /* we need to make the file smaller */
+ if (hist_shrink(base, hsize))
+- unlink(hname);
++ if (unlink(hname) != 0)
++ return;
+ munmap((caddr_t)base, hsize);
+ hist_finish();
+ goto retry;
diff --git a/system/pdksh/patches/117_Debian-test.patch b/system/pdksh/patches/117_Debian-test.patch
new file mode 100644
index 0000000000..5756df78d9
--- /dev/null
+++ b/system/pdksh/patches/117_Debian-test.patch
@@ -0,0 +1,78 @@
+Fix 4-argument test - bug#465250
+Index: pdksh-5.2.14/c_test.c
+===================================================================
+--- pdksh-5.2.14.orig/c_test.c 2009-09-19 12:03:25.000000000 +0200
++++ pdksh-5.2.14/c_test.c 2009-09-19 12:18:27.000000000 +0200
+@@ -131,10 +131,27 @@
+ */
+ if (argc <= 5) {
+ char **owp = wp;
++ char **owpend = te.wp_end;
+ int invert = 0;
+ Test_op op;
+ const char *opnd1, *opnd2;
+
++ if (argc >= 2 && ((*te.isa)(&te, TM_OPAREN)))
++ {
++ te.pos.wp = te.wp_end - 1;
++ if ((*te.isa)(&te, TM_CPAREN))
++ {
++ argc -= 2;
++ te.wp_end--;
++ te.pos.wp = owp + 2;
++ }
++ else
++ {
++ te.pos.wp = owp + 1;
++ te.wp_end = owpend;
++ }
++ }
++
+ while (--argc >= 0) {
+ if ((*te.isa)(&te, TM_END))
+ return !0;
+@@ -173,6 +190,7 @@
+ break;
+ }
+ te.pos.wp = owp + 1;
++ te.wp_end = owpend;
+ }
+
+ return test_parse(&te);
+Index: pdksh-5.2.14/tests/debian-117.t
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ pdksh-5.2.14/tests/debian-117.t 2009-09-19 12:22:53.000000000 +0200
+@@ -0,0 +1,32 @@
++name: debian-117-1
++description:
++ Check test - bug#465250
++stdin:
++ test \( ! -e \) ; echo $?
++expected-stdout:
++ 1
++---
++name: debian-117-2
++description:
++ Check test - bug#465250
++stdin:
++ test \( -e \) ; echo $?
++expected-stdout:
++ 0
++---
++name: debian-117-3
++description:
++ Check test - bug#465250
++stdin:
++ test ! -e ; echo $?
++expected-stdout:
++ 1
++---
++name: debian-117-4
++description:
++ Check test - bug#465250
++stdin:
++ test -e ; echo $?
++expected-stdout:
++ 0
++---