Please review changes against upstream code using SCM,
see the Vcs-* tags in debian/control for its location.

--- mksh-56b.orig/check.t
+++ mksh-56b/check.t
@@ -1,4 +1,4 @@
-# $MirOS: src/bin/mksh/check.t,v 1.797 2017/08/29 13:38:29 tg Exp $
+# $MirOS: src/bin/mksh/check.t,v 1.799 2017/10/17 23:45:16 tg Exp $
 # -*- mode: sh -*-
 #-
 # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -30,7 +30,7 @@
 # (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
 
 expected-stdout:
-	@(#)MIRBSD KSH R56 2017/08/29
+	@(#)MIRBSD KSH R56 2017/10/17
 description:
 	Check base version of full shell
 stdin:
@@ -39,7 +39,7 @@ name: KSH_VERSION
 category: !shell:legacy-yes
 ---
 expected-stdout:
-	@(#)LEGACY KSH R56 2017/08/29
+	@(#)LEGACY KSH R56 2017/10/17
 description:
 	Check base version of legacy shell
 stdin:
--- mksh-56b.orig/exec.c
+++ mksh-56b/exec.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.199 2017/08/07 21:16:31 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.201 2017/10/11 21:09:24 tg Exp $");
 
 #ifndef MKSH_DEFAULT_EXECSHELL
 #define MKSH_DEFAULT_EXECSHELL	MKSH_UNIXROOT "/bin/sh"
@@ -953,8 +953,12 @@ scriptexec(struct op *tp, const char **a
 		}
 #ifdef __OS2__
 		/*
-		 * Search shell/interpreter name without directory in PATH
-		 * if specified path does not exist
+		 * On OS/2, the directory structure differs from normal
+		 * Unix, which can make many scripts whose shebang
+		 * hardcodes the path to an interpreter fail (and there
+		 * might be no /usr/bin/env); for user convenience, if
+		 * the specified interpreter is not usable, do a PATH
+		 * search to find it.
 		 */
 		if (mksh_vdirsep(sh) && !search_path(sh, path, X_OK, NULL)) {
 			cp = search_path(_getname(sh), path, X_OK, NULL);
@@ -1168,11 +1172,7 @@ findcom(const char *name, int flags)
 	char *fpath;
 	union mksh_cchack npath;
 
-	if (mksh_vdirsep(name)
-#ifdef MKSH_DOSPATH
-	    && (strcmp(name, T_builtin) != 0)
-#endif
-	    ) {
+	if (mksh_vdirsep(name)) {
 		insert = 0;
 		/* prevent FPATH search below */
 		flags &= ~FC_FUNC;
--- mksh-56b.orig/lex.c
+++ mksh-56b/lex.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.239 2017/05/05 22:53:29 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.240 2017/10/17 23:45:18 tg Exp $");
 
 /*
  * states while lexing word
@@ -284,15 +284,6 @@ yylex(int cf)
 						}
 						afree(tmp, ATEMP);
 						break;
-					} else {
-						Source *s;
-
-						s = pushs(SREREAD,
-						    source->areap);
-						s->start = s->str =
-						    s->u.freeme = tmp;
-						s->next = source;
-						source = s;
 					}
 				}
 				*wp++ = CHAR;
--- mksh-56b.orig/main.c
+++ mksh-56b/main.c
@@ -34,9 +34,7 @@
 #include <locale.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.342 2017/04/28 11:13:47 tg Exp $");
-
-extern char **environ;
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.345 2017/10/14 21:05:22 tg Exp $");
 
 #ifndef MKSHRC_PATH
 #define MKSHRC_PATH	"~/.mkshrc"
@@ -52,6 +50,7 @@ void chvt_reinit(void);
 static void reclaim(void);
 static void remove_temps(struct temp *);
 static mksh_uari_t rndsetup(void);
+static void init_environ(void);
 #ifdef SIGWINCH
 static void x_sigwinch(int);
 #endif
@@ -242,10 +241,6 @@ main_init(int argc, const char *argv[],
 	set_ifs(TC_IFSWS);
 
 #ifdef __OS2__
-	for (i = 0; i < 3; ++i)
-		if (!isatty(i))
-			setmode(i, O_BINARY);
-
 	os2_init(&argc, &argv);
 #endif
 
@@ -401,14 +396,7 @@ main_init(int argc, const char *argv[],
 #endif
 
 	/* import environment */
-	if (environ != NULL) {
-		wp = (const char **)environ;
-		while (*wp != NULL) {
-			rndpush(*wp);
-			typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
-			++wp;
-		}
-	}
+	init_environ();
 
 	/* for security */
 	typeset(TinitIFS, 0, 0, 0, 0);
@@ -665,8 +653,7 @@ main_init(int argc, const char *argv[],
 		if (Flag(FLOGIN))
 			include(substitute("$HOME/.profile", 0), 0, NULL, true);
 		if (Flag(FTALKING)) {
-			cp = substitute(substitute("${ENV:-" MKSHRC_PATH "}",
-			    0), DOTILDE);
+			cp = substitute("${ENV:-" MKSHRC_PATH "}", DOTILDE);
 			if (cp[0] != '\0')
 				include(cp, 0, NULL, true);
 		}
@@ -1981,3 +1968,84 @@ x_mkraw(int fd, mksh_ttyst *ocb, bool fo
 
 	mksh_tcset(fd, &cb);
 }
+
+#ifdef MKSH_ENVDIR
+static void
+init_environ(void)
+{
+	char *xp;
+	ssize_t n;
+	XString xs;
+	struct shf *shf;
+	DIR *dirp;
+	struct dirent *dent;
+
+	if ((dirp = opendir(MKSH_ENVDIR)) == NULL) {
+		warningf(false, "cannot read environment from %s: %s",
+		    MKSH_ENVDIR, cstrerror(errno));
+		return;
+	}
+	XinitN(xs, 256, ATEMP);
+ read_envfile:
+	errno = 0;
+	if ((dent = readdir(dirp)) != NULL) {
+		if (skip_varname(dent->d_name, true)[0] == '\0') {
+			xp = shf_smprintf(Tf_sSs, MKSH_ENVDIR, dent->d_name);
+			if (!(shf = shf_open(xp, O_RDONLY, 0, 0))) {
+				warningf(false,
+				    "cannot read environment %s from %s: %s",
+				    dent->d_name, MKSH_ENVDIR,
+				    cstrerror(errno));
+				goto read_envfile;
+			}
+			afree(xp, ATEMP);
+			n = strlen(dent->d_name);
+			xp = Xstring(xs, xp);
+			XcheckN(xs, xp, n + 32);
+			memcpy(xp, dent->d_name, n);
+			xp += n;
+			*xp++ = '=';
+			while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {
+				xp += n;
+				if (Xnleft(xs, xp) <= 0)
+					XcheckN(xs, xp, Xlength(xs, xp));
+			}
+			if (n < 0) {
+				warningf(false,
+				    "cannot read environment %s from %s: %s",
+				    dent->d_name, MKSH_ENVDIR,
+				    cstrerror(shf_errno(shf)));
+			} else {
+				*xp = '\0';
+				xp = Xstring(xs, xp);
+				rndpush(xp);
+				typeset(xp, IMPORT | EXPORT, 0, 0, 0);
+			}
+			shf_close(shf);
+		}
+		goto read_envfile;
+	} else if (errno)
+		warningf(false, "cannot read environment from %s: %s",
+		    MKSH_ENVDIR, cstrerror(errno));
+	closedir(dirp);
+	Xfree(xs, xp);
+}
+#else
+extern char **environ;
+
+static void
+init_environ(void)
+{
+	const char **wp;
+
+	if (environ == NULL)
+		return;
+
+	wp = (const char **)environ;
+	while (*wp != NULL) {
+		rndpush(*wp);
+		typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
+		++wp;
+	}
+}
+#endif
--- mksh-56b.orig/misc.c
+++ mksh-56b/misc.c
@@ -32,7 +32,7 @@
 #include <grp.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.279 2017/08/07 21:39:25 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.288 2017/10/15 20:21:51 tg Exp $");
 
 #define KSH_CHVT_FLAG
 #ifdef MKSH_SMALL
@@ -1661,6 +1661,15 @@ do_realpath(const char *upath)
 	if (mksh_abspath(upath)) {
 		/* upath is an absolute pathname */
 		strdupx(ipath, upath, ATEMP);
+#ifdef MKSH_DOSPATH
+	} else if (mksh_drvltr(upath)) {
+		/* upath is a drive-relative pathname */
+		if (getdrvwd(&ldest, ord(*upath)))
+			return (NULL);
+		/* A:foo -> A:/cwd/foo; A: -> A:/cwd */
+		ipath = shf_smprintf(Tf_sss, ldest,
+		    upath[2] ? "/" : "", upath + 2);
+#endif
 	} else {
 		/* upath is a relative pathname, prepend cwd */
 		if ((tp = ksh_get_wd()) == NULL || !mksh_abspath(tp))
@@ -1695,6 +1704,7 @@ do_realpath(const char *upath)
 				continue;
 			else if (len == 2 && tp[1] == '.') {
 				/* strip off last pathname component */
+				/*XXX consider a rooted pathname */
 				while (xp > Xstring(xs, xp))
 					if (mksh_cdirsep(*--xp))
 						break;
@@ -1762,11 +1772,23 @@ do_realpath(const char *upath)
 			 * restart if symlink target is an absolute path,
 			 * otherwise continue with currently resolved prefix
 			 */
+#ifdef MKSH_DOSPATH
+ assemble_symlink:
+#endif
 			/* append rest of current input path to link target */
 			tp = shf_smprintf(Tf_sss, ldest, *ip ? "/" : "", ip);
 			afree(ipath, ATEMP);
 			ip = ipath = tp;
-			if (!mksh_abspath(ldest)) {
+			if (!mksh_abspath(ipath)) {
+#ifdef MKSH_DOSPATH
+				/* symlink target might be drive-relative */
+				if (mksh_drvltr(ipath)) {
+					if (getdrvwd(&ldest, ord(*ipath)))
+						goto notfound;
+					ip += 2;
+					goto assemble_symlink;
+				}
+#endif
 				/* symlink target is a relative path */
 				xp = Xrestpos(xs, xp, pos);
 			} else
@@ -1775,7 +1797,7 @@ do_realpath(const char *upath)
 				/* symlink target is an absolute path */
 				xp = Xstring(xs, xp);
  beginning_of_a_pathname:
-				/* assert: mksh_cdirsep((ip == ipath)[0]) */
+				/* assert: mksh_abspath(ip == ipath) */
 				/* assert: xp == xs.beg => start of path */
 
 				/* exactly two leading slashes? (SUSv4 3.266) */
@@ -1783,6 +1805,14 @@ do_realpath(const char *upath)
 					/* keep them, e.g. for UNC pathnames */
 					Xput(xs, xp, '/');
 				}
+#ifdef MKSH_DOSPATH
+				/* drive letter? */
+				if (mksh_drvltr(ip)) {
+					/* keep it */
+					Xput(xs, xp, *ip++);
+					Xput(xs, xp, *ip++);
+				}
+#endif
 			}
 		}
 		/* otherwise (no symlink) merely go on */
@@ -1932,6 +1962,15 @@ make_path(const char *cwd, const char *f
  * ..					..
  * ./foo				foo
  * foo/../../../bar			../../bar
+ * C:/foo/../..				C:/
+ * C:.					C:
+ * C:..					C:..
+ * C:foo/../../blah			C:../blah
+ *
+ * XXX consider a rooted pathname: we cannot really 'cd ..' for
+ * pathnames like: '/', 'c:/', '//foo', '//foo/', '/@unixroot/'
+ * (no effect), 'c:', 'c:.' (effect is retaining the '../') but
+ * we need to honour this throughout the shell
  */
 void
 simplify_path(char *p)
@@ -1939,6 +1978,17 @@ simplify_path(char *p)
 	char *dp, *ip, *sp, *tp;
 	size_t len;
 	bool needslash;
+#ifdef MKSH_DOSPATH
+	bool needdot = true;
+
+	/* keep drive letter */
+	if (mksh_drvltr(p)) {
+		p += 2;
+		needdot = false;
+	}
+#else
+#define needdot true
+#endif
 
 	switch (*p) {
 	case 0:
@@ -1977,7 +2027,7 @@ simplify_path(char *p)
 				/* just continue with the next one */
 				continue;
 			else if (len == 2 && tp[1] == '.') {
-				/* parent level, but how? */
+				/* parent level, but how? (see above) */
 				if (mksh_abspath(p))
 					/* absolute path, only one way */
 					goto strip_last_component;
@@ -2016,10 +2066,15 @@ simplify_path(char *p)
 		needslash = true;
 		/* try next component */
 	}
-	if (dp == p)
-		/* empty path -> dot */
-		*dp++ = needslash ? '/' : '.';
+	if (dp == p) {
+		/* empty path -> dot (or slash, when absolute) */
+		if (needslash)
+			*dp++ = '/';
+		else if (needdot)
+			*dp++ = '.';
+	}
 	*dp = '\0';
+#undef needdot
 }
 
 void
@@ -2133,6 +2188,18 @@ c_cd(const char **wp)
 		return (2);
 	}
 
+#ifdef MKSH_DOSPATH
+	tryp = NULL;
+	if (mksh_drvltr(dir) && !mksh_cdirsep(dir[2]) &&
+	    !getdrvwd(&tryp, ord(*dir))) {
+		dir = shf_smprintf(Tf_sss, tryp,
+		    dir[2] ? "/" : "", dir + 2);
+		afree(tryp, ATEMP);
+		afree(allocd, ATEMP);
+		allocd = dir;
+	}
+#endif
+
 #ifdef MKSH__NO_PATH_MAX
 	/* only a first guess; make_path will enlarge xs if necessary */
 	XinitN(xs, 1024, ATEMP);
--- mksh-56b.orig/os2.c
+++ mksh-56b/os2.c
@@ -26,18 +26,18 @@
 #include "sh.h"
 
 #include <klibc/startup.h>
+#include <errno.h>
 #include <io.h>
 #include <unistd.h>
 #include <process.h>
 
-__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.2 2017/04/29 22:04:29 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.6 2017/10/13 23:34:49 tg Exp $");
 
 static char *remove_trailing_dots(char *);
 static int access_stat_ex(int (*)(), const char *, void *);
 static int test_exec_exist(const char *, char *);
 static void response(int *, const char ***);
 static char *make_response_file(char * const *);
-static void env_slashify(void);
 static void add_temp(const char *);
 static void cleanup_temps(void);
 static void cleanup(void);
@@ -169,44 +169,12 @@ init_extlibpath(void)
 	}
 }
 
-/*
- * Convert backslashes of environmental variables to forward slahes.
- * A backslash may be used as an escaped character when doing 'echo'.
- * This leads to an unexpected behavior.
- */
-static void
-env_slashify(void)
-{
-	/*
-	 * PATH and TMPDIR are used by OS/2 as well. That is, they may
-	 * have backslashes as a directory separator.
-	 * BEGINLIBPATH and ENDLIBPATH are special variables on OS/2.
-	 */
-	const char *var_list[] = {
-		"PATH",
-		"TMPDIR",
-		"BEGINLIBPATH",
-		"ENDLIBPATH",
-		NULL
-	};
-	const char **var;
-	char *value;
-
-	for (var = var_list; *var; var++) {
-		value = getenv(*var);
-
-		if (value)
-			_fnslashify(value);
-	}
-}
-
 void
 os2_init(int *argcp, const char ***argvp)
 {
 	response(argcp, argvp);
 
 	init_extlibpath();
-	env_slashify();
 
 	if (!isatty(STDIN_FILENO))
 		setmode(STDIN_FILENO, O_BINARY);
@@ -557,3 +525,52 @@ cleanup(void)
 {
 	cleanup_temps();
 }
+
+int
+getdrvwd(char **cpp, unsigned int drvltr)
+{
+	PBYTE cp;
+	ULONG sz;
+	APIRET rc;
+	ULONG drvno;
+
+	if (DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH,
+	    &sz, sizeof(sz)) != 0) {
+		errno = EDOOFUS;
+		return (-1);
+	}
+
+	/* allocate 'X:/' plus sz plus NUL */
+	checkoktoadd((size_t)sz, (size_t)4);
+	cp = aresize(*cpp, (size_t)sz + (size_t)4, ATEMP);
+	cp[0] = ksh_toupper(drvltr);
+	cp[1] = ':';
+	cp[2] = '/';
+	drvno = ksh_numuc(cp[0]) + 1;
+	/* NUL is part of space within buffer passed */
+	++sz;
+	if ((rc = DosQueryCurrentDir(drvno, cp + 3, &sz)) == 0) {
+		/* success! */
+		*cpp = cp;
+		return (0);
+	}
+	afree(cp, ATEMP);
+	*cpp = NULL;
+	switch (rc) {
+	case 15: /* invalid drive */
+		errno = ENOTBLK;
+		break;
+	case 26: /* not dos disk */
+		errno = ENODEV;
+		break;
+	case 108: /* drive locked */
+		errno = EDEADLK;
+		break;
+	case 111: /* buffer overflow */
+		errno = ENAMETOOLONG;
+		break;
+	default:
+		errno = EINVAL;
+	}
+	return (-1);
+}
--- mksh-56b.orig/sh.h
+++ mksh-56b/sh.h
@@ -182,9 +182,9 @@
 #endif
 
 #ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.841 2017/08/29 13:38:31 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.849 2017/10/17 23:45:19 tg Exp $");
 #endif
-#define MKSH_VERSION "R56 2017/08/29"
+#define MKSH_VERSION "R56 2017/10/17"
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
@@ -2734,24 +2734,29 @@ extern int tty_init_fd(void);	/* initial
 #endif
 
 #ifdef MKSH_DOSPATH
+#define mksh_drvltr(s)			__extension__({			\
+	const char *mksh_drvltr_s = (s);				\
+	(ctype(mksh_drvltr_s[0], C_ALPHA) && mksh_drvltr_s[1] == ':');	\
+})
 #define mksh_abspath(s)			__extension__({			\
 	const char *mksh_abspath_s = (s);				\
 	(mksh_cdirsep(mksh_abspath_s[0]) ||				\
-	    (ctype(mksh_abspath_s[0], C_ALPHA) &&			\
-	    mksh_abspath_s[1] == ':'));					\
+	    (mksh_drvltr(mksh_abspath_s) &&				\
+	    mksh_cdirsep(mksh_abspath_s[2])));				\
 })
 #define mksh_cdirsep(c)			__extension__({			\
 	char mksh_cdirsep_c = (c);					\
 	(mksh_cdirsep_c == '/' || mksh_cdirsep_c == '\\');		\
 })
-#define mksh_sdirsep(s)			__extension__({			\
-	const char *mksh_sdirsep_s = (s);				\
-	((char *)((ctype(mksh_sdirsep_s[0], C_ALPHA) &&			\
-	    mksh_sdirsep_s[1] == ':' &&					\
-	    !mksh_cdirsep(mksh_sdirsep_s[2])) ?				\
-	    (mksh_sdirsep_s + 1) : strpbrk(mksh_sdirsep_s, "/\\")));	\
+#define mksh_sdirsep(s)			strpbrk((s), "/\\")
+#define mksh_vdirsep(s)			__extension__({			\
+	const char *mksh_vdirsep_s = (s);				\
+	(((mksh_drvltr(mksh_vdirsep_s) &&				\
+	    !mksh_cdirsep(mksh_vdirsep_s[2])) ? (!0) :			\
+	    (mksh_sdirsep(mksh_vdirsep_s) != NULL)) &&			\
+	    (strcmp(mksh_vdirsep_s, T_builtin) != 0));			\
 })
-#define mksh_vdirsep(s)			(mksh_sdirsep((s)) != NULL)
+int getdrvwd(char **, unsigned int);
 #else
 #define mksh_abspath(s)			(ord((s)[0]) == ord('/'))
 #define mksh_cdirsep(c)			(ord(c) == ord('/'))
--- mksh-56b.orig/var.c
+++ mksh-56b/var.c
@@ -28,7 +28,7 @@
 #include <sys/sysctl.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.220 2017/07/26 23:02:28 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.221 2017/10/13 23:34:49 tg Exp $");
 
 /*-
  * Variables
@@ -1294,9 +1294,29 @@ setspec(struct tbl *vp)
 {
 	mksh_ari_u num;
 	char *s;
-	int st;
+	int st = special(vp->name);
 
-	switch ((st = special(vp->name))) {
+#ifdef MKSH_DOSPATH
+	switch (st) {
+	case V_PATH:
+	case V_TMPDIR:
+#ifdef __OS2__
+	case V_BEGINLIBPATH:
+	case V_ENDLIBPATH:
+#endif
+		/* convert backslashes to slashes for convenience */
+		if (!(vp->flag&INTEGER)) {
+			s = str_val(vp);
+			do {
+				if (*s == ord('\\'))
+					*s = '/';
+			} while (*s++);
+		}
+		break;
+	}
+#endif
+
+	switch (st) {
 #ifdef __OS2__
 	case V_BEGINLIBPATH:
 	case V_ENDLIBPATH:
