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