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