Index: trunk/src/kash/eval.c
===================================================================
--- trunk/src/kash/eval.c	(revision 3436)
+++ trunk/src/kash/eval.c	(revision 3437)
@@ -458,5 +458,5 @@
 		args.backgnd = backgnd;
 		forkshell2(psh, jp, n, backgnd ? FORK_BG : FORK_FG,
-			   evalsubshell_child, n, &args, sizeof(args));
+			   evalsubshell_child, n, &args, sizeof(args), NULL);
 	}
 #else
@@ -578,5 +578,5 @@
 			args.pip[1] = pip[1];
 			forkshell2(psh, jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG,
-				   evalpipe_child, lp->n, &args, sizeof(args));
+				   evalpipe_child, lp->n, &args, sizeof(args), NULL);
 		}
 #else
@@ -677,5 +677,5 @@
 			args.pip[1] = pip[1];
 			forkshell2(psh, jp, n, FORK_NOJOB,
-				   evalbackcmd_child, n, &args, sizeof(args));
+				   evalbackcmd_child, n, &args, sizeof(args), NULL);
 		}
 #else
@@ -811,13 +811,17 @@
 struct evalcommanddoit
 {
-	struct cmdentry cmdentry;
-	char *lastarg;
-	const char *path;
+	struct stackmark smark;
+
 	struct backcmd *backcmd;
 	int flags;
 	int argc;
 	char **argv;
+	char *lastarg;
 	struct arglist varlist;
-	struct stackmark smark;
+	const char *path;
+	struct cmdentry cmdentry;
+
+	/* for child stuff only: */
+	int pip[2];
 };
 
@@ -996,4 +1000,72 @@
 }
 
+/* child callback. */
+static int evalcommand_child(shinstance *psh, union node *cmd, void *argp)
+{
+	struct evalcommanddoit *args = (struct evalcommanddoit *)argp;
+
+	if (args->flags & EV_BACKCMD) {
+		FORCEINTON;
+		shfile_close(&psh->fdtab, args->pip[0]);
+		if (args->pip[1] != 1) {
+			movefd(psh, args->pip[1], 1);
+		}
+	}
+	args->flags |= EV_EXIT;
+
+	evalcommand_doit(psh, cmd, args);
+	/* not reached */  /** @todo make it return here */
+	return 0;
+}
+
+/* Copies data in the argument structure from parent to child. */
+static void evalcommand_setup_child(shinstance *pshchild, shinstance *pshparent, void *argp)
+{
+	struct evalcommanddoit *args = (struct evalcommanddoit *)argp;
+	char **argv;
+	char **srcargv;
+	struct strlist *sp;
+	int argc, i;
+
+	setstackmark(pshchild, &args->smark);
+
+	/* copy arguments. */
+	srcargv = args->argv;
+	argc = args->argc;
+	args->argv = argv = stalloc(pshchild, sizeof(char *) * (argc + 1));
+	for (i = 0; i < argc; i++)
+		argv[i] = stsavestr(pshchild, srcargv[i]);
+	argv[argc] = NULL;
+	if (args->lastarg)
+		args->lastarg = argv[argc - 1];
+
+	/* copy variable list, checking for the 'path'. */
+	sp = args->varlist.list;
+	args->varlist.list = NULL;
+	args->varlist.lastp = &args->varlist.list;
+	for (; sp; sp = sp->next) {
+		struct strlist *snew = (struct strlist *)stalloc(pshchild, sizeof(*snew));
+		char *text;
+		snew->next = NULL;
+		snew->text = text = stsavestr(pshchild, sp->text);
+
+		if (&text[5] == args->path)
+			args->path = &text[sizeof("PATH=") - 1];
+
+		*args->varlist.lastp = snew;
+		args->varlist.lastp = &snew->next;
+	}
+
+	if (args->path == pathval(pshparent))
+		args->path = pathval(pshchild);
+
+	/* back tick command should be ignored in this codepath
+	   (flags != EV_BACKCMD as EV_EXIT is ORed in). */
+
+	/* If cmdentry references an internal function, we must duplicates it's nodes. */
+	if (args->cmdentry.cmdtype == CMDFUNCTION)
+		args->cmdentry.u.func = copyparsetree(pshchild, args->cmdentry.u.func); /** @todo isn't this duplicated already? */
+}
+
 /*
  * Execute a simple command.
@@ -1135,28 +1207,34 @@
 		   || args.cmdentry.u.bltin == evalcmd))) {
 		struct job *jp;
-		int pip[2];
 		int mode;
+
 		INTOFF;
 		jp = makejob(psh, cmd, 1);
 		mode = cmd->ncmd.backgnd;
+		args.pip[0] = -1;
+		args.pip[1] = -1;
 		if (flags & EV_BACKCMD) {
 			mode = FORK_NOJOB;
-			if (sh_pipe(psh, pip) < 0)
+			if (sh_pipe(psh, args.pip) < 0)
 				error(psh, "Pipe call failed");
 		}
+
+		args.backcmd = backcmd;
+		args.flags = flags;
+		args.path = path;
+#ifdef KASH_USE_FORKSHELL2
+		forkshell2(psh, jp, cmd, mode, evalcommand_child, cmd,
+		           &args, sizeof(args), evalcommand_setup_child);
+		evalcommand_parent(psh, flags, args.lastarg, &args.smark, mode, jp,
+						   args.pip, backcmd);
+#else
 		if (forkshell(psh, jp, cmd, mode) != 0) {
-			evalcommand_parent(psh, flags, args.lastarg, &args.smark, mode, jp, pip, backcmd);
+			evalcommand_parent(psh, flags, args.lastarg, &args.smark, mode, jp,
+							   args.pip, backcmd);
 			return;	/* at end of routine */
 		}
-
-		if (flags & EV_BACKCMD) {
-                        FORCEINTON;
-			shfile_close(&psh->fdtab, pip[0]);
-			if (pip[1] != 1) {
-				movefd(psh, pip[1], 1);
-			}
-		}
-		flags |= EV_EXIT;
-
+		evalcommand_child(psh, cmd, &args);
+#endif
+	} else {
 		args.backcmd = backcmd;
 		args.flags = flags;
@@ -1164,10 +1242,4 @@
 		evalcommand_doit(psh, cmd, &args);
 	}
-	else {
-		args.backcmd = backcmd;
-		args.flags = flags;
-		args.path = path;
-		evalcommand_doit(psh, cmd, &args);
-	}
 }
 
@@ -1188,5 +1260,5 @@
 		if (goodname(n->ncmd.args->narg.text))
 			find_command(psh, n->ncmd.args->narg.text, &entry, 0,
-				     pathval(psh));
+				         pathval(psh));
 }
 
Index: trunk/src/kash/exec.c
===================================================================
--- trunk/src/kash/exec.c	(revision 3436)
+++ trunk/src/kash/exec.c	(revision 3437)
@@ -150,5 +150,5 @@
 	} else {
 		/* Before we search the PATH, transform kmk_builtin_% to kmk_% so we don't
-		   need to be too careful mixing internal and external kmk command. */
+		   need to be too careful mixing internal and external kmk commands. */
 		if (   argv0len > 12
 		    && argv0len < 42
Index: trunk/src/kash/generated/nodes.h
===================================================================
--- trunk/src/kash/generated/nodes.h	(revision 3436)
+++ trunk/src/kash/generated/nodes.h	(revision 3437)
@@ -102,6 +102,6 @@
 struct nfile {
       int type;
+      int fd;
       union node *next;
-      int fd;
       union node *fname;
       char *expfname;
@@ -111,6 +111,6 @@
 struct ndup {
       int type;
+      int fd;
       union node *next;
-      int fd;
       int dupfd;
       union node *vname;
@@ -120,6 +120,6 @@
 struct nhere {
       int type;
+      int fd;
       union node *next;
-      int fd;
       union node *doc;
 };
Index: trunk/src/kash/jobs.c
===================================================================
--- trunk/src/kash/jobs.c	(revision 3436)
+++ trunk/src/kash/jobs.c	(revision 3437)
@@ -807,5 +807,6 @@
 int forkshell2(struct shinstance *psh, struct job *jp, union node *n, int mode,
 	       int (*child)(struct shinstance *, void *, union node *),
-	       union node *nchild, void *argp, size_t arglen)
+	       union node *nchild, void *argp, size_t arglen,
+	       void (*setupchild)(struct shinstance *, struct shinstance *, void *))
 {
 	pid_t pid;
@@ -816,5 +817,4 @@
 	{
 		/* child */
-		(void)arglen;
 		forkchild(psh, jp, n, mode);
 		sh_exit(psh, child(psh, nchild, argp));
@@ -827,4 +827,6 @@
 	TRACE((psh, "Fork failed, errno=%d\n", errno));
 	INTON;
+	(void)arglen;
+	(void)setupchild;
 	error(psh, "Cannot fork");
 	return -1; /* won't get here */
Index: trunk/src/kash/jobs.h
===================================================================
--- trunk/src/kash/jobs.h	(revision 3436)
+++ trunk/src/kash/jobs.h	(revision 3437)
@@ -98,5 +98,6 @@
 int forkshell2(struct shinstance *, struct job *, union node *, int,
 	       int (*child)(struct shinstance *, void *, union node *),
-	       union node *, void *, size_t);
+	       union node *, void *, size_t,
+	       void (*setupchild)(struct shinstance *, struct shinstance *, void *));
 #else
 int forkshell(struct shinstance *, struct job *, union node *, int);
Index: trunk/src/kash/memalloc.c
===================================================================
--- trunk/src/kash/memalloc.c	(revision 3436)
+++ trunk/src/kash/memalloc.c	(revision 3437)
@@ -146,4 +146,16 @@
 	psh->stacknleft -= (int)nbytes;
 	return p;
+}
+
+
+char *
+stsavestr(struct shinstance *psh, const char *src)
+{
+	if (src) {
+		size_t size = strlen(src) + 1;
+		char *dst = (char *)stalloc(psh, size);
+		return (char *)memcpy(dst, src, size);
+	}
+	return NULL;
 }
 
Index: trunk/src/kash/memalloc.h
===================================================================
--- trunk/src/kash/memalloc.h	(revision 3436)
+++ trunk/src/kash/memalloc.h	(revision 3437)
@@ -52,4 +52,5 @@
 char *savestr(struct shinstance *, const char *);
 pointer stalloc(struct shinstance *, size_t);
+char *stsavestr(struct shinstance *, const char *);
 void stunalloc(struct shinstance *, pointer);
 void setstackmark(struct shinstance *, struct stackmark *);
Index: trunk/src/kash/nodetypes
===================================================================
--- trunk/src/kash/nodetypes	(revision 3436)
+++ trunk/src/kash/nodetypes	(revision 3437)
@@ -118,6 +118,6 @@
 NAPPEND nfile			# fd>> fname
 	type	  int
-	next	  nodeptr		# next redirection in list
-	fd	  int			# file descriptor being redirected
+	fd	  int			# file descriptor being redirected (must match ndup)
+	next	  nodeptr		# next redirection in list         (must match ndup)
 	fname	  nodeptr		# file name, in a NARG node
 	expfname  temp	char *expfname	# actual file name
@@ -126,6 +126,6 @@
 NFROMFD ndup			# fd>&dupfd
 	type	  int
-	next	  nodeptr		# next redirection in list
-	fd	  int			# file descriptor being redirected
+	fd	  int			# file descriptor being redirected (must match nfile)
+	next	  nodeptr		# next redirection in list         (must match nfile)
 	dupfd	  int			# file descriptor to duplicate
 	vname	  nodeptr		# file name if fd>&$var
@@ -135,6 +135,6 @@
 NXHERE nhere			# fd<<!
 	type	  int
-	next	  nodeptr		# next redirection in list
-	fd	  int			# file descriptor being redirected
+	fd	  int			# file descriptor being redirected (must match nfile)
+	next	  nodeptr		# next redirection in list         (must match nfile)
 	doc	  nodeptr		# input to command (NARG node)
 
Index: trunk/src/kash/parser.c
===================================================================
--- trunk/src/kash/parser.c	(revision 3436)
+++ trunk/src/kash/parser.c	(revision 3437)
@@ -1197,6 +1197,9 @@
 
 parseredir: {
+	union node *np;
 	char fd = *out;
-	union node *np;
+	char dummy[   sizeof(struct nfile) >= sizeof(struct ndup)
+	           && sizeof(struct nfile) >= sizeof(struct nhere) ? 1 : 0];
+	(void)dummy;
 
 	np = (union node *)stalloc(psh, sizeof (struct nfile));
@@ -1218,8 +1221,4 @@
 		switch (c = pgetc(psh)) {
 		case '<':
-			if (sizeof (struct nfile) != sizeof (struct nhere)) {
-				np = (union node *)stalloc(psh, sizeof (struct nhere));
-				np->nfile.fd = 0;
-			}
 			np->type = NHERE;
 			psh->heredoc = (struct heredoc *)stalloc(psh, sizeof (struct heredoc));
@@ -1417,5 +1416,5 @@
 
 			case '\\':
-                                if ((pc = pgetc(psh)) == '\n') {
+				if ((pc = pgetc(psh)) == '\n') {
 					psh->plinno++;
 					if (psh->doprompt)
@@ -1431,7 +1430,6 @@
 					continue;
 				}
-                                if (pc != '\\' && pc != '`' && pc != '$'
-                                    && (!ISDBLQUOTE() || pc != '"'))
-                                        STPUTC(psh, '\\', pout);
+				if (pc != '\\' && pc != '`' && pc != '$' && (!ISDBLQUOTE() || pc != '"'))
+					STPUTC(psh, '\\', pout);
 				break;
 
@@ -1779,2 +1777,160 @@
 	}
 }
+
+/*
+ * Helper to copyparsetree.
+ */
+static struct nodelist *
+copynodelist(shinstance *psh, struct nodelist *src)
+{
+	struct nodelist *ret = NULL;
+	if (src) {
+		struct nodelist **ppnext = &ret;
+		while (src) {
+			struct nodelist *dst = stalloc(psh, sizeof(*dst));
+			dst->next = NULL;
+			*ppnext = dst;
+			ppnext = &dst->next;
+			dst->n = copyparsetree(psh, src->n);
+		}
+	}
+	return ret;
+}
+
+/*
+ * Duplicates a node tree.
+ *
+ * Note! This could probably be generated from nodelist.
+ */
+union node *
+copyparsetree(shinstance *psh, union node *src)
+{
+	/** @todo Try avoid recursion for one of the sub-nodes, esp. when there
+	 *  	  is a list like 'next' one. */
+	union node *ret;
+	if (src) {
+		int const type = src->type;
+		switch (type) {
+			case NSEMI:
+			case NAND:
+			case NOR:
+			case NWHILE:
+			case NUNTIL:
+				ret = (union node *)stalloc(psh, sizeof(src->nbinary));
+				ret->nbinary.type = type;
+				ret->nbinary.ch1  = copyparsetree(psh, src->nbinary.ch1);
+				ret->nbinary.ch2  = copyparsetree(psh, src->nbinary.ch2);
+				break;
+
+			case NCMD:
+				ret = (union node *)stalloc(psh, sizeof(src->ncmd));
+				ret->ncmd.type     = NCMD;
+				ret->ncmd.backgnd  = src->ncmd.backgnd;
+				ret->ncmd.args     = copyparsetree(psh, src->ncmd.args);
+				ret->ncmd.redirect = copyparsetree(psh, src->ncmd.redirect);
+				break;
+
+			case NPIPE:
+				ret = (union node *)stalloc(psh, sizeof(src->npipe));
+				ret->npipe.type     = NPIPE;
+				ret->npipe.backgnd  = src->ncmd.backgnd;
+				ret->npipe.cmdlist  = copynodelist(psh, src->npipe.cmdlist);
+				break;
+
+			case NREDIR:
+			case NBACKGND:
+			case NSUBSHELL:
+				ret = (union node *)stalloc(psh, sizeof(src->nredir));
+				ret->nredir.type     = type;
+				ret->nredir.n        = copyparsetree(psh, src->nredir.n);
+				ret->nredir.redirect = copyparsetree(psh, src->nredir.redirect);
+				break;
+
+			case NIF:
+				ret = (union node *)stalloc(psh, sizeof(src->nif));
+				ret->nif.type        = NIF;
+				ret->nif.test        = copyparsetree(psh, src->nif.test);
+				ret->nif.ifpart      = copyparsetree(psh, src->nif.ifpart);
+				ret->nif.elsepart    = copyparsetree(psh, src->nif.elsepart);
+				break;
+
+			case NFOR:
+				ret = (union node *)stalloc(psh, sizeof(src->nfor));
+				ret->nfor.type       = NFOR;
+				ret->nfor.args       = copyparsetree(psh, src->nfor.args);
+				ret->nfor.body       = copyparsetree(psh, src->nfor.body);
+				ret->nfor.var        = stsavestr(psh, src->nfor.var);
+				break;
+
+			case NCASE:
+				ret = (union node *)stalloc(psh, sizeof(src->ncase));
+				ret->ncase.type      = NCASE;
+				ret->ncase.expr      = copyparsetree(psh, src->ncase.expr);
+				ret->ncase.cases     = copyparsetree(psh, src->ncase.cases);
+				break;
+
+			case NCLIST:
+				ret = (union node *)stalloc(psh, sizeof(src->nclist));
+				ret->nclist.type     = NCLIST;
+				ret->nclist.next     = copyparsetree(psh, src->nclist.next);
+				ret->nclist.pattern  = copyparsetree(psh, src->nclist.pattern);
+				ret->nclist.body     = copyparsetree(psh, src->nclist.body);
+				break;
+
+			case NDEFUN:
+			case NARG:
+				ret = (union node *)stalloc(psh, sizeof(src->narg));
+				ret->narg.type       = type;
+				ret->narg.next       = copyparsetree(psh, src->narg.next);
+				ret->narg.text       = stsavestr(psh, src->narg.text);
+				ret->narg.backquote  = copynodelist(psh, src->narg.backquote);
+				break;
+
+			case NTO:
+			case NCLOBBER:
+			case NFROM:
+			case NFROMTO:
+			case NAPPEND:
+				ret = (union node *)stalloc(psh, sizeof(src->nfile));
+				ret->nfile.type      = type;
+				ret->nfile.fd        = src->nfile.fd;
+				ret->nfile.next      = copyparsetree(psh, src->nfile.next);
+				ret->nfile.fname     = copyparsetree(psh, src->nfile.fname);
+				ret->nfile.expfname  = stsavestr(psh, src->nfile.expfname);
+				break;
+
+			case NTOFD:
+			case NFROMFD:
+				ret = (union node *)stalloc(psh, sizeof(src->ndup));
+				ret->ndup.type       = type;
+				ret->ndup.fd         = src->ndup.fd;
+				ret->ndup.next       = copyparsetree(psh, src->ndup.next);
+				ret->ndup.dupfd      = src->ndup.dupfd;
+				ret->ndup.vname      = copyparsetree(psh, src->ndup.vname);
+				break;
+
+			case NHERE:
+			case NXHERE:
+				ret = (union node *)stalloc(psh, sizeof(src->nhere));
+				ret->nhere.type      = type;
+				ret->nhere.fd        = src->nhere.fd;
+				ret->nhere.next      = copyparsetree(psh, src->nhere.next);
+				ret->nhere.doc       = copyparsetree(psh, src->nhere.doc);
+				break;
+
+			case NNOT:
+				ret = (union node *)stalloc(psh, sizeof(src->nnot));
+				ret->nnot.type      = NNOT;
+				ret->nnot.com       = copyparsetree(psh, src->nnot.com);
+				break;
+
+			default:
+				error(psh, "Unknown node type: %d (node=%p)", src->type, src);
+				return NULL;
+		}
+	} else {
+		ret = NULL;
+	}
+	return ret;
+}
+
Index: trunk/src/kash/parser.h
===================================================================
--- trunk/src/kash/parser.h	(revision 3436)
+++ trunk/src/kash/parser.h	(revision 3437)
@@ -84,4 +84,5 @@
 int goodname(const char *);
 const char *getprompt(struct shinstance *, void *);
+union node *copyparsetree(shinstance *, union node *);
 
 #endif
Index: trunk/src/kash/redir.c
===================================================================
--- trunk/src/kash/redir.c	(revision 3436)
+++ trunk/src/kash/redir.c	(revision 3437)
@@ -289,5 +289,5 @@
 		args.len = len;
 		forkshell2(psh, (struct job *)NULL, (union node *)NULL, FORK_NOJOB,
-			   openhere_child, redir, &args, sizeof(args));
+			   openhere_child, redir, &args, sizeof(args), NULL);
 	}
 #else
Index: trunk/src/kash/shinstance.c
===================================================================
--- trunk/src/kash/shinstance.c	(revision 3436)
+++ trunk/src/kash/shinstance.c	(revision 3437)
@@ -241,5 +241,5 @@
     if (psh)
     {
-        /* Init it enought for sh_destroy() to not get upset */
+        /* Init it enough for sh_destroy() to not get upset */
           /* ... */
 
