diff options
Diffstat (limited to 'system/pdksh/patches/010_OpenBSD-patches.patch')
-rw-r--r-- | system/pdksh/patches/010_OpenBSD-patches.patch | 1112 |
1 files changed, 1112 insertions, 0 deletions
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 + --- + + |