xref: /titanic_41/usr/src/lib/libshell/common/sh/subshell.c (revision d2b5b2d357ee3172eacb6860be1891259902203d)
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  */
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 	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  */
187 void 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 
226 int 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  */
246 Namval_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  */
322 static 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  */
383 Dt_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  */
401 Dt_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 
415 static 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 
434 int 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 
446 void 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 
469 Sfio_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