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