diff --git a/ksh.changes b/ksh.changes index 17fe846..7157fff 100644 --- a/ksh.changes +++ b/ksh.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Thu Sep 19 08:43:37 UTC 2013 - werner@suse.de + +- Make vmbalance awk script more clear for small vm page sizes + +------------------------------------------------------------------- +Wed Sep 18 11:09:34 UTC 2013 - werner@suse.de + +- Extend patch ksh93-fdstatus.dif to solve bnc#835885 +- Modify patch ksh93-builtin.dif to reduce timeouts of pty utility + ------------------------------------------------------------------- Tue Aug 13 09:59:45 UTC 2013 - dmueller@suse.com diff --git a/ksh.spec b/ksh.spec index 4f4d816..48b927d 100644 --- a/ksh.spec +++ b/ksh.spec @@ -245,6 +245,9 @@ fi test -s $fd -a ! -c $fd && break || true done set -- $(readlink $fd) +grep pts /proc/mounts +ls -ld /dev/ptmx +ls -ld /dev/pts exec ./sigexec $SHELL ${1+"$@"} fi IGNORED=0x$(ps --no-headers -o ignored $$) @@ -530,7 +533,7 @@ fi typeset -i failed=0 ln -sf ${root}/lib ${test}/../ sed -ri '/^L[[:blank:]]/a \t 8000' pty.sh - sed -ri 's/(SECONDS[[:blank:]]*>[[:blank:]]*)([[:digit:]]+)/\18/p' signal.sh + sed -ri 's/(SECONDS[[:blank:]]*>[[:blank:]]*)([[:digit:]]+)/\18/' signal.sh unset ${!LESS*} ${SHELL} shtests exec 3> ${TMPDIR:-/tmp}/log @@ -662,7 +665,7 @@ fi ln -sf ../man1/ksh93.1ast.gz %{buildroot}/%{_mandir}/man1/ksh.1ast.gz ln -sf ../man1/ksh93.1ast.gz %{buildroot}/%{_mandir}/man1/rksh.1ast.gz %else - install -m 0644 man/man1/sh.1ast %{buildroot}%{_mandir}/man1/ksh.1ast + install -m 0644 man/man1/sh.1 %{buildroot}%{_mandir}/man1/ksh.1ast ln -sf ../man1/ksh.1ast.gz %{buildroot}/%{_mandir}/man1/rksh.1ast.gz %endif install -m 0644 man/man1/shcomp.1ast %{buildroot}%{_mandir}/man1/shcomp.1ast diff --git a/ksh93-builtin.dif b/ksh93-builtin.dif index 3ba5953..e45da7d 100644 --- a/ksh93-builtin.dif +++ b/ksh93-builtin.dif @@ -1,6 +1,6 @@ --- src/cmd/builtin/pty.c +++ src/cmd/builtin/pty.c 2013-02-01 15:59:52.697952156 +0000 -@@ -216,6 +216,12 @@ mkpty(int* master, int* slave) +@@ -216,13 +216,19 @@ mkpty(int* master, int* slave) #if !_lib_openpty char* sname; #endif @@ -13,6 +13,24 @@ /* * some systems hang hard during the handshake * if you know why then please let us know + */ + +- alarm(4); +- if (tcgetattr(STDERR_FILENO, &tty) >= 0) ++ alarm(6); ++ if (tcgetattr(sffileno(sfstderr), &tty) >= 0) + ttyp = &tty; + else + { +@@ -230,7 +236,7 @@ mkpty(int* master, int* slave) + error(-1, "unable to get standard error terminal attributes"); + } + #ifdef TIOCGWINSZ +- if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) >= 0) ++ if (ioctl(sffileno(sfstderr), TIOCGWINSZ, &win) >= 0) + winp = &win; + else + { @@ -238,6 +244,12 @@ mkpty(int* master, int* slave) error(-1, "unable to get standard error window size"); } @@ -36,6 +54,87 @@ alarm(0); return 0; } +@@ -317,9 +332,13 @@ process(Sfio_t* mp, Sfio_t* lp, int dela + char* s; + Sfio_t* ip; + Sfio_t* sps[2]; ++ struct stat dst; ++ struct stat fst; + + ip = sfstdin; +- for (;;) ++ if (!fstat(sffileno(ip), &dst) && !stat("/dev/null", &fst) && dst.st_dev == fst.st_dev && dst.st_ino == fst.st_ino) ++ ip = 0; ++ do + { + i = 0; + t = timeout; +@@ -336,39 +355,39 @@ process(Sfio_t* mp, Sfio_t* lp, int dela + { + if (n < 0) + error(ERROR_SYSTEM|2, "poll failed"); +- if (t < 0) +- break; ++ break; + } +- else +- for (i = 0; i < n; i++) ++ for (i = t = 0; i < n; i++) ++ { ++ if (!(sfvalue(sps[i]) & SF_READ)) ++ /*skip*/; ++ else if (sps[i] == mp) + { +- if (!(sfvalue(sps[i]) & SF_READ)) +- /*skip*/; +- else if (sps[i] == mp) ++ t++; ++ if (!(s = (char*)sfreserve(mp, SF_UNBOUND, -1))) + { +- if (!(s = (char*)sfreserve(mp, SF_UNBOUND, -1))) +- { +- sfclose(mp); +- mp = 0; +- } +- else if ((r = sfvalue(mp)) > 0 && (sfwrite(sfstdout, s, r) != r || sfsync(sfstdout))) +- { +- error(ERROR_SYSTEM|2, "output write failed"); +- goto done; +- } ++ sfclose(mp); ++ mp = 0; + } +- else ++ else if ((r = sfvalue(mp)) > 0 && (sfwrite(sfstdout, s, r) != r || sfsync(sfstdout))) + { +- if (!(s = sfgetr(ip, '\n', 1))) +- ip = 0; +- else if (sfputr(mp, s, '\r') < 0 || sfsync(mp)) +- { +- error(ERROR_SYSTEM|2, "write failed"); +- goto done; +- } ++ error(ERROR_SYSTEM|2, "output write failed"); ++ goto done; + } + } +- } ++ else ++ { ++ t++; ++ if (!(s = sfgetr(ip, '\n', 1))) ++ ip = 0; ++ else if (sfputr(mp, s, '\r') < 0 || sfsync(mp)) ++ { ++ error(ERROR_SYSTEM|2, "write failed"); ++ goto done; ++ } ++ } ++ } ++ } while (t); + done: + if (mp) + sfclose(mp); --- src/cmd/builtin/what.c +++ src/cmd/builtin/what.c 2012-02-13 11:02:18.645933606 +0000 @@ -68,7 +68,7 @@ static struct diff --git a/ksh93-fdstatus.dif b/ksh93-fdstatus.dif index a02ff87..375452c 100644 --- a/ksh93-fdstatus.dif +++ b/ksh93-fdstatus.dif @@ -1,9 +1,297 @@ -| Fix for bnc#814135 and bnc#808449 +| Fix for bnc#814135, bnc#808449, and bnc#835885 | - crash in bestreclaim() after traversing a memory block with a very large size (ksh) | - set -k does not work properly with ksh-93t-13.17 and higher -| This is a backport from the alpha version ksh93v-2013-04-22. +| - Problem after update of ksh from ksh-93u-0.14.1 to ksh-93u-0.22.1 +| This is a backport from the beta version ksh93v-2013-08-29 +--- src/cmd/ksh93/bltins/read.c ++++ src/cmd/ksh93/bltins/read.c 2013-09-17 15:01:33.000000000 +0000 +@@ -280,24 +280,25 @@ int sh_readline(register Shell_t *shp,ch + if(size || (flags>>D_FLAG)) /* delimiter not new-line or fixed size read */ + { + if((shp->fdstatus[fd]&IOTTY) && !keytrap) +- tty_raw(fd,1); ++ tty_raw(sffileno(iop),1); + if(!(flags&(N_FLAG|NN_FLAG))) + { + delim = ((unsigned)flags)>>D_FLAG; + ep->e_nttyparm.c_cc[VEOL] = delim; + ep->e_nttyparm.c_lflag |= ISIG; +- tty_set(fd,TCSADRAIN,&ep->e_nttyparm); ++ tty_set(sffileno(iop),TCSADRAIN,&ep->e_nttyparm); + } + #if defined(__linux__) + else if ((shp->fdstatus[fd]&(IOTTY|IONOSEEK))==0) + { + struct stat st; +- if ((fstat(fd, &st) == 0) && S_ISFIFO(st.st_mode)) ++ int fn = sffileno(iop); ++ if ((fstat(fn, &st) == 0) && S_ISFIFO(st.st_mode)) + { + int fdflg; +- if (((fdflg = fcntl(fd, F_GETFL)) != -1) && !(fdflg & O_NONBLOCK)) +- fcntl(fd, F_SETFL, fdflg|O_NONBLOCK); +- shp->fdstatus[fd] |= IONOSEEK; ++ if (((fdflg = fcntl(fn, F_GETFL)) != -1) && !(fdflg & O_NONBLOCK)) ++ fcntl(fn, F_SETFL, fdflg|O_NONBLOCK); ++ shp->fdstatus[fn] |= IONOSEEK; + } + } + #endif +@@ -342,7 +343,7 @@ int sh_readline(register Shell_t *shp,ch + size = nv_size(np); + } + was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0; +- if(fd==0) ++ if(sffileno(iop)==0) + was_share = (sfset(iop,SF_SHARE,shp->redir0!=2)&SF_SHARE)!=0; + if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) + { +@@ -366,7 +367,7 @@ int sh_readline(register Shell_t *shp,ch + else + end = var + sizeof(buf) - 1; + up = cur = var; +- if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0) ++ if((sfset(iop,SF_SHARE,1)&SF_SHARE) && sffileno(iop)!=0) + was_share = 1; + if(size==0) + { +@@ -473,7 +474,7 @@ int sh_readline(register Shell_t *shp,ch + timerdel(timeslot); + if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size)) + { +- if((c==size) && np->nvalue.cp && !nv_isarray(np)) ++ if((c==size) && np->nvalue.cp && !nv_isarray(np) && !np->nvfun) + memcpy((char*)np->nvalue.cp,var,c); + else + { +@@ -819,7 +820,7 @@ done: + sfset(iop,SF_SHARE,0); + nv_close(np); + if((shp->fdstatus[fd]&IOTTY) && !keytrap) +- tty_cooked(fd); ++ tty_cooked(sffileno(iop)); + if(flags&S_FLAG) + hist_flush(shp->gd->hist_ptr); + if(jmpval > 1) +--- src/cmd/ksh93/bltins/trap.c ++++ src/cmd/ksh93/bltins/trap.c 2013-09-17 14:37:19.000000000 +0000 +@@ -116,8 +116,7 @@ int b_trap(int argc,char *argv[],Shbltin + continue; + } + shp->st.otrap = 0; +- if(shp->st.trap[sig]) +- free(shp->st.trap[sig]); ++ arg = shp->st.trap[sig]; + shp->st.trap[sig] = 0; + if(!clear && *action) + shp->st.trap[sig] = strdup(action); +@@ -128,6 +127,8 @@ int b_trap(int argc,char *argv[],Shbltin + else + shp->trapnote = 0; + } ++ if(arg) ++ free(arg); + continue; + } + if(sig>shp->gd->sigmax) +--- src/cmd/ksh93/bltins/typeset.c ++++ src/cmd/ksh93/bltins/typeset.c 2013-09-13 16:26:49.000000000 +0000 +@@ -533,6 +533,7 @@ static int setall(char **argv,regist + char *last = 0; + int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC|NV_MOVE)); + int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY); ++ size_t len; + Shell_t *shp =tp->sh; + if(!shp->prefix) + { +@@ -579,7 +580,7 @@ static int setall(char **argv,regist + np = sh_fsearch(shp,name,NV_ADD|HASH_NOSCOPE); + else + #endif /* SHOPT_NAMESPACE */ +- np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE); ++ np = nv_open(name,sh_subfuntree(shp,1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE); + } + else + { +@@ -640,7 +641,10 @@ static int setall(char **argv,regist + path_alias(np,path_absolute(shp,nv_name(np),NIL(Pathcomp_t*))); + continue; + } +- np = nv_open(name,troot,nvflags|((nvflags&NV_ASSIGN)?0:NV_ARRAY)|((iarray|(nvflags&(NV_REF|NV_NOADD)==NV_REF))?NV_FARRAY:0)); ++ if(shp->nodelist && (len=strlen(name)) && name[len-1]=='@') ++ np = *shp->nodelist++; ++ else ++ np = nv_open(name,troot,nvflags|((nvflags&NV_ASSIGN)?0:NV_ARRAY)|((iarray|(nvflags&(NV_REF|NV_NOADD)==NV_REF))?NV_FARRAY:0)); + if(!np) + continue; + if(nv_isnull(np) && !nv_isarray(np) && nv_isattr(np,NV_NOFREE)) +@@ -676,7 +680,7 @@ static int setall(char **argv,regist + } + if(!nv_isarray(np) && !strchr(name,'=') && !(shp->envlist && nv_onlist(shp->envlist,name))) + { +- if(comvar || (shp->last_root==shp->var_tree && (tp->tp || (!shp->st.real_fun && (nvflags&NV_STATIC)) || (!(flag&(NV_EXPORT|NV_RDONLY)) && nv_isattr(np,(NV_EXPORT|NV_IMPORT))==(NV_EXPORT|NV_IMPORT))))) ++ if(comvar || (shp->last_root==shp->var_tree && ((tp->tp && tp->tp!=nv_type(np)) || (!shp->st.real_fun && (nvflags&NV_STATIC)) || (!(flag&(NV_EXPORT|NV_RDONLY)) && nv_isattr(np,(NV_EXPORT|NV_IMPORT))==(NV_EXPORT|NV_IMPORT))))) + { + if((flag&(NV_HOST|NV_INTEGER))!=NV_HOST) + _nv_unset(np,0); +@@ -1168,14 +1172,14 @@ static int unall(int argc, char **argv, + { + name = sh_optunalias; + if(shp->subshell) +- troot = sh_subaliastree(0); ++ troot = sh_subaliastree(shp,0); + } + else + name = sh_optunset; + while(r = optget(argv,name)) switch(r) + { + case 'f': +- troot = sh_subfuntree(1); ++ troot = sh_subfuntree(shp,1); + break; + case 'a': + all=1; +--- src/cmd/ksh93/edit/edit.c ++++ src/cmd/ksh93/edit/edit.c 2013-09-16 13:04:37.000000000 +0000 +@@ -1414,12 +1414,12 @@ int ed_internal(const char *src, genchar + int ed_external(const genchar *src, char *dest) + { + register genchar wc; +- register int c,size; + register char *dp = dest; + char *dpmax = dp+sizeof(genchar)*MAXLINE-2; + if((char*)src == dp) + { +- char buffer[MAXLINE*sizeof(genchar)]; ++ int c; ++ char buffer[MAXLINE*sizeof(genchar)] = ""; + c = ed_external(src,buffer); + + #ifdef _lib_wcscpy +@@ -1431,6 +1431,7 @@ int ed_external(const genchar *src, char + } + while((wc = *src++) && dp= 0) + { +- close(acctfd); ++ sh_close(acctfd); + acctfd = n; + } + } +@@ -203,7 +203,7 @@ static int sh_checkaudit(History_t *hp, + } + while(*cp==';' || *cp==' '); + done: +- close(fd); ++ sh_close(fd); + return(r); + + } +@@ -272,14 +272,14 @@ retry: + int n; + if((n=fcntl(fd,F_DUPFD,10))>=0) + { +- close(fd); ++ sh_close(fd); + fd=n; + } + } + /* make sure that file has history file format */ + if(hsize && hist_check(fd)) + { +- close(fd); ++ sh_close(fd); + hsize = 0; + if(unlink(cp)>=0) + goto retry; +@@ -308,7 +308,7 @@ retry: + for(histmask=16;histmask <= maxlines; histmask <<=1 ); + if(!(hp=new_of(History_t,(--histmask)*sizeof(off_t)))) + { +- close(fd); ++ sh_close(fd); + return(0); + } + shgd->hist_ptr = hist_ptr = hp; +@@ -425,7 +425,7 @@ void hist_close(register History_t *hp) + #if SHOPT_ACCTFILE + if(acctfd) + { +- close(acctfd); ++ sh_close(acctfd); + acctfd = 0; + } + #endif /* SHOPT_ACCTFILE */ +@@ -470,7 +470,7 @@ static History_t* hist_trim(History_t *h + /* The unlink can fail on windows 95 */ + int fd; + char *last, *name=hist_old->histname; +- close(sffileno(hist_old->histfp)); ++ sh_close(sffileno(hist_old->histfp)); + tmpname = (char*)malloc(strlen(name)+14); + if(last = strrchr(name,'/')) + { +@@ -736,7 +736,7 @@ again: + hist_marker(buff,hp->histind); + write(fd,(char*)hist_stamp,2); + write(fd,buff,HIST_MARKSZ); +- close(fd); ++ sh_close(fd); + } + } + last = 0; +@@ -1195,7 +1195,7 @@ static int hist_exceptf(Sfio_t* fp, int + if(errno==ENOSPC || hp->histwfail++ >= 10) + return(0); + /* write failure could be NFS problem, try to re-open */ +- close(oldfd=sffileno(fp)); ++ sh_close(oldfd=sffileno(fp)); + if((newfd=open(hp->histname,O_BINARY|O_APPEND|O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) >= 0) + { + if(fcntl(newfd, F_DUPFD, oldfd) !=oldfd) +--- src/cmd/ksh93/include/defs.h ++++ src/cmd/ksh93/include/defs.h 2013-09-13 14:19:35.000000000 +0000 +@@ -160,6 +160,7 @@ struct shared + Namval_t *namespace; /* current active namespace*/ \ + Namval_t *last_table; /* last table used in last nv_open */ \ + Namval_t *prev_table; /* previous table used in nv_open */ \ ++ Namval_t **nodelist; /* for decl commands */ \ + Sfio_t *outpool; /* ouput stream pool */ \ + long timeout; /* read timeout */ \ + short curenv; /* current subshell number */ \ +@@ -182,6 +183,8 @@ struct shared + pid_t spid; /* subshell process id */ \ + pid_t pipepid; \ + pid_t outpipepid; \ ++ pid_t *procsub; /* pids for >() argument */ \ ++ int nprocsub; /* number of pids in procsub */ \ + int topfd; \ + int savesig; \ + unsigned char *sigflag; /* pointer to signal states */ \ +@@ -423,10 +426,10 @@ extern void sh_printopts(Shopt_t,int,Sh + extern int sh_readline(Shell_t*,char**,volatile int,int,ssize_t,long); + extern Sfio_t *sh_sfeval(char*[]); + extern void sh_setmatch(Shell_t*,const char*,int,int,int[],int); +-extern Dt_t *sh_subaliastree(int); ++extern Dt_t *sh_subaliastree(Shell_t*,int); + extern void sh_scope(Shell_t*, struct argnod*, int); + extern Namval_t *sh_scoped(Shell_t*, Namval_t*); +-extern Dt_t *sh_subfuntree(int); ++extern Dt_t *sh_subfuntree(Shell_t*,int); + extern void sh_subjobcheck(pid_t); + extern int sh_subsavefd(int); + extern void sh_subtmpfile(Shell_t*); --- src/cmd/ksh93/include/io.h -+++ src/cmd/ksh93/include/io.h 2013-04-23 09:27:07.997439763 +0000 ++++ src/cmd/ksh93/include/io.h 2013-09-09 16:35:27.000000000 +0000 @@ -81,6 +81,7 @@ extern void sh_iosave(Shell_t *, int,in extern int sh_iovalidfd(Shell_t*, int); extern int sh_inuse(Shell_t*, int); @@ -12,9 +300,1201 @@ extern int sh_chkopen(const char*); extern int sh_ioaccess(int,int); extern int sh_devtofd(const char*); +--- src/cmd/ksh93/include/jobs.h ++++ src/cmd/ksh93/include/jobs.h 2013-09-16 13:36:02.000000000 +0000 +@@ -103,6 +103,7 @@ struct jobs + pid_t mypid; /* process id of shell */ + pid_t mypgid; /* process group id of shell */ + pid_t mytgid; /* terminal group id of shell */ ++ pid_t lastpost; /* last job posted */ + int curjobid; + unsigned int in_critical; /* >0 => in critical region */ + int savesig; /* active signal */ +@@ -152,11 +153,11 @@ extern struct jobs job; + #define job_lock() (job.in_critical++) + #define job_unlock() \ + do { \ +- int sig; \ +- if (!--job.in_critical && (sig = job.savesig)) \ ++ int _sig; \ ++ if (!--job.in_critical && (_sig = job.savesig)) \ + { \ + if (!job.in_critical++ && !vmbusy()) \ +- job_reap(sig); \ ++ job_reap(_sig); \ + job.in_critical--; \ + } \ + } while(0) +--- src/cmd/ksh93/include/name.h ++++ src/cmd/ksh93/include/name.h 2013-09-11 13:02:16.000000000 +0000 +@@ -124,6 +124,7 @@ struct Ufunction + #define NV_PARAM NV_NODISC /* expansion use positional params */ + + /* This following are for use with nodes which are not name-values */ ++#define NV_DECL 0x20000000 + #define NV_TYPE 0x1000000 + #define NV_STATIC 0x2000000 + #define NV_COMVAR 0x4000000 +@@ -190,7 +191,7 @@ extern int nv_aimax(Namval_t*); + extern int nv_atypeindex(Namval_t*, const char*); + extern int nv_setnotify(Namval_t*,char **); + extern int nv_unsetnotify(Namval_t*,char **); +-extern void nv_setlist(struct argnod*, int, Namval_t*); ++extern Namval_t **nv_setlist(struct argnod*, int, Namval_t*); + extern struct argnod* nv_onlist(struct argnod*, const char*); + extern void nv_optimize(Namval_t*); + extern void nv_outname(Sfio_t*,char*, int); +--- src/cmd/ksh93/sh/args.c ++++ src/cmd/ksh93/sh/args.c 2013-09-12 14:17:44.000000000 +0000 +@@ -32,6 +32,7 @@ + #include "builtins.h" + #include "terminal.h" + #include "edit.h" ++#include "jobs.h" + #include "FEATURE/poll" + #if SHOPT_KIA + # include "shlex.h" +@@ -57,6 +58,7 @@ + #define PRINT 2 + + static char *null; ++static pid_t *procsub; + + /* The following order is determined by sh_optset */ + static const char optksh[] = PFSHOPT BASHOPT "DircabefhkmnpstuvxBCGEl" HFLAG; +@@ -717,6 +719,7 @@ char **sh_argbuild(Shell_t *shp,int *nar + return(ap->dolval+ap->dolbot); + } + shp->lastpath = 0; ++ procsub = shp->procsub; + *nargs = 0; + if(ac) + { +@@ -737,6 +740,8 @@ char **sh_argbuild(Shell_t *shp,int *nar + } + argp = arghead; + } ++ if(procsub) ++ *procsub = 0; + } + { + register char **comargn; +@@ -782,8 +787,9 @@ struct argnod *sh_argprocsub(Shell_t *sh + { + /* argument of the form <(cmd) or >(cmd) */ + register struct argnod *ap; +- int monitor, fd, pv[3]; ++ int nn, monitor, fd, pv[3]; + int subshell = shp->subshell; ++ pid_t pid0; + ap = (struct argnod*)stkseek(shp->stk,ARGVAL); + ap->argflag |= ARG_MAKE; + ap->argflag &= ~ARG_RAW; +@@ -794,18 +800,33 @@ struct argnod *sh_argprocsub(Shell_t *sh + sfwrite(shp->stk,e_devfdNN,8); + pv[2] = 0; + sh_pipe(pv); ++ sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0); + #else + pv[0] = -1; + shp->fifo = pathtemp(0,0,0,"ksh.fifo",0); + mkfifo(shp->fifo,S_IRUSR|S_IWUSR); + sfputr(shp->stk,shp->fifo,0); + #endif /* SHOPT_DEVFD */ +- sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0); + ap = (struct argnod*)stkfreeze(shp->stk,0); + shp->inpipe = shp->outpipe = 0; + if(monitor = (sh_isstate(SH_MONITOR)!=0)) + sh_offstate(SH_MONITOR); + shp->subshell = 0; ++#if SHOPT_DEVFD ++ fcntl(pv[fd],F_SETFD,0); ++ shp->fdstatus[pv[fd]] &= ~IOCLEX; ++#endif /* SHOPT_DEVFD */ ++ pid0=shp->procsub?*shp->procsub:0; ++ if(!shp->procsub) ++ shp->procsub = procsub = newof(0,pid_t,shp->nprocsub=4,0); ++ else if((nn=procsub-shp->procsub) >= shp->nprocsub) ++ { ++ shp->nprocsub += 3; ++ shp->procsub = newof(shp->procsub,pid_t,shp->nprocsub,0); ++ procsub = shp->procsub + nn; ++ } ++ if(pid0) ++ *shp->procsub = 0; + if(fd) + { + shp->inpipe = pv; +@@ -816,11 +837,14 @@ struct argnod *sh_argprocsub(Shell_t *sh + shp->outpipe = pv; + sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); + } ++ if(pid0) ++ *shp->procsub = pid0; ++ *procsub++ = job.lastpost; + shp->subshell = subshell; + if(monitor) + sh_onstate(SH_MONITOR); + #if SHOPT_DEVFD +- close(pv[1-fd]); ++ sh_close(pv[1-fd]); + sh_iosave(shp,-pv[fd], shp->topfd, (char*)0); + #else + free(shp->fifo); +--- src/cmd/ksh93/sh/arith.c ++++ src/cmd/ksh93/sh/arith.c 2013-09-13 13:44:25.000000000 +0000 +@@ -180,7 +180,10 @@ static Namval_t *scope(register Namval_t + { + ap = nv_arrayptr(np); + if(ap && !ap->table) ++ { + ap->table = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(ap->table,shp,1); ++ } + if(ap && ap->table && (nq=nv_search(nv_getsub(np),ap->table,NV_ADD))) + nq->nvenv = (char*)np; + if(nq && nv_isnull(nq)) +--- src/cmd/ksh93/sh/array.c ++++ src/cmd/ksh93/sh/array.c 2013-09-13 14:11:55.000000000 +0000 +@@ -79,6 +79,7 @@ struct assoc_array + + static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags) + { ++ Shell_t *shp = sh_getinterp(); + Namarr_t *aq; + #if SHOPT_FIXEDARRAY + struct fixed_array *fp; +@@ -95,6 +96,7 @@ static Namarr_t *array_scope(Namval_t *n + if(is_associative(aq)) + { + aq->scope = (void*)dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(aq->scope,shp,1); + dtview((Dt_t*)aq->scope,aq->table); + aq->table = (Dt_t*)aq->scope; + return(aq); +@@ -271,6 +273,7 @@ int nv_arrayisset(Namval_t *np, Namarr_t + */ + static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag) + { ++ Shell_t *shp=sh_getinterp(); + register struct index_array *ap = (struct index_array*)arp; + register union Value *up; + Namval_t *mp; +@@ -373,7 +376,10 @@ static Namval_t *array_find(Namval_t *np + { + char *cp; + if(!ap->header.table) ++ { + ap->header.table = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(ap->header.table,shp,1); ++ } + sfprintf(sh.strbuf,"%d",ap->cur); + cp = sfstruse(sh.strbuf); + mp = nv_search(cp, ap->header.table, NV_ADD); +@@ -402,6 +408,7 @@ static Namval_t *array_find(Namval_t *np + #if SHOPT_TYPEDEF + int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags) + { ++ Shell_t *shp = sh_getinterp(); + Namval_t *nq; + char *av[2]; + int rdonly = nv_isattr(np,NV_RDONLY); +@@ -410,7 +417,10 @@ int nv_arraysettype(Namval_t *np, Namval + av[1] = 0; + sh.last_table = 0; + if(!ap->table) ++ { + ap->table = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(ap->table,shp,1); ++ } + if(nq = nv_search(sub, ap->table, NV_ADD)) + { + if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0) +@@ -485,6 +495,7 @@ static Namfun_t *array_clone(Namval_t *n + if(ap->table) + { + ap->table = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(ap->table,shp,1); + if(ap->scope && !(flags&NV_COMVAR)) + { + ap->scope = ap->table; +@@ -854,7 +865,9 @@ static struct index_array *array_grow(Na + np->nvalue.cp=0; + if(nv_hasdisc(np,&array_disc) || (nv_type(np) && nv_isvtree(np))) + { ++ Shell_t *shp = sh_getinterp(); + ap->header.table = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(ap->header.table,shp,1); + mp = nv_search("0", ap->header.table,NV_ADD); + if(mp && nv_isnull(mp)) + { +@@ -1169,6 +1182,7 @@ int nv_nextsub(Namval_t *np) + */ + Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode) + { ++ Shell_t *shp = sh_getinterp(); + register struct index_array *ap = (struct index_array*)nv_arrayptr(np); + register int size = (mode&ARRAY_MASK); + #if SHOPT_FIXEDARRAY +@@ -1180,7 +1194,6 @@ Namval_t *nv_putsub(Namval_t *np,registe + { + if(sp) + { +- Shell_t *shp = sh_getinterp(); + if(ap && ap->xp && !strmatch(sp,"+([0-9])")) + { + Namval_t *mp = nv_namptr(ap->xp,0); +@@ -1258,7 +1271,10 @@ Namval_t *nv_putsub(Namval_t *np,registe + char *cp; + Namval_t *mp; + if(!ap->header.table) ++ { + ap->header.table = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(ap->header.table,shp,1); ++ } + sfprintf(sh.strbuf,"%d",ap->cur); + cp = sfstruse(sh.strbuf); + mp = nv_search(cp, ap->header.table, NV_ADD); +@@ -1666,6 +1682,7 @@ int nv_aimax(register Namval_t* np) + */ + void *nv_associative(register Namval_t *np,const char *sp,int mode) + { ++ Shell_t *shp = sh_getinterp(); + register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np); + register int type; + switch(mode) +@@ -1674,6 +1691,7 @@ void *nv_associative(register Namval_t * + if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array))) + { + ap->header.table = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(ap->header.table,shp,1); + ap->cur = 0; + ap->pos = 0; + ap->header.hdr.disc = &array_disc; +@@ -1742,7 +1760,6 @@ void *nv_associative(register Namval_t * + case NV_ANAME: + if(ap->cur) + { +- Shell_t *shp = sh_getinterp(); + if(!shp->instance && nv_isnull(ap->cur)) + return(NIL(void*)); + return((void*)ap->cur->nvname); +--- src/cmd/ksh93/sh/fault.c ++++ src/cmd/ksh93/sh/fault.c 2013-09-12 14:14:49.000000000 +0000 +@@ -518,6 +518,8 @@ void sh_exit(register int xno) + shp->exitval |= (sig=shp->lastsig); + if(pp && pp->mode>1) + cursig = -1; ++ if(shp->procsub) ++ *shp->procsub = 0; + #ifdef SIGTSTP + if(shp->trapnote&SH_SIGTSTP) + { +--- src/cmd/ksh93/sh/init.c ++++ src/cmd/ksh93/sh/init.c 2013-09-13 13:52:48.000000000 +0000 +@@ -1909,9 +1909,13 @@ static Init_t *nv_init(Shell_t *shp) + (OPTINDNOD)->nvalue.lp = (&shp->st.optindex); + /* set up the seconds clock */ + shp->alias_tree = inittree(shp,shtab_aliases); ++ dtuserdata(shp->alias_tree,shp,1); + shp->track_tree = dtopen(&_Nvdisc,Dtset); ++ dtuserdata(shp->track_tree,shp,1); + shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins); ++ dtuserdata(shp->bltin_tree,shp,1); + shp->fun_tree = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(shp->fun_tree,shp,1); + dtview(shp->fun_tree,shp->bltin_tree); + nv_mount(DOTSHNOD, "type", shp->typedict=dtopen(&_Nvdisc,Dtoset)); + nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0); +@@ -1954,6 +1958,7 @@ static Dt_t *inittree(Shell_t *shp,const + nbltins = n; + } + base_treep = treep = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(treep,shp,1); + treep->user = (void*)shp; + for(tp=name_vals;*tp->sh_name;tp++,np++) + { +--- src/cmd/ksh93/sh/io.c ++++ src/cmd/ksh93/sh/io.c 2013-09-17 17:08:41.000000000 +0000 +@@ -39,6 +39,7 @@ + #include "shnodes.h" + #include "history.h" + #include "edit.h" ++#include "builtins.h" + #include "timeout.h" + #include "FEATURE/externs" + #include "FEATURE/dynamic" +@@ -453,6 +454,8 @@ void sh_ioinit(Shell_t *shp) + sfnotify(sftrack); + sh_iostream(shp,0); + sh_iostream(shp,1); ++ /* sh_iostream(shp,2); --- ksh93u+ 2012-08-01 does not have a (io)vex to ++ restore sfstderr and close file descriptors */ + /* all write steams are in the same pool and share outbuff */ + shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */ + shp->outbuff = (char*)malloc(IOBSIZE+4); +@@ -536,8 +539,12 @@ Sfio_t *sh_iostream(Shell_t *shp, regist + } + if(status&IOREAD) + { +- if(!(bp = (char *)malloc(IOBSIZE+1))) ++ if(shp->bltinfun && shp->bltinfun!=b_read && shp->bltindata.bnode && !nv_isattr(shp->bltindata.bnode,BLT_SPC)) ++ bp = 0; ++ else if(!(bp = (char *)malloc(IOBSIZE+1))) + return(NIL(Sfio_t*)); ++ if(bp) ++ bp[IOBSIZE]=0; + flags |= SF_READ; + if(!(status&IOWRITE)) + flags &= ~SF_WRITE; +@@ -550,7 +557,8 @@ Sfio_t *sh_iostream(Shell_t *shp, regist + { + if(status&IOTTY) + sfset(iop,SF_LINE|SF_WCWIDTH,1); +- sfsetbuf(iop, bp, IOBSIZE); ++ if(bp) ++ sfsetbuf(iop, bp, IOBSIZE); + } + else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags))) + return(NIL(Sfio_t*)); +@@ -964,7 +972,7 @@ int sh_pipe(register int pv[]) + while ((r=bind (pv[out], (struct sockaddr *) &sin, slen)) == -1 && errno==EADDRINUSE); + if(r<0 || listen(pv[out],5) <0) + { +- close(pv[out]); ++ sh_close(pv[out]); + errormsg(SH_DICT,ERROR_system(1),e_pipe); + } + fcntl(pv[out],F_SETFD,FD_CLOEXEC); +@@ -1079,7 +1087,7 @@ static char *io_usename(char *name, int + if((fd = sh_open(name,O_RDONLY,0)) >= 0) + { + r = fstat(fd,&statb); +- close(fd); ++ sh_close(fd); + if(r) + return(0); + if(!S_ISREG(statb.st_mode)) +@@ -1144,6 +1152,7 @@ int sh_redirect(Shell_t *shp,struct iono + char *tname=0, *after="", *trace = shp->st.trap[SH_DEBUGTRAP]; + Namval_t *np=0; + int isstring = shp->subshell?(sfset(sfstdout,0,0)&SF_STRING):0; ++ Sfio_t *sp; + + if(flag==2) + clexec = 1; +@@ -1245,16 +1254,35 @@ int sh_redirect(Shell_t *shp,struct iono + { + int dupfd,toclose= -1; + io_op[2] = '&'; +- if((fd=fname[0])>='0' && fd<='9') ++ if((fd=fname[0])>='0' && (fd=='{' || fd<='9')) + { + char *number = fname; +- dupfd = strtol(fname,&number,10); ++ int f; ++ if(fd=='{') ++ { ++ np = 0; ++ if(number=strchr(fname,'}')) ++ { ++ *number = 0; ++ np = nv_open(fname+1,shp->var_tree,NV_NOASSIGN|NV_VARNAME|NV_NOFAIL); ++ *number++ = '}'; ++ } ++ if(!np) ++ { ++ message = e_file; ++ goto fail; ++ } ++ dupfd = nv_getnum(np); ++ np = 0; ++ } ++ else ++ dupfd = strtol(fname,&number,10); + if(*number=='-') + { + toclose = dupfd; + number++; + } +- if(*number || dupfd > IOUFD) ++ if(*number) + { + message = e_file; + goto fail; +@@ -1267,8 +1295,23 @@ int sh_redirect(Shell_t *shp,struct iono + shp->subdup |= 1<sftable[dupfd]) ++ else if(sp=shp->sftable[dupfd]) ++ { ++ char *tmpname; ++ if((sfset(sp,0,0)&SF_STRING) && (tmpname = pathtemp(NiL ,NiL,NiL,"sf",&f))) ++ { ++ Sfoff_t last = sfseek(sp,(Sfoff_t)0,SEEK_END); ++ ++ unlink(tmpname); ++ free(tmpname); ++ write(f, sp->_data, (size_t)last); ++ lseek(f,(Sfoff_t)0,SEEK_SET); ++ ++ sfclose(sp); ++ sp = sfnew(sp,NULL,-1,f,SF_READ); ++ } + sfsync(shp->sftable[dupfd]); ++ } + if(dupfd!=1 && fn < 10) + shp->subdup &= ~(1<sftable[dupfd]) && sfset(sp,0,0)&SF_STRING) ++ { ++ char *cp; ++ Sfoff_t off = sftell(sp); ++ sfset(sp,SF_MALLOC,0); ++ cp = sfsetbuf(sp,(char*)sp,0); ++ sfset(sp,SF_MALLOC,1); ++ r = (int)(sfseek(sp,(Sfoff_t)0,SEEK_END)-off); ++ sfseek(sp,off,SEEK_SET); ++ fd = shp->gd->lim.open_max-1; ++ shp->sftable[fd] = sfnew(NIL(Sfio_t*),cp,r,-1,SF_READ|SF_STRING); ++ shp->fdstatus[fd] = shp->fdstatus[dupfd]; ++ } ++ else if((fd=sh_fcntl(dupfd,F_DUPFD,3))<0) + goto fail; + if(fd>= shp->gd->lim.open_max) + sh_iovalidfd(shp,fd); +- sh_iocheckfd(shp,dupfd); ++ if(!shp->sftable[dupfd]) ++ sh_iocheckfd(shp,dupfd); + shp->fdstatus[fd] = (shp->fdstatus[dupfd]&~IOCLEX); + if(toclose<0 && shp->fdstatus[fd]&IOREAD) + shp->fdstatus[fd] |= IODUP; +@@ -1496,7 +1553,8 @@ int sh_redirect(Shell_t *shp,struct iono + if(fn>9 || !(shp->inuse_bits&(1<sftable[fn],fn); + } +- sh_close(fn); ++ if(!(iof&IODOC)) ++ sh_close(fn); + } + if(flag==3) + return(fd); +@@ -1531,7 +1589,24 @@ int sh_redirect(Shell_t *shp,struct iono + shp->inuse_bits |= (1<2 && clexec) ++ else if(iof&IODOC) ++ { ++ Sfio_t *sp = &_Sfstderr; ++ if(fn==1) ++ sp = &_Sfstdout; ++ else if(fn==0) ++ sp = &_Sfstdin; ++ shp->sftable[fn] = shp->sftable[-1]; ++ shp->fdstatus[fn] = shp->fdstatus[-1]; ++ if(fn <=2) ++ { ++ sfswap(shp->sftable[fn],sp); ++ shp->sftable[fn] = sp; ++ } ++ shp->fdptrs[fn] = 0; ++ shp->sftable[-1] = 0; ++ } ++ if(fd >2 && clexec && !(shp->fdstatus[fd]&IOCLEX)) + { + fcntl(fd,F_SETFD,FD_CLOEXEC); + shp->fdstatus[fd] |= IOCLEX; +@@ -2059,9 +2134,11 @@ int sh_iocheckfd(Shell_t *shp, register + if(!(n&(IOSEEK|IONOSEEK))) + { + struct stat statb; ++ Sfio_t *sp = shp->sftable[fd]; + /* /dev/null check is a workaround for select bug */ + static ino_t null_ino; + static dev_t null_dev; ++ shp->sftable[fd] = 0; + if(null_ino==0 && stat(e_devnull,&statb) >=0) + { + null_ino = statb.st_ino; +@@ -2097,6 +2174,7 @@ int sh_iocheckfd(Shell_t *shp, register + n |= IONOSEEK; + else + n |= IOSEEK; ++ shp->sftable[fd] = sp; + } + if(fd==0) + n &= ~IOWRITE; +@@ -2143,6 +2221,7 @@ static int io_prompt(Shell_t *shp,Sfio_t + } + #endif /* TIOCLBIC */ + cp = sh_mactry(shp,nv_getval(sh_scoped(shp,PS1NOD))); ++ shp->exitval = 0; + for(;c= *cp;cp++) + { + if(c==HIST_CHAR) +--- src/cmd/ksh93/sh/jobs.c ++++ src/cmd/ksh93/sh/jobs.c 2013-09-16 14:18:07.000000000 +0000 +@@ -424,6 +424,8 @@ int job_reap(register int sig) + } + if(pid<=0) + break; ++ if(pid==shp->spid) ++ shp->spid = 0; + if(wstat==0) + job_chksave(pid); + flags |= WNOHANG; +@@ -520,7 +522,12 @@ int job_reap(register int sig) + { + shp->sigflag[SIGCHLD] |= SH_SIGTRAP; + if(sig==0) ++ { ++ int c = job.in_critical; ++ job.in_critical = 0; + job_chldtrap(shp,shp->st.trapcom[SIGCHLD],0); ++ job.in_critical = c; ++ } + else + shp->trapnote |= SH_SIGTRAP; + } +@@ -1313,6 +1320,7 @@ int job_post(Shell_t *shp,pid_t pid, pid + return(0); + } + job_lock(); ++ job.lastpost = pid; + #ifdef SHOPT_BGX + if(join==1) + { +@@ -1635,9 +1643,21 @@ int job_wait(register pid_t pid) + if(intr && shp->trapnote) + shp->exitval = 1; + pwfg = 0; +- job_unlock(); + if(pid==1) ++ { ++ if(nochild) ++ { ++ for(pw=job.pwlist; pw; pw=px) ++ { ++ px = pw->p_nxtjob; ++ pw->p_flag |= P_DONE; ++ job_unpost(pw,1); ++ } ++ } ++ job_unlock(); + return(nochild); ++ } ++ job_unlock(); + exitset(); + if(pid==0) + goto done; +@@ -1800,7 +1820,7 @@ static struct process *job_unpost(regist + #endif /* DEBUG */ + pwtop = pw = job_byjid((int)pwtop->p_job); + #ifdef SHOPT_BGX +- if(pw->p_flag&P_BG) ++ if(!pw || pw->p_flag&P_BG) + return(pw); + #endif /* SHOPT_BGX */ + for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc); +--- src/cmd/ksh93/sh/lex.c ++++ src/cmd/ksh93/sh/lex.c 2013-09-13 19:12:25.000000000 +0000 +@@ -556,7 +556,7 @@ int sh_lex(Lex_t* lp) + lp->lexd.docword=1; + else if(n==LPAREN) + { +- if(lp->lex.intest) ++ if(lp->lex.intest || lp->comp_assign) + return(c); + lp->lexd.nest=1; + lp->lastline = shp->inlineno; +--- src/cmd/ksh93/sh/macro.c ++++ src/cmd/ksh93/sh/macro.c 2013-09-13 18:46:30.000000000 +0000 +@@ -392,7 +392,7 @@ void sh_machere(Shell_t *shp,Sfio_t *inf + break; + } + case S_PAR: +- comsubst(mp,(Shnode_t*)0,1); ++ comsubst(mp,(Shnode_t*)0,3); + break; + case S_EOF: + if((c=fcfill()) > 0) +@@ -1166,7 +1166,7 @@ retry1: + case S_PAR: + if(type) + goto nosub; +- comsubst(mp,(Shnode_t*)0,1); ++ comsubst(mp,(Shnode_t*)0,3); + return(1); + case S_DIG: + var = 0; +@@ -1349,7 +1349,7 @@ retry1: + ap = nv_arrayptr(np=nq); + if(ap) + { +- nv_putsub(np,v,ARRAY_SCAN); ++ np = nv_putsub(np,v,ARRAY_SCAN); + v = stkptr(stkp,mp->dotdot); + dolmax =1; + if(array_assoc(ap)) +@@ -2077,6 +2077,18 @@ static void comsubst(Mac_t *mp,register + fcrestore(&save); + return; + } ++ else if(type==2 && t && (t->tre.tretyp&COMMSK)==0 && t->com.comarg) ++ { ++ Namval_t *np; ++ str = NULL; ++ if(!(t->com.comtyp&COMSCAN)) ++ { ++ struct dolnod *ap = (struct dolnod*)t->com.comarg; ++ str = ap->dolval[ap->dolbot]; ++ } ++ else if(t->com.comarg->argflag&ARG_RAW) ++ str = t->com.comarg->argval; ++ } + } + else + { +@@ -2158,10 +2170,22 @@ static void comsubst(Mac_t *mp,register + mp->ifsp = nv_getval(np); + stkset(stkp,savptr,savtop); + newlines = 0; +- sfsetbuf(sp,(void*)sp,0); +- bufsize = sfvalue(sp); ++ if(type==3 && mp->shp->spid) ++ { ++ c = mp->shp->exitval; ++ job_wait(mp->shp->spid); ++ if(mp->shp->exitval==ERROR_NOENT) ++ { ++ mp->shp->exitval = c; ++ mp->shp->savexit=mp->shp->exitval; ++ } ++ if(mp->shp->pipepid==mp->shp->spid) ++ mp->shp->spid = 0; ++ mp->shp->pipepid = 0; ++ } + /* read command substitution output and put on stack or here-doc */ + sfpool(sp, NIL(Sfio_t*), SF_WRITE); ++ sfset(sp, SF_WRITE|SF_PUBLIC|SF_SHARE,0); + sh_offstate(SH_INTERACTIVE); + if((foff = sfseek(sp,(Sfoff_t)0,SEEK_END)) > 0) + { +@@ -2170,6 +2194,8 @@ static void comsubst(Mac_t *mp,register + stkseek(stkp,soff+foff+64); + stkseek(stkp,soff); + } ++ if(foff > IOBSIZE) ++ sfsetbuf(sp,NULL,SF_UNBOUND); + while((str=(char*)sfreserve(sp,SF_UNBOUND,0)) && (c=bufsize=sfvalue(sp))>0) + { + #if SHOPT_CRNL +@@ -2291,6 +2317,13 @@ static void mac_copy(register Mac_t *mp, + Stk_t *stkp=mp->shp->stk; + int oldpat = mp->pattern; + nopat = (mp->quote||(mp->assign==1)||mp->arith); ++ if(size>512) ++ { ++ /* pre-allocate to improve performance */ ++ c = stktell(stkp); ++ stkseek(stkp,c+size+(size>>4)); ++ stkseek(stkp,c); ++ } + if(mp->zeros) + { + /* prevent leading 0's from becomming octal constants */ +@@ -2742,7 +2775,10 @@ static char *sh_tilde(Shell_t *shp,regis + skip: + #endif /* _WINIX */ + if(!logins_tree) ++ { + logins_tree = dtopen(&_Nvdisc,Dtbag); ++ dtuserdata(logins_tree,shp,1); ++ } + if(np=nv_search(string,logins_tree,NV_ADD)) + { + c = shp->subshell; +--- src/cmd/ksh93/sh/main.c ++++ src/cmd/ksh93/sh/main.c 2013-09-13 12:07:49.000000000 +0000 +@@ -309,7 +309,7 @@ int sh_main(int ac, char *av[], Shinit_f + int isdir = 0; + if((fdin=sh_open(name,O_RDONLY,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode))) + { +- close(fdin); ++ sh_close(fdin); + isdir = 1; + fdin = -1; + } +--- src/cmd/ksh93/sh/name.c ++++ src/cmd/ksh93/sh/name.c 2013-09-16 16:00:12.000000000 +0000 +@@ -291,7 +291,7 @@ struct argnod *nv_onlist(struct argnod * + * Perform parameter assignment for a linked list of parameters + * contains attributes for the parameters + */ +-void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ) ++Namval_t ** nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ) + { + Shell_t *shp = sh_getinterp(); + register char *cp; +@@ -301,7 +301,7 @@ void nv_setlist(register struct argnod * + int traceon = (sh_isoption(SH_XTRACE)!=0); + int array = (flags&(NV_ARRAY|NV_IARRAY)); + Namarr_t *ap; +- Namval_t node; ++ Namval_t node, **nodelist=0, **nlp=0; + struct Namref nr; + #if SHOPT_TYPEDEF + int maketype = flags&NV_TYPE; +@@ -330,6 +330,15 @@ void nv_setlist(register struct argnod * + } + else + shp->prefix_root = shp->first_root = 0; ++ if(flags&NV_DECL) ++ { ++ struct argnod *ap; ++ int n=0; ++ for(ap=arg;ap; ap=ap->argnxt.ap) ++ n++; ++ nlp = nodelist = (Namval_t**)stakalloc((n+1)*sizeof(Namval_t*)); ++ nodelist[n] = 0; ++ } + for(;arg; arg=arg->argnxt.ap) + { + shp->used_pos = 0; +@@ -421,6 +430,8 @@ void nv_setlist(register struct argnod * + if(array&NV_ARRAY) + { + nv_setarray(np,nv_associative); ++ if(typ) ++ nv_settype(np,typ,0); + } + else + { +@@ -436,7 +447,7 @@ void nv_setlist(register struct argnod * + #endif /* SHOPT_TYPEDEF */ + } + /* check for array assignment */ +- if(tp->tre.tretyp!=TLST && tp->com.comarg && !tp->com.comset && ((array&NV_IARRAY) || !((mp=tp->com.comnamp) && nv_isattr(mp,BLT_DCL)))) ++ if((tp->tre.tretyp&COMMSK)==TCOM && tp->com.comarg && !tp->com.comset && ((array&NV_IARRAY) || !((mp=tp->com.comnamp) && nv_isattr(mp,BLT_DCL)))) + { + int argc; + Dt_t *last_root = shp->last_root; +@@ -509,6 +520,7 @@ void nv_setlist(register struct argnod * + if(!(array&NV_IARRAY) && !(tp->com.comset->argflag&ARG_MESSAGE)) + nv_setarray(np,nv_associative); + } ++ shp->typeinit = 0; + nv_setlist(tp->com.comset,flags&~NV_STATIC,0); + shp->prefix = prefix; + if(tp->com.comset->argval[1]!='[') +@@ -682,6 +694,7 @@ void nv_setlist(register struct argnod * + } + #endif /* SHOPT_TYPEDEF */ + } ++ return(nodelist); + } + + /* +@@ -821,6 +834,7 @@ Namval_t *nv_create(const char *name, D + { + Dt_t *dp = dtview(shp->var_tree,(Dt_t*)0); + rp->sdict = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(rp->sdict,shp,1); + dtview(rp->sdict,dp); + dtview(shp->var_tree,rp->sdict); + } +@@ -1170,7 +1184,10 @@ Namval_t *nv_create(const char *name, D + ap = nv_arrayptr(np); + } + if(n && ap && !ap->table) ++ { + ap->table = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(ap->table,shp,1); ++ } + if(ap && ap->table && (nq=nv_search(sub,ap->table,n))) + nq->nvenv = (char*)np; + if(nq && nv_isnull(nq)) +@@ -1288,8 +1305,9 @@ void nv_delete(Namval_t* np, Dt_t *root, + if(rp->sub) + free(rp->sub); + rp->sub = 0; +- rp = dtdelete(Refdict,(void*)rp); +- rp->np = &NullNode; ++ rp = dtremove(Refdict,(void*)rp); ++ if(rp) ++ rp->np = &NullNode; + } + } + } +@@ -1341,10 +1359,12 @@ Namval_t *nv_open(const char *name, Dt_t + struct Cache_entry *xp; + #endif + +- sh_stats(STAT_NVOPEN); + memset(&fun,0,sizeof(fun)); + shp->openmatch = 0; + shp->last_table = 0; ++ if(!name) ++ return(0); ++ sh_stats(STAT_NVOPEN); + if(!root) + root = shp->var_tree; + shp->last_root = root; +@@ -1391,7 +1411,7 @@ Namval_t *nv_open(const char *name, Dt_t + while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') && + (c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT || c==S_COLON)); + if(shp->subshell && c=='=') +- root = sh_subaliastree(1); ++ root = sh_subaliastree(shp,1); + if(c= *--cp) + *cp = 0; + np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD); +@@ -2350,6 +2370,7 @@ void sh_scope(Shell_t *shp, struct argno + newroot = nv_dict(shp->namespace); + #endif /* SHOPT_NAMESPACE */ + newscope = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(newscope,shp,1); + if(envlist) + { + dtview(newscope,(Dt_t*)shp->var_tree); +@@ -2465,6 +2486,8 @@ static void table_unset(Shell_t *shp, re + } + } + npnext = (Namval_t*)dtnext(root,np); ++ if(nv_arrayptr(np)) ++ nv_putsub(np,NIL(char*),ARRAY_SCAN); + _nv_unset(np,flags); + nv_delete(np,root,0); + } +@@ -2533,7 +2556,7 @@ void _nv_unset(register Namval_t *np,int + } + dtclose(rp->sdict); + } +- stakdelete(slp->slptr); ++ sfclose(slp->slptr); + free((void*)np->nvalue.ip); + np->nvalue.ip = 0; + } +@@ -2547,9 +2570,11 @@ void _nv_unset(register Namval_t *np,int + /* This function contains disc */ + if(!nv_local) + { ++ Dt_t *last_root = shp->last_root; + nv_local=1; + nv_putv(np,NIL(char*),flags,np->nvfun); + nv_local=0; ++ shp->last_root = last_root; + return; + } + /* called from disc, assign the actual value */ +@@ -2570,7 +2595,7 @@ void _nv_unset(register Namval_t *np,int + { + + if(np->nvalue.nrp->root) +- dtdelete(Refdict,(void*)np->nvalue.nrp); ++ dtremove(Refdict,(void*)np->nvalue.nrp); + if(np->nvalue.nrp->sub) + free(np->nvalue.nrp->sub); + free((void*)np->nvalue.nrp); +@@ -3334,7 +3359,10 @@ int nv_rename(register Namval_t *np, int + if(ap=nv_arrayptr(np)) + { + if(!ap->table) ++ { + ap->table = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(ap->table,shp,1); ++ } + if(ap->table) + mp = nv_search(nv_getsub(np),ap->table,NV_ADD); + nv_arraychild(np,mp,0); +@@ -3569,7 +3597,7 @@ void nv_unref(register Namval_t *np) + { + if(np->nvalue.nrp->sub) + free(np->nvalue.nrp->sub); +- dtdelete(Refdict,(void*)np->nvalue.nrp); ++ dtremove(Refdict,(void*)np->nvalue.nrp); + } + free((void*)np->nvalue.nrp); + np->nvalue.cp = strdup(nv_name(nq)); +--- src/cmd/ksh93/sh/nvdisc.c ++++ src/cmd/ksh93/sh/nvdisc.c 2013-09-13 14:34:31.000000000 +0000 +@@ -246,6 +246,7 @@ static void chktfree(register Namval_t * + */ + static void assign(Namval_t *np,const char* val,int flags,Namfun_t *handle) + { ++ Shell_t *shp = sh_getinterp(); + int type = (flags&NV_APPEND)?APPEND:ASSIGN; + register struct vardisc *vp = (struct vardisc*)handle; + register Namval_t *nq = vp->disc[type]; +@@ -330,7 +331,7 @@ static void assign(Namval_t *np,const ch + } + else if(!nq || !isblocked(bp,type)) + { +- Dt_t *root = sh_subfuntree(1); ++ Dt_t *root = sh_subfuntree(shp,1); + int n; + Namarr_t *ap; + block(bp,type); +@@ -1225,7 +1226,10 @@ Namval_t *sh_addbuiltin(const char *path + if(np->nvenv) + dtdelete(sh.bltin_tree,np); + if(extra == (void*)1) ++ { ++ dtdelete(sh.bltin_tree,np); + return(0); ++ } + np = 0; + } + break; +@@ -1296,6 +1300,7 @@ static Namfun_t *clone_table(Namval_t* n + Dt_t *oroot=tp->dict,*nroot=dtopen(&_Nvdisc,Dtoset); + if(!nroot) + return(0); ++ dtuserdata(nroot,dtuserdata(oroot,0,0),1); + memcpy((void*)ntp,(void*)fp,sizeof(struct table)); + ntp->dict = nroot; + ntp->parent = nv_lastdict(); +@@ -1437,6 +1442,7 @@ Namval_t *nv_mount(Namval_t *np, const c + { + Namval_t *mp, *pp; + struct table *tp; ++ dtuserdata(dict,sh_getinterp(),1); + if(nv_hasdisc(np,&table_disc)) + pp = np; + else +@@ -1493,6 +1499,6 @@ Namval_t *sh_fsearch(Shell_t *shp, const + sfputr(stkp,nv_name(shp->namespace),'.'); + sfputr(stkp,fname,0); + fname = stkptr(stkp,offset); +- return(nv_search(fname,sh_subfuntree(add&NV_ADD),add)); ++ return(nv_search(fname,sh_subfuntree(shp,add&NV_ADD),add)); + } + #endif /* SHOPT_NAMESPACE */ +--- src/cmd/ksh93/sh/nvtree.c ++++ src/cmd/ksh93/sh/nvtree.c 2013-09-16 15:37:34.000000000 +0000 +@@ -144,8 +144,9 @@ static Namfun_t *nextdisc(Namval_t *np) + + void *nv_diropen(Namval_t *np,const char *name) + { +- char *next,*last; +- int c,len=strlen(name); ++ const char *last; ++ char *next; ++ size_t c,len=strlen(name); + struct nvdir *save, *dp = new_of(struct nvdir,len+1); + Namval_t *nq=0,fake; + Namfun_t *nfp=0; +@@ -160,7 +161,10 @@ void *nv_diropen(Namval_t *np,const char + dp->len = len; + dp->root = sh.last_root?sh.last_root:sh.var_tree; + #if 1 +- while(1) ++ last = &name[len]; ++ if(!np) ++ np = nv_search(name,dp->root,0); ++ if(!np || !nv_isvtree(np)) while(1) + { + dp->table = sh.last_table; + sh.last_table = 0; +@@ -188,7 +192,7 @@ void *nv_diropen(Namval_t *np,const char + { + char *cp = nv_name(dp->hp); + c = strlen(cp); +- if(memcmp(name,cp,c) || name[c]!='[') ++ if(strncmp(name,cp,c) || name[c]!='[') + dp->hp = (Namval_t*)dtnext(dp->root,dp->hp); + else + { +@@ -266,7 +270,7 @@ static Namval_t *nextnode(struct nvdir * + { + if(dp->nextnode) + return((*dp->nextnode)(dp->hp,dp->root,dp->fun)); +- if(dp->len && memcmp(dp->data, dp->hp->nvname, dp->len)) ++ if(dp->len && strncmp(dp->data, dp->hp->nvname, dp->len)) + return(0); + return((Namval_t*)dtnext(dp->root,dp->hp)); + } +@@ -311,7 +315,7 @@ char *nv_dirnext(void *dir) + dp->hp = (*dp->nextnode)(np,(Dt_t*)0,dp->fun); + } + sh.last_table = last_table; +- if(!dp->len || memcmp(cp,dp->data,dp->len)==0) ++ if(!dp->len || strncmp(cp,dp->data,dp->len)==0) + { + if((nfp=nextdisc(np)) && (nfp->disc->getval||nfp->disc->getnum) && nv_isvtree(np) && strcmp(cp,dp->data)) + nfp = 0; +@@ -703,6 +707,7 @@ static void outval(char *name, const cha + if(!(np=nv_open(vname,wp->root,mode|NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope))) + { + wp->shp->last_table = last_table; ++ wp->flags &= ~NV_COMVAR; + return; + } + if(!wp->out) +@@ -739,8 +744,20 @@ static void outval(char *name, const cha + break; + } + if(!xp) ++ { ++ if(nv_type(np) || !(wp->flags&NV_COMVAR)) ++ { ++ wp->flags &= ~NV_COMVAR; ++ return; ++ } ++ if(wp->indent>0) ++ sfnputc(wp->out,'\t',wp->indent); ++ nv_attribute(np,wp->out,"typeset",' '); ++ sfputr(wp->out,name,wp->indent>0?'\n':-1); + return; ++ } + } ++ wp->flags &= ~NV_COMVAR; + if(nv_isnull(np) && !nv_isarray(np) && !nv_isattr(np,NV_INTEGER)) + return; + if(special || (nv_isarray(np) && nv_arrayptr(np))) +@@ -927,6 +944,17 @@ static char **genvalue(char **argv, cons + } + else + { ++ if(n && *cp && cp[-1]!='.' && cp[-1]!='[') ++ break; ++ if(outfile && wp->indent<0 && (wp->flags&NV_COMVAR)) ++ sfputc(outfile,';'); ++ wp->flags |= NV_COMVAR; ++ if(argv[1]) ++ { ++ ssize_t r = (cp-argv[0]) + strlen(cp); ++ if(argv[1][r]=='.' && strncmp(argv[0],argv[1],r)==0) ++ wp->flags &= ~NV_COMVAR; ++ } + outval(cp,arg,wp); + if(wp->array) + { +@@ -943,6 +971,7 @@ static char **genvalue(char **argv, cons + wp->nofollow = 0; + } + wp->array = 0; ++ wp->flags &= ~NV_COMVAR; + if(outfile) + { + int c = prefix[m-1]; +@@ -1031,9 +1060,18 @@ static char *walk_tree(register Namval_t + shp->var_tree = dp; + if(nq && mq) + { ++ register struct nvdir *odir=0,*dp = (struct nvdir*)dir; ++ if(dp->table==nq) ++ { ++ dp = dp->prev; ++ odir = dir; ++ dir = dp; ++ } + nv_clone(nq,mq,flags|NV_RAW); + if(flags&NV_MOVE) + nv_delete(nq,walk.root,0); ++ if(odir) ++ free(odir); + } + continue; + } +--- src/cmd/ksh93/sh/nvtype.c ++++ src/cmd/ksh93/sh/nvtype.c 2013-09-17 13:37:34.000000000 +0000 +@@ -484,7 +484,10 @@ static Namfun_t *clone_type(Namval_t* np + } + } + if(nv_isattr(mp,NV_BINARY)) ++ { + mp->nvalue.cp = dp->data; ++ nv_onattr(mp,NV_NOFREE); ++ } + if(pp->strsize<0) + dp->strsize = -pp->strsize; + return(&dp->fun); +--- src/cmd/ksh93/sh/parse.c ++++ src/cmd/ksh93/sh/parse.c 2013-09-13 16:21:49.000000000 +0000 +@@ -1722,6 +1722,7 @@ static struct ionod *inout(Lex_t *lexp,s + lexp->digits=0; + iop=(struct ionod*) stkalloc(stkp,sizeof(struct ionod)); + iop->iodelim = 0; ++ iop->iosize = 0; + if(token=sh_lex(lexp)) + { + if(token==RPAREN && (iof&IOLSEEK) && lexp->comsub) +--- src/cmd/ksh93/sh/path.c ++++ src/cmd/ksh93/sh/path.c 2013-09-17 13:49:01.000000000 +0000 +@@ -592,7 +592,7 @@ static void funload(Shell_t *shp,int fno + pname = path_fullname(shp,stakptr(PATH_OFFSET)); + if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname))) + { +- Dt_t *funtree = sh_subfuntree(1); ++ Dt_t *funtree = sh_subfuntree(shp,1); + while(1) + { + rpfirst = dtprev(shp->fpathdict,rp); +@@ -613,6 +613,7 @@ static void funload(Shell_t *shp,int fno + } + while((rp=dtnext(shp->fpathdict,rp)) && strcmp(pname,rp->fname)==0); + sh_close(fno); ++ free((void*)pname); + return; + } + sh_onstate(SH_NOLOG); +@@ -868,15 +869,15 @@ Pathcomp_t *path_absolute(Shell_t *shp,r + if(isfun && f>=0 && (cp = strrchr(name,'.'))) + { + *cp = 0; +- if(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE)) ++ if(nv_open(name,sh_subfuntree(shp,1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE)) + f = -1; + *cp = '.'; + } + if(isfun && f>=0) + { +- nv_onattr(nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION); ++ nv_onattr(nv_open(name,sh_subfuntree(shp,1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE),NV_LTOU|NV_FUNCTION); + funload(shp,f,name); +- close(f); ++ sh_close(f); + f = -1; + return(0); + } +@@ -1408,7 +1409,7 @@ static void exscript(Shell_t *shp,regist + sabuf.ac_etime = compress( (time_t)(after-before)); + fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL); + write(fd, (const char*)&sabuf, sizeof( sabuf )); +- close( fd); ++ sh_close( fd); + } + } + +--- src/cmd/ksh93/sh/streval.c ++++ src/cmd/ksh93/sh/streval.c 2013-09-17 15:21:23.000000000 +0000 +@@ -165,14 +165,11 @@ Sfdouble_t arith_exec(Arith_t *ep) + Math_f fun; + struct lval node; + Shell_t *shp = ep->shp; ++ memset(&node,0,sizeof(node)); + node.shp = shp; + node.emode = ep->emode; + node.expr = ep->expr; + node.elen = ep->elen; +- node.value = 0; +- node.nosub = 0; +- node.ptr = 0; +- node.eflag = 0; + if(level++ >=MAXLEVEL) + { + arith_error(e_recursive,ep->expr,ep->emode); --- src/cmd/ksh93/sh/subshell.c -+++ src/cmd/ksh93/sh/subshell.c 2013-04-23 09:40:16.089940758 +0000 -@@ -122,11 +122,13 @@ void sh_subtmpfile(Shell_t *shp) ++++ src/cmd/ksh93/sh/subshell.c 2013-09-17 15:12:00.000000000 +0000 +@@ -122,23 +122,26 @@ void sh_subtmpfile(Shell_t *shp) register struct checkpt *pp = (struct checkpt*)shp->jmplist; register struct subshell *sp = subshell_data->pipe; /* save file descriptor 1 if open */ @@ -30,7 +1510,13 @@ } else if(errno!=EBADF) errormsg(SH_DICT,ERROR_system(1),e_toomany); -@@ -138,7 +140,7 @@ void sh_subtmpfile(Shell_t *shp) + /* popping a discipline forces a /tmp file create */ +- sfdisc(sfstdout,SF_POPDISC); ++ if(shp->comsub != 1) ++ sfdisc(sfstdout,SF_POPDISC); + if((fd=sffileno(sfstdout))<0) + { + /* unable to create the /tmp file so use a pipe */ int fds[3]; Sfoff_t off; fds[2] = 0; @@ -39,7 +1525,7 @@ sp->pipefd = fds[0]; sh_fcntl(sp->pipefd,F_SETFD,FD_CLOEXEC); /* write the data to the pipe */ -@@ -180,7 +182,7 @@ void sh_subfork(void) +@@ -180,7 +183,7 @@ void sh_subfork(void) { register struct subshell *sp = subshell_data; Shell_t *shp = sp->shp; @@ -48,7 +1534,7 @@ pid_t pid; char *trap = shp->st.trapcom[0]; if(trap) -@@ -213,7 +215,7 @@ void sh_subfork(void) +@@ -213,7 +216,7 @@ void sh_subfork(void) shp->comsub = 0; SH_SUBSHELLNOD->nvalue.s = 0; sp->subpid=0; @@ -57,16 +1543,78 @@ shp->savesig = 0; } } -@@ -528,7 +530,7 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ +@@ -337,7 +340,7 @@ static void nv_restore(struct subshell * + } + nv_setsize(mp,nv_size(np)); + if(!(flags&NV_MINIMAL)) +- mp->nvenv = np->nvenv; ++ mp->nvenv = nv_isnull(mp)?0:np->nvenv; + if(!nofree) + mp->nvfun = np->nvfun; + if(nv_isattr(np,NV_IDENT)) +@@ -379,7 +382,7 @@ static void nv_restore(struct subshell * + * return pointer to alias tree + * create new one if in a subshell and one doesn't exist and create is non-zero + */ +-Dt_t *sh_subaliastree(int create) ++Dt_t *sh_subaliastree(Shell_t *shp,int create) + { + register struct subshell *sp = subshell_data; + if(!sp || sp->shp->curenv==0) +@@ -387,6 +390,7 @@ Dt_t *sh_subaliastree(int create) + if(!sp->salias && create) + { + sp->salias = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(sp->salias,shp,1); + dtview(sp->salias,sp->shp->alias_tree); + sp->shp->alias_tree = sp->salias; + } +@@ -397,7 +401,7 @@ Dt_t *sh_subaliastree(int create) + * return pointer to function tree + * create new one if in a subshell and one doesn't exist and create is non-zero + */ +-Dt_t *sh_subfuntree(int create) ++Dt_t *sh_subfuntree(Shell_t *shp,int create) + { + register struct subshell *sp = subshell_data; + if(!sp || sp->shp->curenv==0) +@@ -405,6 +409,7 @@ Dt_t *sh_subfuntree(int create) + if(!sp->sfun && create) + { + sp->sfun = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(sp->sfun,shp,1); + dtview(sp->sfun,sp->shp->fun_tree); + sp->shp->fun_tree = sp->sfun; + } +@@ -492,6 +497,8 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ + subenv = 0; + } + shp->curenv = ++subenv; ++ if(shp->curenv<=0) ++ shp->curenv = subenv = 1; + savst = shp->st; + sh_pushcontext(shp,&buff,SH_JMPSUB); + subshell = shp->subshell+1; +@@ -506,6 +513,7 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ + sp->options = shp->options; + sp->jobs = job_subsave(); + sp->subdup = shp->subdup; ++ shp->subdup = 0; + #if SHOPT_COSHELL + sp->coshell = shp->coshell; + shp->coshell = 0; +@@ -528,7 +536,9 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ job.curpgid = 0; sp->subshare = shp->subshare; sp->comsub = shp->comsub; - shp->subshare = comsub==2 || (comsub==1 && sh_isoption(SH_SUBSHARE)); + shp->subshare = comsub==2 || (comsub && sh_isoption(SH_SUBSHARE)); ++ if(!shp->subshare) ++ sp->pathlist = path_dup((Pathcomp_t*)shp->pathlist); if(comsub) shp->comsub = comsub; if(!comsub || !shp->subshare) -@@ -602,7 +604,7 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ +@@ -602,7 +612,7 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ sp->tmpfd = -1; sp->pipefd = -1; /* use sftmp() file for standard output */ @@ -75,7 +1623,7 @@ { sfswap(sp->saveout,sfstdout); errormsg(SH_DICT,ERROR_system(1),e_tmpcreate); -@@ -688,11 +690,16 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ +@@ -688,19 +698,27 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ } sfset(iop,SF_READ,1); } @@ -94,7 +1642,20 @@ if (fcntl(sp->tmpfd,F_DUPFD,1) != 1) duped++; sh_close(sp->tmpfd); -@@ -776,7 +783,6 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ + } + shp->fdstatus[1] = sp->fdstatus; + } +- path_delete((Pathcomp_t*)shp->pathlist); +- shp->pathlist = (void*)sp->pathlist; ++ if(!shp->subshare) ++ { ++ path_delete((Pathcomp_t*)shp->pathlist); ++ shp->pathlist = (void*)sp->pathlist; ++ } + job_subrestore(sp->jobs); + shp->jobenv = savecurenv; + job.curpgid = savejobpgid; +@@ -776,7 +794,6 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ shp->coutpipe = sp->coutpipe; } shp->subshare = sp->subshare; @@ -102,7 +1663,7 @@ shp->subdup = sp->subdup; #if SHOPT_COSHELL shp->coshell = sp->coshell; -@@ -806,7 +812,12 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ +@@ -806,7 +823,12 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_ if(nsig>0) kill(getpid(),nsig); if(sp->subpid) @@ -116,7 +1677,7 @@ sfseek(iop,(off_t)0,SEEK_SET); if(shp->trapnote) --- src/cmd/ksh93/sh/xec.c -+++ src/cmd/ksh93/sh/xec.c 2013-04-23 10:39:02.725439216 +0000 ++++ src/cmd/ksh93/sh/xec.c 2013-09-13 18:27:02.000000000 +0000 @@ -102,26 +102,30 @@ struct funenv * temp file. */ @@ -194,7 +1755,77 @@ sh_close(subpipe[0]); subpipe[0] = -1; tsetio = 0; -@@ -1597,10 +1611,14 @@ int sh_exec(register const Shnode_t *t, +@@ -748,20 +762,20 @@ static void *sh_coinit(Shell_t *shp,char + { + struct cosh *csp = job.colist; + const char *name = argv?argv[0]:0; +- int id, open=1; ++ int id, xopen=1; + if(!name) + return(0); + if(*name=='-') + { + name++; +- open=0; ++ xopen=0; + } + nv_open(name,shp->var_tree,NV_IDENT|NV_NOADD); + while(csp) + { + if(strcmp(name,csp->name)==0) + { +- if(open) ++ if(xopen) + { + coattr(csp->coshell,argv[1]); + return((void*)csp); +@@ -771,7 +785,7 @@ static void *sh_coinit(Shell_t *shp,char + } + csp = csp->next; + } +- if(!open) ++ if(!xopen) + errormsg(SH_DICT,ERROR_exit(1),"%s: unknown namespace",name); + environ[0][2]=0; + csp = newof(0,struct cosh,1,strlen(name)+1); +@@ -898,13 +912,14 @@ static int sh_coexec(Shell_t *shp,const + #if SHOPT_FILESCAN + static Sfio_t *openstream(Shell_t *shp, struct ionod *iop, int *save) + { +- int savein, fd = sh_redirect(shp,iop,3); ++ int err=errno,savein, fd = sh_redirect(shp,iop,3); + Sfio_t *sp; + savein = dup(0); + if(fd==0) + fd = savein; + sp = sfnew(NULL,NULL,SF_UNBOUND,fd,SF_READ); +- close(0); ++ while(close(0)<0 && errno==EINTR) ++ errno = err; + open(e_devnull,O_RDONLY); + shp->offsets[0] = -1; + shp->offsets[1] = 0; +@@ -1207,7 +1222,9 @@ int sh_exec(register const Shnode_t *t, + if(OPTIMIZE) + flgs |= NV_TAGGED; + #endif +- nv_setlist(argp,flgs,tp); ++ if (np && nv_isattr(np,BLT_DCL)) ++ flgs |= NV_DECL; ++ shp->nodelist = nv_setlist(argp,flgs,tp); + if(np==shp->typeinit) + shp->typeinit = 0; + shp->envlist = argp; +@@ -1570,7 +1587,7 @@ int sh_exec(register const Shnode_t *t, + unset_instance(nq,&node,&nr,mode); + sh_funstaks(slp->slchild,-1); + stakdelete(slp->slptr); +- if(jmpval > SH_JMPFUN) ++ if(jmpval > SH_JMPFUN || (io && jmpval>SH_JMPIO)) + siglongjmp(*shp->jmplist,jmpval); + goto setexit; + } +@@ -1597,10 +1614,14 @@ int sh_exec(register const Shnode_t *t, if(shp->subshell) { sh_subtmpfile(shp); @@ -203,7 +1834,7 @@ if((type&(FAMP|TFORK))==(FAMP|TFORK)) - sh_subfork(); + { -+ if(shp->comsub==1 && !(shp->fdstatus[1]&IONOSEEK)) ++ if(shp->comsub && !(shp->fdstatus[1]&IONOSEEK)) + { + unpipe=iousepipe(shp); + sh_subfork(); @@ -212,7 +1843,7 @@ } no_fork = !ntflag && !(type&(FAMP|FPOU)) && !shp->subshell && !(shp->st.trapcom[SIGINT] && *shp->st.trapcom[SIGINT]) && -@@ -1676,7 +1694,7 @@ int sh_exec(register const Shnode_t *t, +@@ -1676,7 +1697,7 @@ int sh_exec(register const Shnode_t *t, if(parent<0) { if(shp->comsub==1 && usepipe && unpipe) @@ -221,7 +1852,7 @@ break; } #else -@@ -1693,7 +1711,7 @@ int sh_exec(register const Shnode_t *t, +@@ -1693,7 +1714,7 @@ int sh_exec(register const Shnode_t *t, if(parent<0) { if(shp->comsub==1 && usepipe && unpipe) @@ -230,25 +1861,150 @@ break; } #else -@@ -1734,7 +1752,7 @@ int sh_exec(register const Shnode_t *t, +@@ -1715,6 +1736,8 @@ int sh_exec(register const Shnode_t *t, + nlock--; + job_unlock(); + } ++ if(shp->subshell) ++ shp->spid = parent; + if(type&FPCL) + sh_close(shp->inpipe[0]); + if(type&(FCOOP|FAMP)) +@@ -1733,8 +1756,8 @@ int sh_exec(register const Shnode_t *t, + job_wait(parent); if(shp->topfd > topfd) sh_iorestore(shp,topfd,0); - if(usepipe && tsetio && subdup && unpipe) +- if(usepipe && tsetio && subdup && unpipe) - iounpipe(shp); ++ if(usepipe && tsetio && subdup) + sh_iounpipe(shp); if(!sh_isoption(SH_MONITOR)) { shp->trapnote &= ~SH_SIGIGNORE; -@@ -1954,7 +1972,7 @@ int sh_exec(register const Shnode_t *t, +@@ -1906,8 +1929,8 @@ int sh_exec(register const Shnode_t *t, + { + was_interactive = sh_isstate(SH_INTERACTIVE); + sh_offstate(SH_INTERACTIVE); +- sh_iosave(shp,0,shp->topfd,(char*)0); + shp->pipepid = simple; ++ sh_iosave(shp,0,shp->topfd,(char*)0); + sh_iorenumber(shp,shp->inpipe[0],0); + /* + * if read end of pipe is a simple command +@@ -1924,7 +1947,7 @@ int sh_exec(register const Shnode_t *t, + jmpval = sigsetjmp(buffp->buff,0); + if(jmpval==0) + { +- if(shp->comsub==1) ++ if(shp->comsub) + tsetio = 1; + sh_redirect(shp,t->fork.forkio,execflg); + (t->fork.forktre)->tre.tretyp |= t->tre.tretyp&FSHOWME; +@@ -1953,8 +1976,8 @@ int sh_exec(register const Shnode_t *t, + if(type || !sh_isoption(SH_PIPEFAIL)) shp->exitval = type; } - if(shp->comsub==1 && usepipe) +- if(shp->comsub==1 && usepipe) - iounpipe(shp); ++ if(shp->comsub==1 && usepipe && unpipe) + sh_iounpipe(shp); shp->pipepid = 0; shp->st.ioset = 0; if(simple && was_errexit) -@@ -3165,7 +3183,7 @@ pid_t _sh_fork(Shell_t *shp,register pid +@@ -2179,7 +2202,7 @@ int sh_exec(register const Shnode_t *t, + } + shp->exitval = n; + #ifdef SIGTSTP +- if(!pipejob && sh_isstate(SH_MONITOR)) ++ if(!pipejob && sh_isstate(SH_MONITOR) && sh_isstate(SH_INTERACTIVE)) + tcsetpgrp(JOBTTY,shp->gd->pid); + #endif /*SIGTSTP */ + job.curpgid = savepgid; +@@ -2320,7 +2343,10 @@ int sh_exec(register const Shnode_t *t, + nv_putsub(np,NIL(char*),0L); + nv_putval(np,cp,0); + if(nameref) ++ { + nv_setref(np,(Dt_t*)0,NV_VARNAME); ++ nv_onattr(np,NV_TABLE); ++ } + if(trap=shp->st.trap[SH_DEBUGTRAP]) + { + av[0] = (t->tre.tretyp&COMSCAN)?"select":"for"; +@@ -2352,6 +2378,8 @@ int sh_exec(register const Shnode_t *t, + if(shp->st.breakcnt<0) + shp->st.execbrk = (++shp->st.breakcnt !=0); + } ++ if(nameref) ++ nv_offattr(np,NV_TABLE); + #if SHOPT_OPTIMIZE + endfor: + sh_popcontext(shp,buffp); +@@ -2466,8 +2494,10 @@ int sh_exec(register const Shnode_t *t, + #if SHOPT_FILESCAN + if(iop) + { ++ int err=errno; + sfclose(iop); +- close(0); ++ while(close(0)<0 && errno==EINTR) ++ errno = err; + dup(savein); + shp->cur_line = 0; + } +@@ -2688,6 +2718,7 @@ int sh_exec(register const Shnode_t *t, + else + { + root = dtopen(&_Nvdisc,Dtoset); ++ dtuserdata(root,shp,1); + nv_mount(np, (char*)0, root); + np->nvalue.cp = Empty; + dtview(root,shp->var_base); +@@ -2729,7 +2760,7 @@ int sh_exec(register const Shnode_t *t, + np = sh_fsearch(shp,fname,NV_ADD|HASH_NOSCOPE); + if(!np) + #endif /* SHOPT_NAMESPACE */ +- np = nv_open(fname,sh_subfuntree(1),NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOSCOPE); ++ np = nv_open(fname,sh_subfuntree(shp,1),NV_NOASSIGN|NV_NOARRAY|NV_VARNAME|NV_NOSCOPE); + if(npv) + { + if(!shp->mktype) +@@ -2745,7 +2776,7 @@ int sh_exec(register const Shnode_t *t, + stakdelete(slp->slptr); + if(rp->sdict) + { +- Namval_t *mp, *nq; ++ Namval_t *nq; + shp->last_root = rp->sdict; + for(mp=(Namval_t*)dtfirst(rp->sdict);mp;mp=nq) + { +@@ -2799,7 +2830,8 @@ int sh_exec(register const Shnode_t *t, + rp->np = np; + if(!shp->fpathdict) + shp->fpathdict = dtopen(&_Rpdisc,Dtobag); +- if(shp->fpathdict) { ++ if(shp->fpathdict) ++ { + dtuserdata(shp->fpathdict,shp,1); + dtinsert(shp->fpathdict,rp); + } +@@ -2909,6 +2941,15 @@ int sh_exec(register const Shnode_t *t, + break; + } + } ++ if(shp->procsub && *shp->procsub) ++ { ++ pid_t pid, *procsub; ++ int exitval = shp->exitval; ++ for(procsub=shp->procsub;pid=*procsub;procsub++) ++ job_wait(pid); ++ *shp->procsub = 0; ++ shp->exitval = exitval; ++ } + if(shp->trapnote || (shp->exitval && sh_isstate(SH_ERREXIT)) && + t && echeck) + sh_chktrap(shp); +@@ -3165,7 +3206,7 @@ pid_t _sh_fork(Shell_t *shp,register pid { if(shp->topfd > restorefd) sh_iorestore(shp,restorefd,0); @@ -257,7 +2013,25 @@ } } return(parent); -@@ -3626,7 +3644,7 @@ static void coproc_init(Shell_t *shp, in +@@ -3477,8 +3518,7 @@ static void sh_funct(Shell_t *shp,Namval + struct funenv fun; + char *fname = nv_getval(SH_FUNNAMENOD); + struct Level *lp =(struct Level*)(SH_LEVELNOD->nvfun); +- int level, pipepid=shp->pipepid, comsub=shp->comsub; +- shp->comsub = 0; ++ int level, pipepid=shp->pipepid; + shp->pipepid = 0; + sh_stats(STAT_FUNCT); + if(!lp->hdr.disc) +@@ -3521,7 +3561,6 @@ static void sh_funct(Shell_t *shp,Namval + lp->maxlevel = level; + SH_LEVELNOD->nvalue.s = lp->maxlevel; + shp->last_root = nv_dict(DOTSHNOD); +- shp->comsub = comsub; + #if 0 + nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE); + #else +@@ -3626,11 +3665,11 @@ static void coproc_init(Shell_t *shp, in sh_pipe(shp->cpipe); if((outfd=shp->cpipe[1]) < 10) { @@ -266,3 +2040,26 @@ if(fd>=10) { shp->fdstatus[fd] = (shp->fdstatus[outfd]&~IOCLEX); +- close(outfd); ++ sh_close(outfd); + shp->fdstatus[outfd] = IOCLOSE; + shp->cpipe[1] = fd; + } +@@ -3719,7 +3758,7 @@ static int run_subshell(Shell_t *shp,con + if(!shp->gd->shpath) + shp->gd->shpath = pathshell(); + pid = spawnveg(shp->shpath,arglist,envlist,grp); +- close(fd); ++ sh_close(fd); + for(i=3; i < 10; i++) + { + if(shp->fdstatus[i]&IOCLEX && i!=pin && i!=pout) +@@ -4000,7 +4039,7 @@ static pid_t sh_ntfork(Shell_t *shp,cons + shp->gd->shpath = pathshell(); + spawnpid = path_spawn(shp,shp->gd->shpath,&argv[-1],arge,pp,(grp<<1)|1); + if(fd>=0) +- close(fd); ++ sh_close(fd); + argv[0] = argv[-1]; + } + fail: diff --git a/ksh93.dif b/ksh93.dif index 60cade9..ca4a331 100644 --- a/ksh93.dif +++ b/ksh93.dif @@ -318,6 +318,15 @@ fi ") got=$* +@@ -336,7 +336,7 @@ then LC_ALL=en_US.UTF-8 + [[ $(print -r -- "$x") == $'hello\u[20ac]\xee world' ]] || err_exit '%q with unicode and non-unicode not working' + if [[ $(whence od) ]] + then got='68 65 6c 6c 6f e2 82 ac ee 20 77 6f 72 6c 64 0a' +- [[ $(print -r -- "$x" | od -An -tx1) == "$got" ]] || err_exit "incorrect string from printf %q" ++ [[ $(print -r -- "$x" | od -An -tx1) =~ "$got" ]] || err_exit "incorrect string from printf %q" + fi + + fi --- src/cmd/ksh93/tests/options.sh +++ src/cmd/ksh93/tests/options.sh 2012-01-16 16:50:59.000000000 +0000 @@ -510,7 +510,7 @@ z=$($SHELL 2>&1 -uc 'print ${X2345678901 diff --git a/vmbalance b/vmbalance index efaaca3..8cc12c6 100644 --- a/vmbalance +++ b/vmbalance @@ -14,6 +14,8 @@ BEGIN { sum=0 allocs=0 frees=0 + left=0 + peak=0 } /^execve/ { if (FNR == 1) { @@ -29,6 +31,8 @@ BEGIN { } else { sum+=$4 allocs++ + if (peak < sum) + peak = sum } } /^munmap(2|64)?\(/ { @@ -38,5 +42,6 @@ BEGIN { } } END { - print script ": " sum " bytes with " allocs " chunks allocated and " frees " chunks freed" > "/dev/fd/3" + left=allocs-frees + print script ": " sum " bytes summed up, " peak " peak value, " left " chunks left over, " allocs " allocated, and " frees " freed" > "/dev/fd/3" }