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