1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                  David Korn <dgk@research.att.com>                   *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21/*
22 *   Create and manage subshells avoiding forks when possible
23 *
24 *   David Korn
25 *   AT&T Labs
26 *
27 */
28
29#include	"defs.h"
30#include	<ls.h>
31#include	"io.h"
32#include	"fault.h"
33#include	"shnodes.h"
34#include	"shlex.h"
35#include	"jobs.h"
36#include	"variables.h"
37#include	"path.h"
38
39#ifndef PIPE_BUF
40#   define PIPE_BUF	512
41#endif
42
43/*
44 * Note that the following structure must be the same
45 * size as the Dtlink_t structure
46 */
47struct Link
48{
49	struct Link	*next;
50	Namval_t	*child;
51	Dt_t		*dict;
52	Namval_t	*node;
53};
54
55/*
56 * The following structure is used for command substitution and (...)
57 */
58static struct subshell
59{
60	Shell_t		*shp;	/* shell interpreter */
61	struct subshell	*prev;	/* previous subshell data */
62	struct subshell	*pipe;	/* subshell where output goes to pipe on fork */
63	Dt_t		*var;	/* variable table at time of subshell */
64	struct Link	*svar;	/* save shell variable table */
65	Dt_t		*sfun;	/* function scope for subshell */
66	Dt_t		*salias;/* alias scope for subshell */
67	Pathcomp_t	*pathlist; /* for PATH variable */
68#if (ERROR_VERSION >= 20030214L)
69	struct Error_context_s *errcontext;
70#else
71	struct errorcontext *errcontext;
72#endif
73	Shopt_t		options;/* save shell options */
74	pid_t		subpid;	/* child process id */
75	Sfio_t*	saveout;/*saved standard output */
76	char		*pwd;	/* present working directory */
77	const char	*shpwd;	/* saved pointer to sh.pwd */
78	void		*jobs;	/* save job info */
79	mode_t		mask;	/* saved umask */
80	short		tmpfd;	/* saved tmp file descriptor */
81	short		pipefd;	/* read fd if pipe is created */
82	char		jobcontrol;
83	char		monitor;
84	unsigned char	fdstatus;
85	int		fdsaved; /* bit make for saved files */
86	int		sig;	/* signal for $$ */
87	pid_t		bckpid;
88	pid_t		cpid;
89	int		coutpipe;
90	int		cpipe;
91	int		nofork;
92	char		subshare;
93} *subshell_data;
94
95static int subenv;
96
97/*
98 * This routine will turn the sftmp() file into a real /tmp file or pipe
99 */
100void	sh_subtmpfile(int pflag)
101{
102	Shell_t *shp = &sh;
103	int fds[2];
104	Sfoff_t off;
105	register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
106	register struct subshell *sp = subshell_data->pipe;
107	if(sfset(sfstdout,0,0)&SF_STRING)
108	{
109		register int fd;
110		/* save file descriptor 1 if open */
111		if((sp->tmpfd = fd = fcntl(1,F_DUPFD,10)) >= 0)
112		{
113			fcntl(fd,F_SETFD,FD_CLOEXEC);
114			shp->fdstatus[fd] = shp->fdstatus[1]|IOCLEX;
115			close(1);
116			shp->fdstatus[1] = IOCLOSE;
117		}
118		else if(errno!=EBADF)
119		{
120			((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
121			shp->toomany = 1;
122			errormsg(SH_DICT,ERROR_system(1),e_toomany);
123		}
124		if(shp->subshare || !pflag)
125		{
126			sfdisc(sfstdout,SF_POPDISC);
127			if((fd=sffileno(sfstdout))>=0)
128			{
129				shp->fdstatus[fd] = IOREAD|IOWRITE;
130				sfsync(sfstdout);
131				if(fd==1)
132					fcntl(1,F_SETFD,0);
133				else
134				{
135					sfsetfd(sfstdout,1);
136					shp->fdstatus[1] = shp->fdstatus[fd];
137					shp->fdstatus[fd] = IOCLOSE;
138				}
139				goto skip;
140			}
141		}
142	}
143	if(sp && (shp->fdstatus[1]==IOCLOSE || (!shp->subshare && !(shp->fdstatus[1]&IONOSEEK))))
144	{
145		struct stat statb,statx;
146		int fd;
147		sh_pipe(fds);
148		sp->pipefd = fds[0];
149		sh_fcntl(sp->pipefd,F_SETFD,FD_CLOEXEC);
150		/* write the data to the pipe */
151		if(off = sftell(sfstdout))
152		{
153			write(fds[1],sfsetbuf(sfstdout,(Void_t*)sfstdout,0),(size_t)off);
154			sfpurge(sfstdout);
155		}
156		if((sfset(sfstdout,0,0)&SF_STRING) || fstat(1,&statb)<0)
157			statb.st_ino = 0;
158		sfclose(sfstdout);
159		if((sh_fcntl(fds[1],F_DUPFD, 1)) != 1)
160			errormsg(SH_DICT,ERROR_system(1),e_redirect);
161		sh_close(fds[1]);
162		if(statb.st_ino) for(fd=0; fd < 10; fd++)
163		{
164			if(fd==1 || ((shp->fdstatus[fd]&(IONOSEEK|IOSEEK|IOWRITE))!=(IOSEEK|IOWRITE)) || fstat(fd,&statx)<0)
165				continue;
166			if(statb.st_ino==statx.st_ino && statb.st_dev==statx.st_dev)
167			{
168				sh_close(fd);
169				fcntl(1,F_DUPFD, fd);
170			}
171		}
172	skip:
173		sh_iostream(shp,1);
174		sfset(sfstdout,SF_SHARE|SF_PUBLIC,1);
175		sfpool(sfstdout,shp->outpool,SF_WRITE);
176		if(pp && pp->olist  && pp->olist->strm == sfstdout)
177			pp->olist->strm = 0;
178	}
179}
180
181
182/*
183 * This routine creates a temp file if necessary and creates a subshell.
184 * The parent routine longjmps back to sh_subshell()
185 * The child continues possibly with its standard output replaced by temp file
186 */
187void sh_subfork(void)
188{
189	register struct subshell *sp = subshell_data;
190	Shell_t	*shp = sp->shp;
191	int	curenv = shp->curenv;
192	pid_t pid;
193	char *trap = shp->st.trapcom[0];
194	if(trap)
195		trap = strdup(trap);
196	/* see whether inside $(...) */
197	if(sp->pipe)
198		sh_subtmpfile(1);
199	shp->curenv = 0;
200	if(pid = sh_fork(FSHOWME,NIL(int*)))
201	{
202		shp->curenv = curenv;
203		/* this is the parent part of the fork */
204		if(sp->subpid==0)
205			sp->subpid = pid;
206		if(trap)
207			free((void*)trap);
208		siglongjmp(*shp->jmplist,SH_JMPSUB);
209	}
210	else
211	{
212		/* this is the child part of the fork */
213		/* setting subpid to 1 causes subshell to exit when reached */
214		sh_onstate(SH_FORKED);
215		sh_onstate(SH_NOLOG);
216		sh_offoption(SH_MONITOR);
217		sh_offstate(SH_MONITOR);
218		subshell_data = 0;
219		shp->subshell = 0;
220		SH_SUBSHELLNOD->nvalue.s = 0;
221		sp->subpid=0;
222		shp->st.trapcom[0] = trap;
223	}
224}
225
226int nv_subsaved(register Namval_t *np)
227{
228	register struct subshell	*sp;
229	register struct Link		*lp;
230	for(sp = (struct subshell*)subshell_data; sp; sp=sp->prev)
231	{
232		for(lp=sp->svar; lp; lp = lp->next)
233		{
234			if(lp->node==np)
235				return(1);
236		}
237	}
238	return(0);
239}
240
241/*
242 * This routine will make a copy of the given node in the
243 * layer created by the most recent subshell_fork if the
244 * node hasn't already been copied
245 */
246Namval_t *sh_assignok(register Namval_t *np,int add)
247{
248	register Namval_t	*mp;
249	register struct Link	*lp;
250	register struct subshell *sp = (struct subshell*)subshell_data;
251	struct Ufunction	*rp;
252	Shell_t			*shp = sp->shp;
253	Dt_t			*dp;
254	Namval_t		*mpnext;
255	Namarr_t		*ap;
256	int			save;
257	/* don't bother with this */
258	if(!sp->shpwd || (nv_isnull(np) && !add) || np==SH_LEVELNOD)
259		return(np);
260	/* don't bother to save if in newer scope */
261	if(!(rp=shp->st.real_fun)  || !(dp=rp->sdict))
262		dp = sp->var;
263	if(np->nvenv && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && shp->last_root)
264		dp = shp->last_root;
265	if((mp=nv_search((char*)np,dp,HASH_BUCKET))!=np)
266	{
267		if(mp || !np->nvfun || np->nvfun->subshell>=sh.subshell)
268			return(np);
269	}
270	if((ap=nv_arrayptr(np)) && (mp=nv_opensub(np)))
271	{
272		shp->last_root = ap->table;
273		sh_assignok(mp,add);
274		if(!add || array_assoc(ap))
275			return(np);
276	}
277	for(lp=subshell_data->svar; lp; lp = lp->next)
278	{
279		if(lp->node==np)
280			return(np);
281	}
282	/* first two pointers use linkage from np */
283	lp = (struct Link*)malloc(sizeof(*np)+2*sizeof(void*));
284	memset(lp,0, sizeof(*mp)+2*sizeof(void*));
285	lp->node = np;
286	if(!add &&  nv_isvtree(np))
287	{
288		Namval_t	fake;
289		Dt_t		*walk, *root=shp->var_tree;
290		char		*name = nv_name(np);
291		int		len = strlen(name);
292		fake.nvname = name;
293		mpnext = dtnext(root,&fake);
294		dp = root->walk?root->walk:root;
295		while(mp=mpnext)
296		{
297			walk = root->walk?root->walk:root;
298			mpnext = dtnext(root,mp);
299			if(memcmp(name,mp->nvname,len) || mp->nvname[len]!='.')
300				break;
301			nv_delete(mp,walk,NV_NOFREE);
302			*((Namval_t**)mp) = lp->child;
303			lp->child = mp;
304
305		}
306	}
307	lp->dict = dp;
308	mp = (Namval_t*)&lp->dict;
309	lp->next = subshell_data->svar;
310	subshell_data->svar = lp;
311	save = shp->subshell;
312	shp->subshell = 0;
313	mp->nvname = np->nvname;
314	nv_clone(np,mp,(add?(nv_isnull(np)?0:NV_NOFREE)|NV_ARRAY:NV_MOVE));
315	shp->subshell = save;
316	return(np);
317}
318
319/*
320 * restore the variables
321 */
322static void nv_restore(struct subshell *sp)
323{
324	register struct Link *lp, *lq;
325	register Namval_t *mp, *np;
326	const char *save = sp->shpwd;
327	Namval_t	*mpnext;
328	sp->shpwd = 0;	/* make sure sh_assignok doesn't save with nv_unset() */
329	for(lp=sp->svar; lp; lp=lq)
330	{
331		np = (Namval_t*)&lp->dict;
332		lq = lp->next;
333		mp = lp->node;
334		if(!mp->nvname)
335			continue;
336		if(nv_isarray(mp))
337			 nv_putsub(mp,NIL(char*),ARRAY_SCAN);
338		_nv_unset(mp,NV_RDONLY|NV_CLONE);
339		if(nv_isarray(np))
340		{
341			nv_clone(np,mp,NV_MOVE);
342			goto skip;
343		}
344		nv_setsize(mp,nv_size(np));
345		if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT))
346			mp->nvenv = np->nvenv;
347		mp->nvfun = np->nvfun;
348		mp->nvflag = np->nvflag;
349		if(nv_cover(mp))
350		{
351			nv_putval(mp, nv_getval(np),np->nvflag|NV_NOFREE);
352			if(!nv_isattr(np,NV_NOFREE))
353				nv_offattr(mp,NV_NOFREE);
354		}
355		else
356			mp->nvalue.cp = np->nvalue.cp;
357		np->nvfun = 0;
358		if(nv_isattr(mp,NV_EXPORT))
359		{
360			char *name = nv_name(mp);
361			sh_envput(sh.env,mp);
362			if(*name=='_' && strcmp(name,"_AST_FEATURES")==0)
363				astconf(NiL, NiL, NiL);
364		}
365		else if(nv_isattr(np,NV_EXPORT))
366			env_delete(sh.env,nv_name(mp));
367	skip:
368		for(mp=lp->child; mp; mp=mpnext)
369		{
370			mpnext = *((Namval_t**)mp);
371			dtinsert(lp->dict,mp);
372		}
373		free((void*)lp);
374		sp->svar = lq;
375	}
376	sp->shpwd=save;
377}
378
379/*
380 * return pointer to alias tree
381 * create new one if in a subshell and one doesn't exist and create is non-zero
382 */
383Dt_t *sh_subaliastree(int create)
384{
385	register struct subshell *sp = subshell_data;
386	if(!sp || sh.curenv==0)
387		return(sh.alias_tree);
388	if(!sp->salias && create)
389	{
390		sp->salias = dtopen(&_Nvdisc,Dtoset);
391		dtview(sp->salias,sh.alias_tree);
392		sh.alias_tree = sp->salias;
393	}
394	return(sp->salias);
395}
396
397/*
398 * return pointer to function tree
399 * create new one if in a subshell and one doesn't exist and create is non-zero
400 */
401Dt_t *sh_subfuntree(int create)
402{
403	register struct subshell *sp = subshell_data;
404	if(!sp || sh.curenv==0)
405		return(sh.fun_tree);
406	if(!sp->sfun && create)
407	{
408		sp->sfun = dtopen(&_Nvdisc,Dtoset);
409		dtview(sp->sfun,sh.fun_tree);
410		sh.fun_tree = sp->sfun;
411	}
412	return(sh.fun_tree);
413}
414
415static void table_unset(register Dt_t *root,int fun)
416{
417	register Namval_t *np,*nq;
418	int flag;
419	for(np=(Namval_t*)dtfirst(root);np;np=nq)
420	{
421		nq = (Namval_t*)dtnext(root,np);
422		flag=0;
423		if(fun && np->nvalue.rp && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/')
424		{
425			np->nvalue.rp->fdict = 0;
426			flag = NV_NOFREE;
427		}
428		else
429			_nv_unset(np,NV_RDONLY);
430		nv_delete(np,root,flag|NV_FUNCTION);
431	}
432}
433
434int sh_subsavefd(register int fd)
435{
436	register struct subshell *sp = subshell_data;
437	register int old=0;
438	if(sp)
439	{
440		old = !(sp->fdsaved&(1<<(fd-1)));
441		sp->fdsaved |= (1<<(fd-1));
442	}
443	return(old);
444}
445
446void sh_subjobcheck(pid_t pid)
447{
448	register struct subshell *sp = subshell_data;
449	while(sp)
450	{
451		if(sp->cpid==pid)
452		{
453			sh_close(sp->coutpipe);
454			sh_close(sp->cpipe);
455			sp->coutpipe = sp->cpipe = -1;
456			return;
457		}
458		sp = sp->prev;
459	}
460}
461
462/*
463 * Run command tree <t> in a virtual sub-shell
464 * If comsub is not null, then output will be placed in temp file (or buffer)
465 * If comsub is not null, the return value will be a stream consisting of
466 * output of command <t>.  Otherwise, NULL will be returned.
467 */
468
469Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub)
470{
471	Shell_t *shp = &sh;
472	struct subshell sub_data;
473	register struct subshell *sp = &sub_data;
474	int jmpval,nsig=0,duped=0;
475	int savecurenv = shp->curenv;
476	int savejobpgid = job.curpgid;
477	int16_t subshell;
478	char *savsig;
479	Sfio_t *iop=0;
480	struct checkpt buff;
481	struct sh_scoped savst;
482	struct dolnod   *argsav=0;
483	memset((char*)sp, 0, sizeof(*sp));
484	sfsync(shp->outpool);
485	argsav = sh_arguse(shp);
486	if(shp->curenv==0)
487	{
488		subshell_data=0;
489		subenv = 0;
490	}
491	shp->curenv = ++subenv;
492	job.curpgid = 0;
493	savst = shp->st;
494	sh_pushcontext(&buff,SH_JMPSUB);
495	subshell = shp->subshell+1;
496	SH_SUBSHELLNOD->nvalue.s = subshell;
497	shp->subshell = subshell;
498	sp->prev = subshell_data;
499	sp->shp = shp;
500	sp->sig = 0;
501	subshell_data = sp;
502	sp->errcontext = &buff.err;
503	sp->var = shp->var_tree;
504	sp->options = shp->options;
505	sp->jobs = job_subsave();
506	/* make sure initialization has occurred */
507	if(!shp->pathlist)
508		path_get(".");
509	sp->pathlist = path_dup((Pathcomp_t*)shp->pathlist);
510	if(!shp->pwd)
511		path_pwd(0);
512	sp->bckpid = shp->bckpid;
513	if(comsub)
514		sh_stats(STAT_COMSUB);
515	sp->subshare = shp->subshare;
516	shp->subshare = comsub==2 ||  (comsub==1 && sh_isoption(SH_SUBSHARE));
517	if(!comsub || !shp->subshare)
518	{
519		sp->shpwd = shp->pwd;
520		sp->pwd = (shp->pwd?strdup(shp->pwd):0);
521		sp->mask = shp->mask;
522		sh_stats(STAT_SUBSHELL);
523		/* save trap table */
524		shp->st.otrapcom = 0;
525		if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0])
526		{
527			nsig += sizeof(char*);
528			memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig);
529			/* this nonsense needed for $(trap) */
530			shp->st.otrapcom = (char**)savsig;
531		}
532		sp->cpid = shp->cpid;
533		sp->coutpipe = shp->coutpipe;
534		sp->cpipe = shp->cpipe[1];
535		shp->cpid = 0;
536		sh_sigreset(0);
537	}
538	jmpval = sigsetjmp(buff.buff,0);
539	if(jmpval==0)
540	{
541		if(comsub)
542		{
543			/* disable job control */
544			shp->spid = 0;
545			sp->jobcontrol = job.jobcontrol;
546			sp->monitor = (sh_isstate(SH_MONITOR)!=0);
547			job.jobcontrol=0;
548			sh_offstate(SH_MONITOR);
549			sp->pipe = sp;
550			/* save sfstdout and status */
551			sp->saveout = sfswap(sfstdout,NIL(Sfio_t*));
552			sp->fdstatus = shp->fdstatus[1];
553			sp->tmpfd = -1;
554			sp->pipefd = -1;
555			/* use sftmp() file for standard output */
556			if(!(iop = sftmp(PIPE_BUF)))
557			{
558				sfswap(sp->saveout,sfstdout);
559				errormsg(SH_DICT,ERROR_system(1),e_tmpcreate);
560			}
561			sfswap(iop,sfstdout);
562			sfset(sfstdout,SF_READ,0);
563			shp->fdstatus[1] = IOWRITE;
564			if(!(sp->nofork = sh_state(SH_NOFORK)))
565				sh_onstate(SH_NOFORK);
566			flags |= sh_state(SH_NOFORK);
567		}
568		else if(sp->prev)
569		{
570			sp->pipe = sp->prev->pipe;
571			flags &= ~sh_state(SH_NOFORK);
572		}
573		sh_exec(t,flags);
574	}
575	if(comsub!=2 && jmpval!=SH_JMPSUB && shp->st.trapcom[0] && shp->subshell)
576	{
577		/* trap on EXIT not handled by child */
578		char *trap=shp->st.trapcom[0];
579		shp->st.trapcom[0] = 0;	/* prevent recursion */
580		shp->oldexit = shp->exitval;
581		sh_trap(trap,0);
582		free(trap);
583	}
584	sh_popcontext(&buff);
585	if(shp->subshell==0)	/* must be child process */
586	{
587		subshell_data = sp->prev;
588		if(jmpval==SH_JMPSCRIPT)
589			siglongjmp(*shp->jmplist,jmpval);
590		shp->exitval &= SH_EXITMASK;
591		sh_done(shp,0);
592	}
593	if(comsub)
594	{
595		/* re-enable job control */
596		if(!sp->nofork)
597			sh_offstate(SH_NOFORK);
598		job.jobcontrol = sp->jobcontrol;
599		if(sp->monitor)
600			sh_onstate(SH_MONITOR);
601		if(sp->pipefd>=0)
602		{
603			/* sftmp() file has been returned into pipe */
604			iop = sh_iostream(shp,sp->pipefd);
605			sfclose(sfstdout);
606		}
607		else
608		{
609			/* move tmp file to iop and restore sfstdout */
610			iop = sfswap(sfstdout,NIL(Sfio_t*));
611			if(!iop)
612			{
613				/* maybe locked try again */
614				sfclrlock(sfstdout);
615				iop = sfswap(sfstdout,NIL(Sfio_t*));
616			}
617			if(iop && sffileno(iop)==1)
618			{
619				int fd=sfsetfd(iop,3);
620				if(fd<0)
621				{
622					shp->toomany = 1;
623					((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
624					errormsg(SH_DICT,ERROR_system(1),e_toomany);
625				}
626				shp->sftable[fd] = iop;
627				fcntl(fd,F_SETFD,FD_CLOEXEC);
628				shp->fdstatus[fd] = (shp->fdstatus[1]|IOCLEX);
629				shp->fdstatus[1] = IOCLOSE;
630			}
631			sfset(iop,SF_READ,1);
632		}
633		sfswap(sp->saveout,sfstdout);
634		/*  check if standard output was preserved */
635		if(sp->tmpfd>=0)
636		{
637			close(1);
638			if (fcntl(sp->tmpfd,F_DUPFD,1) != 1)
639				duped++;
640			sh_close(sp->tmpfd);
641		}
642		shp->fdstatus[1] = sp->fdstatus;
643	}
644	if(sp->subpid)
645	{
646		if(shp->exitval > SH_EXITSIG)
647			sp->sig = (shp->exitval&SH_EXITMASK);
648		shp->exitval = 0;
649		if(comsub)
650			shp->spid = sp->subpid;
651	}
652	if(comsub && iop && sp->pipefd<0)
653		sfseek(iop,(off_t)0,SEEK_SET);
654	path_delete((Pathcomp_t*)shp->pathlist);
655	shp->pathlist = (void*)sp->pathlist;
656	job_subrestore(sp->jobs);
657	shp->jobenv = savecurenv;
658	job.curpgid = savejobpgid;
659	shp->bckpid = sp->bckpid;
660	if(sp->shpwd)	/* restore environment if saved */
661	{
662		int n;
663		shp->options = sp->options;
664		nv_restore(sp);
665		if(sp->salias)
666		{
667			shp->alias_tree = dtview(sp->salias,0);
668			table_unset(sp->salias,0);
669			dtclose(sp->salias);
670		}
671		if(sp->sfun)
672		{
673			shp->fun_tree = dtview(sp->sfun,0);
674			table_unset(sp->sfun,1);
675			dtclose(sp->sfun);
676		}
677		n = shp->st.trapmax-savst.trapmax;
678		sh_sigreset(1);
679		if(n>0)
680			memset(&shp->st.trapcom[savst.trapmax],0,n*sizeof(char*));
681		shp->st = savst;
682		shp->curenv = savecurenv;
683		if(nsig)
684		{
685			memcpy((char*)&shp->st.trapcom[0],savsig,nsig);
686			free((void*)savsig);
687		}
688		shp->options = sp->options;
689		if(!shp->pwd || strcmp(sp->pwd,shp->pwd))
690		{
691			/* restore PWDNOD */
692			Namval_t *pwdnod = sh_scoped(shp,PWDNOD);
693			if(shp->pwd)
694			{
695				chdir(shp->pwd=sp->pwd);
696				path_newdir(shp->pathlist);
697			}
698			if(nv_isattr(pwdnod,NV_NOFREE))
699				pwdnod->nvalue.cp = (const char*)sp->pwd;
700		}
701		else if(sp->shpwd != shp->pwd)
702		{
703			shp->pwd = sp->pwd;
704			if(PWDNOD->nvalue.cp==sp->shpwd)
705				PWDNOD->nvalue.cp = sp->pwd;
706		}
707		else
708			free((void*)sp->pwd);
709		if(sp->mask!=shp->mask)
710			umask(shp->mask=sp->mask);
711		if(shp->coutpipe!=sp->coutpipe)
712		{
713			sh_close(shp->coutpipe);
714			sh_close(shp->cpipe[1]);
715		}
716		shp->cpid = sp->cpid;
717		shp->cpipe[1] = sp->cpipe;
718		shp->coutpipe = sp->coutpipe;
719	}
720	shp->subshare = sp->subshare;
721	if(shp->subshell)
722		SH_SUBSHELLNOD->nvalue.s = --shp->subshell;
723	subshell = shp->subshell;
724	subshell_data = sp->prev;
725	sh_argfree(shp,argsav,0);
726	if(shp->topfd != buff.topfd)
727		sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval);
728	if(sp->sig)
729	{
730		if(sp->prev)
731			sp->prev->sig = sp->sig;
732		else
733		{
734			sh_fault(sp->sig);
735			sh_chktrap();
736		}
737	}
738	sh_sigcheck();
739	shp->trapnote = 0;
740	if(sp->subpid && !comsub)
741		job_wait(sp->subpid);
742	if(shp->exitval > SH_EXITSIG)
743	{
744		int sig = shp->exitval&SH_EXITMASK;
745		if(sig==SIGINT || sig== SIGQUIT)
746			sh_fault(sig);
747	}
748	if(duped)
749	{
750		((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
751		shp->toomany = 1;
752		errormsg(SH_DICT,ERROR_system(1),e_redirect);
753	}
754	if(jmpval && shp->toomany)
755		siglongjmp(*shp->jmplist,jmpval);
756	return(iop);
757}
758