xref: /titanic_44/usr/src/lib/libshell/common/sh/subshell.c (revision de6732348404877079e00a1631babd13d8a5ad14)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2009 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_offstate(SH_MONITOR);
217 		subshell_data = 0;
218 		shp->subshell = 0;
219 		SH_SUBSHELLNOD->nvalue.s = 0;
220 		sp->subpid=0;
221 		shp->st.trapcom[0] = trap;
222 	}
223 }
224 
225 int nv_subsaved(register Namval_t *np)
226 {
227 	register struct subshell	*sp;
228 	register struct Link		*lp;
229 	for(sp = (struct subshell*)subshell_data; sp; sp=sp->prev)
230 	{
231 		for(lp=sp->svar; lp; lp = lp->next)
232 		{
233 			if(lp->node==np)
234 				return(1);
235 		}
236 	}
237 	return(0);
238 }
239 
240 /*
241  * This routine will make a copy of the given node in the
242  * layer created by the most recent subshell_fork if the
243  * node hasn't already been copied
244  */
245 Namval_t *sh_assignok(register Namval_t *np,int add)
246 {
247 	register Namval_t	*mp;
248 	register struct Link	*lp;
249 	register struct subshell *sp = (struct subshell*)subshell_data;
250 	struct Ufunction	*rp;
251 	Shell_t			*shp = sp->shp;
252 	Dt_t			*dp;
253 	Namval_t		*mpnext;
254 	Namarr_t		*ap;
255 	int			save;
256 	/* don't bother with this */
257 	if(!sp->shpwd || (nv_isnull(np) && !add) || np==SH_LEVELNOD)
258 		return(np);
259 	/* don't bother to save if in newer scope */
260 	if(!(rp=shp->st.real_fun)  || !(dp=rp->sdict))
261 		dp = sp->var;
262 	if(np->nvenv && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && shp->last_root)
263 		dp = shp->last_root;
264 	if((mp=nv_search((char*)np,dp,HASH_BUCKET))!=np)
265 	{
266 		if(mp || !np->nvfun || np->nvfun->subshell>=sh.subshell)
267 			return(np);
268 	}
269 	if((ap=nv_arrayptr(np)) && (mp=nv_opensub(np)))
270 	{
271 		shp->last_root = ap->table;
272 		sh_assignok(mp,add);
273 		if(!add || array_assoc(ap))
274 			return(np);
275 	}
276 	for(lp=subshell_data->svar; lp; lp = lp->next)
277 	{
278 		if(lp->node==np)
279 			return(np);
280 	}
281 	/* first two pointers use linkage from np */
282 	lp = (struct Link*)malloc(sizeof(*np)+2*sizeof(void*));
283 	memset(lp,0, sizeof(*mp)+2*sizeof(void*));
284 	lp->node = np;
285 	if(!add &&  nv_isvtree(np))
286 	{
287 		Namval_t	fake;
288 		Dt_t		*walk, *root=shp->var_tree;
289 		char		*name = nv_name(np);
290 		int		len = strlen(name);
291 		fake.nvname = name;
292 		mpnext = dtnext(root,&fake);
293 		dp = root->walk?root->walk:root;
294 		while(mp=mpnext)
295 		{
296 			walk = root->walk?root->walk:root;
297 			mpnext = dtnext(root,mp);
298 			if(memcmp(name,mp->nvname,len) || mp->nvname[len]!='.')
299 				break;
300 			nv_delete(mp,walk,NV_NOFREE);
301 			*((Namval_t**)mp) = lp->child;
302 			lp->child = mp;
303 
304 		}
305 	}
306 	lp->dict = dp;
307 	mp = (Namval_t*)&lp->dict;
308 	lp->next = subshell_data->svar;
309 	subshell_data->svar = lp;
310 	save = shp->subshell;
311 	shp->subshell = 0;
312 	mp->nvname = np->nvname;
313 	nv_clone(np,mp,(add?(nv_isnull(np)?0:NV_NOFREE)|NV_ARRAY:NV_MOVE));
314 	shp->subshell = save;
315 	return(np);
316 }
317 
318 /*
319  * restore the variables
320  */
321 static void nv_restore(struct subshell *sp)
322 {
323 	register struct Link *lp, *lq;
324 	register Namval_t *mp, *np;
325 	const char *save = sp->shpwd;
326 	Namval_t	*mpnext;
327 	sp->shpwd = 0;	/* make sure sh_assignok doesn't save with nv_unset() */
328 	for(lp=sp->svar; lp; lp=lq)
329 	{
330 		np = (Namval_t*)&lp->dict;
331 		lq = lp->next;
332 		mp = lp->node;
333 		if(!mp->nvname)
334 			continue;
335 		if(nv_isarray(mp))
336 			 nv_putsub(mp,NIL(char*),ARRAY_SCAN);
337 		_nv_unset(mp,NV_RDONLY|NV_CLONE);
338 		if(nv_isarray(np))
339 		{
340 			nv_clone(np,mp,NV_MOVE);
341 			goto skip;
342 		}
343 		nv_setsize(mp,nv_size(np));
344 		if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT))
345 			mp->nvenv = np->nvenv;
346 		mp->nvfun = np->nvfun;
347 		mp->nvflag = np->nvflag;
348 		if(nv_cover(mp))
349 		{
350 			nv_putval(mp, nv_getval(np),np->nvflag|NV_NOFREE);
351 			if(!nv_isattr(np,NV_NOFREE))
352 				nv_offattr(mp,NV_NOFREE);
353 		}
354 		else
355 			mp->nvalue.cp = np->nvalue.cp;
356 		np->nvfun = 0;
357 		if(nv_isattr(mp,NV_EXPORT))
358 		{
359 			char *name = nv_name(mp);
360 			sh_envput(sh.env,mp);
361 			if(*name=='_' && strcmp(name,"_AST_FEATURES")==0)
362 				astconf(NiL, NiL, NiL);
363 		}
364 		else if(nv_isattr(np,NV_EXPORT))
365 			env_delete(sh.env,nv_name(mp));
366 	skip:
367 		for(mp=lp->child; mp; mp=mpnext)
368 		{
369 			mpnext = *((Namval_t**)mp);
370 			dtinsert(lp->dict,mp);
371 		}
372 		free((void*)lp);
373 		sp->svar = lq;
374 	}
375 	sp->shpwd=save;
376 }
377 
378 /*
379  * return pointer to alias tree
380  * create new one if in a subshell and one doesn't exist and create is non-zero
381  */
382 Dt_t *sh_subaliastree(int create)
383 {
384 	register struct subshell *sp = subshell_data;
385 	if(!sp || sh.curenv==0)
386 		return(sh.alias_tree);
387 	if(!sp->salias && create)
388 	{
389 		sp->salias = dtopen(&_Nvdisc,Dtoset);
390 		dtview(sp->salias,sh.alias_tree);
391 		sh.alias_tree = sp->salias;
392 	}
393 	return(sp->salias);
394 }
395 
396 /*
397  * return pointer to function tree
398  * create new one if in a subshell and one doesn't exist and create is non-zero
399  */
400 Dt_t *sh_subfuntree(int create)
401 {
402 	register struct subshell *sp = subshell_data;
403 	if(!sp || sh.curenv==0)
404 		return(sh.fun_tree);
405 	if(!sp->sfun && create)
406 	{
407 		sp->sfun = dtopen(&_Nvdisc,Dtoset);
408 		dtview(sp->sfun,sh.fun_tree);
409 		sh.fun_tree = sp->sfun;
410 	}
411 	return(sh.fun_tree);
412 }
413 
414 static void table_unset(register Dt_t *root,int fun)
415 {
416 	register Namval_t *np,*nq;
417 	int flag;
418 	for(np=(Namval_t*)dtfirst(root);np;np=nq)
419 	{
420 		nq = (Namval_t*)dtnext(root,np);
421 		flag=0;
422 		if(fun && np->nvalue.rp && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/')
423 		{
424 			np->nvalue.rp->fdict = 0;
425 			flag = NV_NOFREE;
426 		}
427 		else
428 			_nv_unset(np,NV_RDONLY);
429 		nv_delete(np,root,flag|NV_FUNCTION);
430 	}
431 }
432 
433 int sh_subsavefd(register int fd)
434 {
435 	register struct subshell *sp = subshell_data;
436 	register int old=0;
437 	if(sp)
438 	{
439 		old = !(sp->fdsaved&(1<<(fd-1)));
440 		sp->fdsaved |= (1<<(fd-1));
441 	}
442 	return(old);
443 }
444 
445 void sh_subjobcheck(pid_t pid)
446 {
447 	register struct subshell *sp = subshell_data;
448 	while(sp)
449 	{
450 		if(sp->cpid==pid)
451 		{
452 			sh_close(sp->coutpipe);
453 			sh_close(sp->cpipe);
454 			sp->coutpipe = sp->cpipe = -1;
455 			return;
456 		}
457 		sp = sp->prev;
458 	}
459 }
460 
461 /*
462  * Run command tree <t> in a virtual sub-shell
463  * If comsub is not null, then output will be placed in temp file (or buffer)
464  * If comsub is not null, the return value will be a stream consisting of
465  * output of command <t>.  Otherwise, NULL will be returned.
466  */
467 
468 Sfio_t *sh_subshell(Shnode_t *t, int flags, int comsub)
469 {
470 	Shell_t *shp = &sh;
471 	struct subshell sub_data;
472 	register struct subshell *sp = &sub_data;
473 	int jmpval,nsig=0,duped=0;
474 	int savecurenv = shp->curenv;
475 	int savejobpgid = job.curpgid;
476 	int16_t subshell;
477 	char *savsig;
478 	Sfio_t *iop=0;
479 	struct checkpt buff;
480 	struct sh_scoped savst;
481 	struct dolnod   *argsav=0;
482 	memset((char*)sp, 0, sizeof(*sp));
483 	sfsync(shp->outpool);
484 	argsav = sh_arguse(shp);
485 	if(shp->curenv==0)
486 	{
487 		subshell_data=0;
488 		subenv = 0;
489 	}
490 	shp->curenv = ++subenv;
491 	job.curpgid = 0;
492 	savst = shp->st;
493 	sh_pushcontext(&buff,SH_JMPSUB);
494 	subshell = shp->subshell+1;
495 	SH_SUBSHELLNOD->nvalue.s = subshell;
496 	shp->subshell = subshell;
497 	sp->prev = subshell_data;
498 	sp->shp = shp;
499 	sp->sig = 0;
500 	subshell_data = sp;
501 	sp->errcontext = &buff.err;
502 	sp->var = shp->var_tree;
503 	sp->options = shp->options;
504 	sp->jobs = job_subsave();
505 	/* make sure initialization has occurred */
506 	if(!shp->pathlist)
507 		path_get(".");
508 	sp->pathlist = path_dup((Pathcomp_t*)shp->pathlist);
509 	if(!shp->pwd)
510 		path_pwd(0);
511 	sp->bckpid = shp->bckpid;
512 	if(comsub)
513 		sh_stats(STAT_COMSUB);
514 	sp->subshare = shp->subshare;
515 	shp->subshare = comsub==2 ||  (comsub==1 && sh_isoption(SH_SUBSHARE));
516 	if(!comsub || !shp->subshare)
517 	{
518 		sp->shpwd = shp->pwd;
519 		sp->pwd = (shp->pwd?strdup(shp->pwd):0);
520 		sp->mask = shp->mask;
521 		sh_stats(STAT_SUBSHELL);
522 		/* save trap table */
523 		shp->st.otrapcom = 0;
524 		if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0])
525 		{
526 			nsig += sizeof(char*);
527 			memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig);
528 			/* this nonsense needed for $(trap) */
529 			shp->st.otrapcom = (char**)savsig;
530 		}
531 		sp->cpid = shp->cpid;
532 		sp->coutpipe = shp->coutpipe;
533 		sp->cpipe = shp->cpipe[1];
534 		shp->cpid = 0;
535 		sh_sigreset(0);
536 	}
537 	jmpval = sigsetjmp(buff.buff,0);
538 	if(jmpval==0)
539 	{
540 		if(comsub)
541 		{
542 			/* disable job control */
543 			shp->spid = 0;
544 			sp->jobcontrol = job.jobcontrol;
545 			sp->monitor = (sh_isstate(SH_MONITOR)!=0);
546 			job.jobcontrol=0;
547 			sh_offstate(SH_MONITOR);
548 			sp->pipe = sp;
549 			/* save sfstdout and status */
550 			sp->saveout = sfswap(sfstdout,NIL(Sfio_t*));
551 			sp->fdstatus = shp->fdstatus[1];
552 			sp->tmpfd = -1;
553 			sp->pipefd = -1;
554 			/* use sftmp() file for standard output */
555 			if(!(iop = sftmp(PIPE_BUF)))
556 			{
557 				sfswap(sp->saveout,sfstdout);
558 				errormsg(SH_DICT,ERROR_system(1),e_tmpcreate);
559 			}
560 			sfswap(iop,sfstdout);
561 			sfset(sfstdout,SF_READ,0);
562 			shp->fdstatus[1] = IOWRITE;
563 			if(!(sp->nofork = sh_state(SH_NOFORK)))
564 				sh_onstate(SH_NOFORK);
565 			flags |= sh_state(SH_NOFORK);
566 		}
567 		else if(sp->prev)
568 		{
569 			sp->pipe = sp->prev->pipe;
570 			flags &= ~sh_state(SH_NOFORK);
571 		}
572 		sh_exec(t,flags);
573 	}
574 	if(comsub!=2 && jmpval!=SH_JMPSUB && shp->st.trapcom[0] && shp->subshell)
575 	{
576 		/* trap on EXIT not handled by child */
577 		char *trap=shp->st.trapcom[0];
578 		shp->st.trapcom[0] = 0;	/* prevent recursion */
579 		shp->oldexit = shp->exitval;
580 		sh_trap(trap,0);
581 		free(trap);
582 	}
583 	sh_popcontext(&buff);
584 	if(shp->subshell==0)	/* must be child process */
585 	{
586 		subshell_data = sp->prev;
587 		if(jmpval==SH_JMPSCRIPT)
588 			siglongjmp(*shp->jmplist,jmpval);
589 		shp->exitval &= SH_EXITMASK;
590 		sh_done(shp,0);
591 	}
592 	if(comsub)
593 	{
594 		/* re-enable job control */
595 		if(!sp->nofork)
596 			sh_offstate(SH_NOFORK);
597 		job.jobcontrol = sp->jobcontrol;
598 		if(sp->monitor)
599 			sh_onstate(SH_MONITOR);
600 		if(sp->pipefd>=0)
601 		{
602 			/* sftmp() file has been returned into pipe */
603 			iop = sh_iostream(shp,sp->pipefd);
604 			sfclose(sfstdout);
605 		}
606 		else
607 		{
608 			/* move tmp file to iop and restore sfstdout */
609 			iop = sfswap(sfstdout,NIL(Sfio_t*));
610 			if(!iop)
611 			{
612 				/* maybe locked try again */
613 				sfclrlock(sfstdout);
614 				iop = sfswap(sfstdout,NIL(Sfio_t*));
615 			}
616 			if(iop && sffileno(iop)==1)
617 			{
618 				int fd=sfsetfd(iop,3);
619 				if(fd<0)
620 				{
621 					shp->toomany = 1;
622 					((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
623 					errormsg(SH_DICT,ERROR_system(1),e_toomany);
624 				}
625 				shp->sftable[fd] = iop;
626 				fcntl(fd,F_SETFD,FD_CLOEXEC);
627 				shp->fdstatus[fd] = (shp->fdstatus[1]|IOCLEX);
628 				shp->fdstatus[1] = IOCLOSE;
629 			}
630 			sfset(iop,SF_READ,1);
631 		}
632 		sfswap(sp->saveout,sfstdout);
633 		/*  check if standard output was preserved */
634 		if(sp->tmpfd>=0)
635 		{
636 			close(1);
637 			if (fcntl(sp->tmpfd,F_DUPFD,1) != 1)
638 				duped++;
639 			sh_close(sp->tmpfd);
640 		}
641 		shp->fdstatus[1] = sp->fdstatus;
642 	}
643 	if(sp->subpid)
644 	{
645 		if(shp->exitval > SH_EXITSIG)
646 			sp->sig = (shp->exitval&SH_EXITMASK);
647 		shp->exitval = 0;
648 		if(comsub)
649 			shp->spid = sp->subpid;
650 	}
651 	if(comsub && iop && sp->pipefd<0)
652 		sfseek(iop,(off_t)0,SEEK_SET);
653 	path_delete((Pathcomp_t*)shp->pathlist);
654 	shp->pathlist = (void*)sp->pathlist;
655 	job_subrestore(sp->jobs);
656 	shp->jobenv = savecurenv;
657 	job.curpgid = savejobpgid;
658 	shp->bckpid = sp->bckpid;
659 	if(sp->shpwd)	/* restore environment if saved */
660 	{
661 		int n;
662 		shp->options = sp->options;
663 		nv_restore(sp);
664 		if(sp->salias)
665 		{
666 			shp->alias_tree = dtview(sp->salias,0);
667 			table_unset(sp->salias,0);
668 			dtclose(sp->salias);
669 		}
670 		if(sp->sfun)
671 		{
672 			shp->fun_tree = dtview(sp->sfun,0);
673 			table_unset(sp->sfun,1);
674 			dtclose(sp->sfun);
675 		}
676 		n = shp->st.trapmax-savst.trapmax;
677 		sh_sigreset(1);
678 		if(n>0)
679 			memset(&shp->st.trapcom[savst.trapmax],0,n*sizeof(char*));
680 		shp->st = savst;
681 		shp->curenv = savecurenv;
682 		if(nsig)
683 		{
684 			memcpy((char*)&shp->st.trapcom[0],savsig,nsig);
685 			free((void*)savsig);
686 		}
687 		shp->options = sp->options;
688 		if(!shp->pwd || strcmp(sp->pwd,shp->pwd))
689 		{
690 			/* restore PWDNOD */
691 			Namval_t *pwdnod = sh_scoped(shp,PWDNOD);
692 			if(shp->pwd)
693 			{
694 				chdir(shp->pwd=sp->pwd);
695 				path_newdir(shp->pathlist);
696 			}
697 			if(nv_isattr(pwdnod,NV_NOFREE))
698 				pwdnod->nvalue.cp = (const char*)sp->pwd;
699 		}
700 		else if(sp->shpwd != shp->pwd)
701 		{
702 			shp->pwd = sp->pwd;
703 			if(PWDNOD->nvalue.cp==sp->shpwd)
704 				PWDNOD->nvalue.cp = sp->pwd;
705 		}
706 		else
707 			free((void*)sp->pwd);
708 		if(sp->mask!=shp->mask)
709 			umask(shp->mask=sp->mask);
710 		if(shp->coutpipe!=sp->coutpipe)
711 		{
712 			sh_close(shp->coutpipe);
713 			sh_close(shp->cpipe[1]);
714 		}
715 		shp->cpid = sp->cpid;
716 		shp->cpipe[1] = sp->cpipe;
717 		shp->coutpipe = sp->coutpipe;
718 	}
719 	shp->subshare = sp->subshare;
720 	if(shp->subshell)
721 		SH_SUBSHELLNOD->nvalue.s = --shp->subshell;
722 	subshell = shp->subshell;
723 	subshell_data = sp->prev;
724 	sh_argfree(shp,argsav,0);
725 	if(shp->topfd != buff.topfd)
726 		sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval);
727 	if(sp->sig)
728 	{
729 		if(sp->prev)
730 			sp->prev->sig = sp->sig;
731 		else
732 		{
733 			sh_fault(sp->sig);
734 			sh_chktrap();
735 		}
736 	}
737 	sh_sigcheck();
738 	shp->trapnote = 0;
739 	if(sp->subpid && !comsub)
740 		job_wait(sp->subpid);
741 	if(shp->exitval > SH_EXITSIG)
742 	{
743 		int sig = shp->exitval&SH_EXITMASK;
744 		if(sig==SIGINT || sig== SIGQUIT)
745 			sh_fault(sig);
746 	}
747 	if(duped)
748 	{
749 		((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
750 		shp->toomany = 1;
751 		errormsg(SH_DICT,ERROR_system(1),e_redirect);
752 	}
753 	if(jmpval && shp->toomany)
754 		siglongjmp(*shp->jmplist,jmpval);
755 	return(iop);
756 }
757