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