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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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