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 */
sh_subtmpfile(int pflag)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 */
sh_subfork(void)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
nv_subsaved(register Namval_t * np)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 */
sh_assignok(register Namval_t * np,int add)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 */
nv_restore(struct subshell * sp)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 */
sh_subaliastree(int create)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 */
sh_subfuntree(int create)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
table_unset(register Dt_t * root,int fun)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
sh_subsavefd(register int fd)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
sh_subjobcheck(pid_t pid)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
sh_subshell(Shnode_t * t,int flags,int comsub)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