xref: /titanic_50/usr/src/lib/libshell/common/sh/subshell.c (revision 13237b7e1e5bd293e466307b2e06f8e0e2321a0a)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2008 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  */
47 struct 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  */
58 static 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 
95 static int subenv;
96 
97 /*
98  * This routine will turn the sftmp() file into a real /tmp file or pipe
99  */
100 void	sh_subtmpfile(int pflag)
101 {
102 	Shell_t *shp = &sh;
103 	int fds[2];
104 	Sfoff_t off;
105 	if(sfset(sfstdout,0,0)&SF_STRING)
106 	{
107 		register int fd;
108 		register struct checkpt	*pp = (struct checkpt*)shp->jmplist;
109 		register struct subshell *sp = subshell_data->pipe;
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 		}
117 		else if(errno!=EBADF)
118 			errormsg(SH_DICT,ERROR_system(1),e_toomany);
119 		if(!pflag)
120 		{
121 			sfdisc(sfstdout,SF_POPDISC);
122 			if((fd=sffileno(sfstdout))>=0)
123 			{
124 				sh.fdstatus[fd] = IOREAD|IOWRITE;
125 				sfsync(sfstdout);
126 				if(fd==1)
127 					fcntl(1,F_SETFD,0);
128 				else
129 				{
130 					sfsetfd(sfstdout,1);
131 					sh.fdstatus[1] = sh.fdstatus[fd];
132 					sh.fdstatus[fd] = IOCLOSE;
133 				}
134 				goto skip;
135 			}
136 		}
137 		sh_pipe(fds);
138 		sp->pipefd = fds[0];
139 		sh_fcntl(sp->pipefd,F_SETFD,FD_CLOEXEC);
140 		/* write the data to the pipe */
141 		if(off = sftell(sfstdout))
142 		{
143 			write(fds[1],sfsetbuf(sfstdout,(Void_t*)sfstdout,0),(size_t)off);
144 			sfpurge(sfstdout);
145 		}
146 		sfclose(sfstdout);
147 		if((sh_fcntl(fds[1],F_DUPFD, 1)) != 1)
148 			errormsg(SH_DICT,ERROR_system(1),e_file+4);
149 		sh_close(fds[1]);
150 	skip:
151 		sh_iostream(shp,1);
152 		sfset(sfstdout,SF_SHARE|SF_PUBLIC,1);
153 		sfpool(sfstdout,shp->outpool,SF_WRITE);
154 		if(pp && pp->olist  && pp->olist->strm == sfstdout)
155 			pp->olist->strm = 0;
156 	}
157 }
158 
159 /*
160  * This routine creates a temp file if necessary and creates a subshell.
161  * The parent routine longjmps back to sh_subshell()
162  * The child continues possibly with its standard output replaced by temp file
163  */
164 void sh_subfork(void)
165 {
166 	register struct subshell *sp = subshell_data;
167 	Shell_t	*shp = sp->shp;
168 	int	curenv = shp->curenv;
169 	pid_t pid;
170 	/* see whether inside $(...) */
171 	if(sp->pipe)
172 		sh_subtmpfile(1);
173 	shp->curenv = 0;
174 	if(pid = sh_fork(0,NIL(int*)))
175 	{
176 		shp->curenv = curenv;
177 		/* this is the parent part of the fork */
178 		if(sp->subpid==0)
179 			sp->subpid = pid;
180 		siglongjmp(*shp->jmplist,SH_JMPSUB);
181 	}
182 	else
183 	{
184 		/* this is the child part of the fork */
185 		/* setting subpid to 1 causes subshell to exit when reached */
186 		sh_onstate(SH_FORKED);
187 		sh_onstate(SH_NOLOG);
188 		sh_offstate(SH_MONITOR);
189 		subshell_data = 0;
190 		shp->subshell = 0;
191 		SH_SUBSHELLNOD->nvalue.s = 0;
192 		sp->subpid=0;
193 	}
194 }
195 
196 int nv_subsaved(register Namval_t *np)
197 {
198 	register struct subshell	*sp;
199 	register struct Link		*lp;
200 	for(sp = (struct subshell*)subshell_data; sp; sp=sp->prev)
201 	{
202 		for(lp=sp->svar; lp; lp = lp->next)
203 		{
204 			if(lp->node==np)
205 				return(1);
206 		}
207 	}
208 	return(0);
209 }
210 
211 /*
212  * This routine will make a copy of the given node in the
213  * layer created by the most recent subshell_fork if the
214  * node hasn't already been copied
215  */
216 Namval_t *sh_assignok(register Namval_t *np,int add)
217 {
218 	register Namval_t	*mp;
219 	register struct Link	*lp;
220 	register struct subshell *sp = (struct subshell*)subshell_data;
221 	struct Ufunction	*rp;
222 	Shell_t			*shp = sp->shp;
223 	Dt_t			*dp;
224 	Namval_t		*mpnext;
225 	Namarr_t		*ap;
226 	int			save;
227 	/* don't bother with this */
228 	if(!sp->shpwd || (nv_isnull(np) && !add))
229 		return(np);
230 	/* don't bother to save if in newer scope */
231 	if(!(rp=shp->st.real_fun)  || !(dp=rp->sdict))
232 		dp = sp->var;
233 	if(np->nvenv && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && shp->last_root)
234 		dp = shp->last_root;
235 	if((mp=nv_search((char*)np,dp,HASH_BUCKET))!=np)
236 	{
237 		if(mp || !np->nvfun || np->nvfun->subshell>=sh.subshell)
238 			return(np);
239 	}
240 	if((ap=nv_arrayptr(np)) && (mp=nv_opensub(np)))
241 	{
242 		shp->last_root = ap->table;
243 		sh_assignok(mp,add);
244 		if(!add || array_assoc(ap))
245 			return(np);
246 	}
247 	for(lp=subshell_data->svar; lp; lp = lp->next)
248 	{
249 		if(lp->node==np)
250 			return(np);
251 	}
252 	/* first two pointers use linkage from np */
253 	lp = (struct Link*)malloc(sizeof(*np)+2*sizeof(void*));
254 	memset(lp,0, sizeof(*mp)+2*sizeof(void*));
255 	lp->node = np;
256 	if(!add &&  nv_isvtree(np))
257 	{
258 		Namval_t	fake;
259 		Dt_t		*walk, *root=shp->var_tree;
260 		char		*name = nv_name(np);
261 		int		len = strlen(name);
262 		fake.nvname = name;
263 		mpnext = dtnext(root,&fake);
264 		dp = root->walk?root->walk:root;
265 		while(mp=mpnext)
266 		{
267 			walk = root->walk?root->walk:root;
268 			mpnext = dtnext(root,mp);
269 			if(memcmp(name,mp->nvname,len) || mp->nvname[len]!='.')
270 				break;
271 			nv_delete(mp,walk,NV_NOFREE);
272 			*((Namval_t**)mp) = lp->child;
273 			lp->child = mp;
274 
275 		}
276 	}
277 	lp->dict = dp;
278 	mp = (Namval_t*)&lp->dict;
279 	lp->next = subshell_data->svar;
280 	subshell_data->svar = lp;
281 	save = shp->subshell;
282 	shp->subshell = 0;
283 	mp->nvname = np->nvname;
284 	nv_clone(np,mp,(add?(nv_isnull(np)?0:NV_NOFREE)|NV_ARRAY:NV_MOVE));
285 	shp->subshell = save;
286 	return(np);
287 }
288 
289 /*
290  * restore the variables
291  */
292 static void nv_restore(struct subshell *sp)
293 {
294 	register struct Link *lp, *lq;
295 	register Namval_t *mp, *np;
296 	const char *save = sp->shpwd;
297 	Namval_t	*mpnext;
298 	sp->shpwd = 0;	/* make sure sh_assignok doesn't save with nv_unset() */
299 	for(lp=sp->svar; lp; lp=lq)
300 	{
301 		np = (Namval_t*)&lp->dict;
302 		lq = lp->next;
303 		mp = lp->node;
304 		if(!mp->nvname)
305 			continue;
306 		if(nv_isarray(mp))
307 			 nv_putsub(mp,NIL(char*),ARRAY_SCAN);
308 		_nv_unset(mp,NV_RDONLY);
309 		if(nv_isarray(np))
310 		{
311 			nv_clone(np,mp,NV_MOVE);
312 			goto skip;
313 		}
314 		nv_setsize(mp,nv_size(np));
315 		if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT))
316 			mp->nvenv = np->nvenv;
317 		mp->nvfun = np->nvfun;
318 		mp->nvflag = np->nvflag;
319 		if(nv_cover(mp))
320 			nv_putval(mp, np->nvalue.cp,0);
321 		else
322 			mp->nvalue.cp = np->nvalue.cp;
323 		np->nvfun = 0;
324 		if(nv_isattr(mp,NV_EXPORT))
325 		{
326 			char *name = nv_name(mp);
327 			sh_envput(sh.env,mp);
328 			if(*name=='_' && strcmp(name,"_AST_FEATURES")==0)
329 				astconf(NiL, NiL, NiL);
330 		}
331 		else if(nv_isattr(np,NV_EXPORT))
332 			env_delete(sh.env,nv_name(mp));
333 	skip:
334 		for(mp=lp->child; mp; mp=mpnext)
335 		{
336 			mpnext = *((Namval_t**)mp);
337 			dtinsert(lp->dict,mp);
338 		}
339 		free((void*)lp);
340 		sp->svar = lq;
341 	}
342 	sp->shpwd=save;
343 }
344 
345 /*
346  * return pointer to alias tree
347  * create new one if in a subshell and one doesn't exist and create is non-zero
348  */
349 Dt_t *sh_subaliastree(int create)
350 {
351 	register struct subshell *sp = subshell_data;
352 	if(!sp || sh.curenv==0)
353 		return(sh.alias_tree);
354 	if(!sp->salias && create)
355 	{
356 		sp->salias = dtopen(&_Nvdisc,Dtoset);
357 		dtview(sp->salias,sh.alias_tree);
358 		sh.alias_tree = sp->salias;
359 	}
360 	return(sp->salias);
361 }
362 
363 /*
364  * return pointer to function tree
365  * create new one if in a subshell and one doesn't exist and create is non-zero
366  */
367 Dt_t *sh_subfuntree(int create)
368 {
369 	register struct subshell *sp = subshell_data;
370 	if(!sp || sh.curenv==0)
371 		return(sh.fun_tree);
372 	if(!sp->sfun && create)
373 	{
374 		sp->sfun = dtopen(&_Nvdisc,Dtoset);
375 		dtview(sp->sfun,sh.fun_tree);
376 		sh.fun_tree = sp->sfun;
377 	}
378 	return(sh.fun_tree);
379 }
380 
381 static void table_unset(register Dt_t *root,int fun)
382 {
383 	register Namval_t *np,*nq;
384 	int flag;
385 	for(np=(Namval_t*)dtfirst(root);np;np=nq)
386 	{
387 		nq = (Namval_t*)dtnext(root,np);
388 		flag=0;
389 		if(fun && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/')
390 		{
391 			np->nvalue.rp->fdict = 0;
392 			flag = NV_NOFREE;
393 		}
394 		else
395 			_nv_unset(np,NV_RDONLY);
396 		nv_delete(np,root,flag|NV_FUNCTION);
397 	}
398 }
399 
400 int sh_subsavefd(register int fd)
401 {
402 	register struct subshell *sp = subshell_data;
403 	register int old=0;
404 	if(sp)
405 	{
406 		old = !(sp->fdsaved&(1<<(fd-1)));
407 		sp->fdsaved |= (1<<(fd-1));
408 	}
409 	return(old);
410 }
411 
412 void sh_subjobcheck(pid_t pid)
413 {
414 	register struct subshell *sp = subshell_data;
415 	while(sp)
416 	{
417 		if(sp->cpid==pid)
418 		{
419 			sh_close(sp->coutpipe);
420 			sh_close(sp->cpipe);
421 			sp->coutpipe = sp->cpipe = -1;
422 			return;
423 		}
424 		sp = sp->prev;
425 	}
426 }
427 
428 /*
429  * Run command tree <t> in a virtual sub-shell
430  * If comsub is not null, then output will be placed in temp file (or buffer)
431  * If comsub is not null, the return value will be a stream consisting of
432  * output of command <t>.  Otherwise, NULL will be returned.
433  */
434 
435 Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub)
436 {
437 	Shell_t *shp = &sh;
438 	struct subshell sub_data;
439 	register struct subshell *sp = &sub_data;
440 	int jmpval,nsig=0;
441 	int savecurenv = shp->curenv;
442 	int savejobpgid = job.curpgid;
443 	int16_t subshell;
444 	char *savsig;
445 	Sfio_t *iop=0;
446 	struct checkpt buff;
447 	struct sh_scoped savst;
448 	struct dolnod   *argsav=0;
449 	memset((char*)sp, 0, sizeof(*sp));
450 	sfsync(shp->outpool);
451 	argsav = sh_arguse(shp);
452 	if(shp->curenv==0)
453 	{
454 		subshell_data=0;
455 		subenv = 0;
456 	}
457 	shp->curenv = ++subenv;
458 	job.curpgid = 0;
459 	savst = shp->st;
460 	sh_pushcontext(&buff,SH_JMPSUB);
461 	subshell = shp->subshell+1;
462 	SH_SUBSHELLNOD->nvalue.s = subshell;
463 	shp->subshell = subshell;
464 	sp->prev = subshell_data;
465 	sp->shp = shp;
466 	sp->sig = 0;
467 	subshell_data = sp;
468 	sp->errcontext = &buff.err;
469 	sp->var = shp->var_tree;
470 	sp->options = shp->options;
471 	sp->jobs = job_subsave();
472 	/* make sure initialization has occurred */
473 	if(!shp->pathlist)
474 		path_get(".");
475 	sp->pathlist = path_dup((Pathcomp_t*)shp->pathlist);
476 	if(!shp->pwd)
477 		path_pwd(0);
478 	sp->bckpid = shp->bckpid;
479 	if(comsub)
480 		sh_stats(STAT_COMSUB);
481 	sp->subshare = shp->subshare;
482 	shp->subshare = comsub==2 ||  (comsub==1 && sh_isoption(SH_SUBSHARE));
483 	if(!comsub || !shp->subshare)
484 	{
485 		sp->shpwd = shp->pwd;
486 		sp->pwd = (shp->pwd?strdup(shp->pwd):0);
487 		sp->mask = shp->mask;
488 		sh_stats(STAT_SUBSHELL);
489 		/* save trap table */
490 		shp->st.otrapcom = 0;
491 		if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0])
492 		{
493 			nsig += sizeof(char*);
494 			memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig);
495 			/* this nonsense needed for $(trap) */
496 			shp->st.otrapcom = (char**)savsig;
497 		}
498 		sp->cpid = shp->cpid;
499 		sp->coutpipe = shp->coutpipe;
500 		sp->cpipe = shp->cpipe[1];
501 		shp->coutpipe = shp->cpipe[1] = -1;
502 		shp->cpid = 0;
503 		sh_sigreset(0);
504 	}
505 	jmpval = sigsetjmp(buff.buff,0);
506 	if(jmpval==0)
507 	{
508 		if(comsub)
509 		{
510 			/* disable job control */
511 			shp->spid = 0;
512 			sp->jobcontrol = job.jobcontrol;
513 			sp->monitor = (sh_isstate(SH_MONITOR)!=0);
514 			job.jobcontrol=0;
515 			sh_offstate(SH_MONITOR);
516 			sp->pipe = sp;
517 			/* save sfstdout and status */
518 			sp->saveout = sfswap(sfstdout,NIL(Sfio_t*));
519 			sp->fdstatus = shp->fdstatus[1];
520 			sp->tmpfd = -1;
521 			sp->pipefd = -1;
522 			/* use sftmp() file for standard output */
523 			if(!(iop = sftmp(PIPE_BUF)))
524 			{
525 				sfswap(sp->saveout,sfstdout);
526 				errormsg(SH_DICT,ERROR_system(1),e_tmpcreate);
527 			}
528 			sfswap(iop,sfstdout);
529 			sfset(sfstdout,SF_READ,0);
530 			shp->fdstatus[1] = IOWRITE;
531 			if(!(sp->nofork = sh_state(SH_NOFORK)))
532 				sh_onstate(SH_NOFORK);
533 			flags |= sh_state(SH_NOFORK);
534 		}
535 		else if(sp->prev)
536 		{
537 			sp->pipe = sp->prev->pipe;
538 			flags &= ~sh_state(SH_NOFORK);
539 		}
540 		sh_exec(t,flags);
541 	}
542 	if(comsub!=2 && jmpval!=SH_JMPSUB && shp->st.trapcom[0] && shp->subshell)
543 	{
544 		/* trap on EXIT not handled by child */
545 		char *trap=shp->st.trapcom[0];
546 		shp->st.trapcom[0] = 0;	/* prevent recursion */
547 		shp->oldexit = shp->exitval;
548 		sh_trap(trap,0);
549 		free(trap);
550 	}
551 	sh_popcontext(&buff);
552 	if(shp->subshell==0)	/* must be child process */
553 	{
554 		subshell_data = sp->prev;
555 		if(jmpval==SH_JMPSCRIPT)
556 			siglongjmp(*shp->jmplist,jmpval);
557 		sh_done(shp,0);
558 	}
559 	if(comsub)
560 	{
561 		/* re-enable job control */
562 		if(!sp->nofork)
563 			sh_offstate(SH_NOFORK);
564 		job.jobcontrol = sp->jobcontrol;
565 		if(sp->monitor)
566 			sh_onstate(SH_MONITOR);
567 		if(sp->pipefd>=0)
568 		{
569 			/* sftmp() file has been returned into pipe */
570 			iop = sh_iostream(shp,sp->pipefd);
571 			sfclose(sfstdout);
572 		}
573 		else
574 		{
575 			/* move tmp file to iop and restore sfstdout */
576 			iop = sfswap(sfstdout,NIL(Sfio_t*));
577 			if(!iop)
578 			{
579 				/* maybe locked try again */
580 				sfclrlock(sfstdout);
581 				iop = sfswap(sfstdout,NIL(Sfio_t*));
582 			}
583 			if(iop && sffileno(iop)==1)
584 			{
585 				int fd=sfsetfd(iop,3);
586 				if(fd<0)
587 					errormsg(SH_DICT,ERROR_system(1),e_toomany);
588 				shp->sftable[fd] = iop;
589 				fcntl(fd,F_SETFD,FD_CLOEXEC);
590 				shp->fdstatus[fd] = (shp->fdstatus[1]|IOCLEX);
591 				shp->fdstatus[1] = IOCLOSE;
592 			}
593 			sfset(iop,SF_READ,1);
594 		}
595 		sfswap(sp->saveout,sfstdout);
596 		/*  check if standard output was preserved */
597 		if(sp->tmpfd>=0)
598 		{
599 			close(1);
600 			fcntl(sp->tmpfd,F_DUPFD,1);
601 			sh_close(sp->tmpfd);
602 		}
603 		shp->fdstatus[1] = sp->fdstatus;
604 	}
605 	if(sp->subpid)
606 	{
607 		if(shp->exitval > SH_EXITSIG)
608 			sp->sig = (shp->exitval&SH_EXITMASK);
609 		shp->exitval = 0;
610 		if(comsub)
611 			shp->spid = sp->subpid;
612 		else
613 			job_wait(sp->subpid);
614 	}
615 	if(comsub && iop && sp->pipefd<0)
616 		sfseek(iop,(off_t)0,SEEK_SET);
617 	path_delete((Pathcomp_t*)shp->pathlist);
618 	shp->pathlist = (void*)sp->pathlist;
619 	job_subrestore(sp->jobs);
620 	shp->jobenv = savecurenv;
621 	job.curpgid = savejobpgid;
622 	shp->bckpid = sp->bckpid;
623 	if(sp->shpwd)	/* restore environment if saved */
624 	{
625 		int n;
626 		shp->options = sp->options;
627 		nv_restore(sp);
628 		if(sp->salias)
629 		{
630 			shp->alias_tree = dtview(sp->salias,0);
631 			table_unset(sp->salias,0);
632 			dtclose(sp->salias);
633 		}
634 		if(sp->sfun)
635 		{
636 			shp->fun_tree = dtview(sp->sfun,0);
637 			table_unset(sp->sfun,1);
638 			dtclose(sp->sfun);
639 		}
640 		n = shp->st.trapmax-savst.trapmax;
641 		sh_sigreset(1);
642 		if(n>0)
643 			memset(&shp->st.trapcom[savst.trapmax],0,n*sizeof(char*));
644 		shp->st = savst;
645 		shp->curenv = savecurenv;
646 		if(nsig)
647 		{
648 			memcpy((char*)&shp->st.trapcom[0],savsig,nsig);
649 			free((void*)savsig);
650 		}
651 		shp->options = sp->options;
652 		if(!shp->pwd || strcmp(sp->pwd,shp->pwd))
653 		{
654 			/* restore PWDNOD */
655 			Namval_t *pwdnod = sh_scoped(shp,PWDNOD);
656 			if(shp->pwd)
657 			{
658 				chdir(shp->pwd=sp->pwd);
659 				path_newdir(shp->pathlist);
660 			}
661 			if(nv_isattr(pwdnod,NV_NOFREE))
662 				pwdnod->nvalue.cp = (const char*)sp->pwd;
663 		}
664 		else if(sp->shpwd != shp->pwd)
665 		{
666 			shp->pwd = sp->pwd;
667 			if(PWDNOD->nvalue.cp==sp->shpwd)
668 				PWDNOD->nvalue.cp = sp->pwd;
669 		}
670 		else
671 			free((void*)sp->pwd);
672 		if(sp->mask!=shp->mask)
673 			umask(shp->mask=sp->mask);
674 		if(shp->coutpipe>=0)
675 		{
676 			sh_close(shp->coutpipe);
677 			sh_close(shp->cpipe[1]);
678 		}
679 		shp->cpid = sp->cpid;
680 		shp->cpipe[1] = sp->cpipe;
681 		shp->coutpipe = sp->coutpipe;
682 	}
683 	shp->subshare = sp->subshare;
684 	if(shp->subshell)
685 		SH_SUBSHELLNOD->nvalue.s = --shp->subshell;
686 	if(sp->sig)
687 	{
688 		if(sp->prev)
689 			sp->prev->sig = sp->sig;
690 		else
691 		{
692 			sh_fault(sp->sig);
693 			sh_chktrap();
694 		}
695 	}
696 	subshell = shp->subshell;
697 	subshell_data = sp->prev;
698 	sh_argfree(shp,argsav,0);
699 	shp->trapnote = 0;
700 	if(shp->topfd != buff.topfd)
701 		sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval);
702 	if(shp->exitval > SH_EXITSIG)
703 	{
704 		int sig = shp->exitval&SH_EXITMASK;
705 		if(sig==SIGINT || sig== SIGQUIT)
706 			sh_fault(sig);
707 	}
708 	return(iop);
709 }
710