Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/subshell.c
1810 views
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 <[email protected]> *
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
shp->fdstatus[fd] = shp->fdstatus[1]|IOCLEX;
129
close(1);
130
}
131
else if(errno!=EBADF)
132
errormsg(SH_DICT,ERROR_system(1),e_toomany);
133
/* popping a discipline forces a /tmp file create */
134
sfdisc(sfstdout,SF_POPDISC);
135
if((fd=sffileno(sfstdout))<0)
136
{
137
/* unable to create the /tmp file so use a pipe */
138
int fds[3];
139
Sfoff_t off;
140
fds[2] = 0;
141
sh_pipe(fds);
142
sp->pipefd = fds[0];
143
sh_fcntl(sp->pipefd,F_SETFD,FD_CLOEXEC);
144
/* write the data to the pipe */
145
if(off = sftell(sfstdout))
146
write(fds[1],sfsetbuf(sfstdout,(Void_t*)sfstdout,0),(size_t)off);
147
sfclose(sfstdout);
148
if((sh_fcntl(fds[1],F_DUPFD, 1)) != 1)
149
errormsg(SH_DICT,ERROR_system(1),e_file+4);
150
sh_close(fds[1]);
151
}
152
else
153
{
154
shp->fdstatus[fd] = IOREAD|IOWRITE;
155
sfsync(sfstdout);
156
if(fd==1)
157
fcntl(1,F_SETFD,0);
158
else
159
{
160
sfsetfd(sfstdout,1);
161
shp->fdstatus[1] = shp->fdstatus[fd];
162
shp->fdstatus[fd] = IOCLOSE;
163
}
164
}
165
sh_iostream(shp,1);
166
sfset(sfstdout,SF_SHARE|SF_PUBLIC,1);
167
sfpool(sfstdout,shp->outpool,SF_WRITE);
168
if(pp && pp->olist && pp->olist->strm == sfstdout)
169
pp->olist->strm = 0;
170
}
171
}
172
173
174
/*
175
* This routine creates a temp file if necessary and creates a subshell.
176
* The parent routine longjmps back to sh_subshell()
177
* The child continues possibly with its standard output replaced by temp file
178
*/
179
void sh_subfork(void)
180
{
181
register struct subshell *sp = subshell_data;
182
Shell_t *shp = sp->shp;
183
int curenv = shp->curenv;
184
pid_t pid;
185
char *trap = shp->st.trapcom[0];
186
if(trap)
187
trap = strdup(trap);
188
/* see whether inside $(...) */
189
if(sp->pipe)
190
sh_subtmpfile(shp);
191
shp->curenv = 0;
192
shp->savesig = -1;
193
if(pid = sh_fork(shp,FSHOWME,NIL(int*)))
194
{
195
shp->curenv = curenv;
196
/* this is the parent part of the fork */
197
if(sp->subpid==0)
198
sp->subpid = pid;
199
if(trap)
200
free((void*)trap);
201
siglongjmp(*shp->jmplist,SH_JMPSUB);
202
}
203
else
204
{
205
/* this is the child part of the fork */
206
/* setting subpid to 1 causes subshell to exit when reached */
207
sh_onstate(SH_FORKED);
208
sh_onstate(SH_NOLOG);
209
sh_offoption(SH_MONITOR);
210
sh_offstate(SH_MONITOR);
211
subshell_data = 0;
212
shp->subshell = 0;
213
shp->comsub = 0;
214
SH_SUBSHELLNOD->nvalue.s = 0;
215
sp->subpid=0;
216
shp->st.trapcom[0] = trap;
217
shp->savesig = 0;
218
}
219
}
220
221
int nv_subsaved(register Namval_t *np)
222
{
223
register struct subshell *sp;
224
register struct Link *lp;
225
for(sp = (struct subshell*)subshell_data; sp; sp=sp->prev)
226
{
227
for(lp=sp->svar; lp; lp = lp->next)
228
{
229
if(lp->node==np)
230
return(1);
231
}
232
}
233
return(0);
234
}
235
236
/*
237
* This routine will make a copy of the given node in the
238
* layer created by the most recent subshell_fork if the
239
* node hasn't already been copied
240
*/
241
Namval_t *sh_assignok(register Namval_t *np,int add)
242
{
243
register Namval_t *mp;
244
register struct Link *lp;
245
register struct subshell *sp = (struct subshell*)subshell_data;
246
Shell_t *shp = sp->shp;
247
Dt_t *dp= shp->var_tree;
248
Namval_t *mpnext;
249
Namarr_t *ap;
250
int save;
251
/* don't bother with this */
252
if(!sp->shpwd || np==SH_LEVELNOD || np==L_ARGNOD || np==SH_SUBSCRNOD || np==SH_NAMENOD)
253
return(np);
254
/* don't bother to save if in newer scope */
255
if(sp->var!=shp->var_tree && sp->var!=shp->var_base && shp->last_root==shp->var_tree)
256
return(np);
257
if((ap=nv_arrayptr(np)) && (mp=nv_opensub(np)))
258
{
259
shp->last_root = ap->table;
260
sh_assignok(mp,add);
261
if(!add || array_assoc(ap))
262
return(np);
263
}
264
for(lp=sp->svar; lp;lp = lp->next)
265
{
266
if(lp->node==np)
267
return(np);
268
}
269
/* first two pointers use linkage from np */
270
lp = (struct Link*)malloc(sizeof(*np)+2*sizeof(void*));
271
memset(lp,0, sizeof(*mp)+2*sizeof(void*));
272
lp->node = np;
273
if(!add && nv_isvtree(np))
274
{
275
Namval_t fake;
276
Dt_t *walk, *root=shp->var_tree;
277
char *name = nv_name(np);
278
size_t len = strlen(name);
279
fake.nvname = name;
280
mpnext = dtnext(root,&fake);
281
dp = root->walk?root->walk:root;
282
while(mp=mpnext)
283
{
284
walk = root->walk?root->walk:root;
285
mpnext = dtnext(root,mp);
286
if(memcmp(name,mp->nvname,len) || mp->nvname[len]!='.')
287
break;
288
nv_delete(mp,walk,NV_NOFREE);
289
*((Namval_t**)mp) = lp->child;
290
lp->child = mp;
291
292
}
293
}
294
lp->dict = dp;
295
mp = (Namval_t*)&lp->dict;
296
lp->next = subshell_data->svar;
297
subshell_data->svar = lp;
298
save = shp->subshell;
299
shp->subshell = 0;
300
mp->nvname = np->nvname;
301
if(nv_isattr(np,NV_NOFREE))
302
nv_onattr(mp,NV_IDENT);
303
nv_clone(np,mp,(add?(nv_isnull(np)?0:NV_NOFREE)|NV_ARRAY:NV_MOVE));
304
shp->subshell = save;
305
return(np);
306
}
307
308
/*
309
* restore the variables
310
*/
311
static void nv_restore(struct subshell *sp)
312
{
313
register struct Link *lp, *lq;
314
register Namval_t *mp, *np;
315
const char *save = sp->shpwd;
316
Namval_t *mpnext;
317
int flags,nofree;
318
sp->shpwd = 0; /* make sure sh_assignok doesn't save with nv_unset() */
319
for(lp=sp->svar; lp; lp=lq)
320
{
321
np = (Namval_t*)&lp->dict;
322
lq = lp->next;
323
mp = lp->node;
324
if(!mp->nvname)
325
continue;
326
flags = 0;
327
if(nv_isattr(mp,NV_MINIMAL) && !nv_isattr(np,NV_EXPORT))
328
flags |= NV_MINIMAL;
329
if(nv_isarray(mp))
330
nv_putsub(mp,NIL(char*),ARRAY_SCAN);
331
nofree = mp->nvfun?mp->nvfun->nofree:0;
332
_nv_unset(mp,NV_RDONLY|NV_CLONE);
333
if(nv_isarray(np))
334
{
335
nv_clone(np,mp,NV_MOVE);
336
goto skip;
337
}
338
nv_setsize(mp,nv_size(np));
339
if(!(flags&NV_MINIMAL))
340
mp->nvenv = np->nvenv;
341
if(!nofree)
342
mp->nvfun = np->nvfun;
343
if(nv_isattr(np,NV_IDENT))
344
{
345
nv_offattr(np,NV_IDENT);
346
flags |= NV_NOFREE;
347
}
348
mp->nvflag = np->nvflag|(flags&NV_MINIMAL);
349
if(nv_cover(mp))
350
nv_putval(mp, nv_getval(np),np->nvflag|NV_NOFREE|NV_RDONLY);
351
else
352
mp->nvalue.cp = np->nvalue.cp;
353
if(nofree && np->nvfun && !np->nvfun->nofree)
354
free((char*)np->nvfun);
355
np->nvfun = 0;
356
if(nv_isattr(mp,NV_EXPORT))
357
{
358
char *name = nv_name(mp);
359
sh_envput(sp->shp->env,mp);
360
if(*name=='_' && strcmp(name,"_AST_FEATURES")==0)
361
astconf(NiL, NiL, NiL);
362
}
363
else if(nv_isattr(np,NV_EXPORT))
364
env_delete(sp->shp->env,nv_name(mp));
365
nv_onattr(mp,flags);
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 || sp->shp->curenv==0)
386
return(sh.alias_tree);
387
if(!sp->salias && create)
388
{
389
sp->salias = dtopen(&_Nvdisc,Dtoset);
390
dtview(sp->salias,sp->shp->alias_tree);
391
sp->shp->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 || sp->shp->curenv==0)
404
return(sh.fun_tree);
405
if(!sp->sfun && create)
406
{
407
sp->sfun = dtopen(&_Nvdisc,Dtoset);
408
dtview(sp->sfun,sp->shp->fun_tree);
409
sp->shp->fun_tree = sp->sfun;
410
}
411
return(sp->shp->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(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub)
469
{
470
struct subshell sub_data;
471
register struct subshell *sp = &sub_data;
472
int jmpval,nsig=0,duped=0;
473
int savecurenv = shp->curenv;
474
int savejobpgid = job.curpgid;
475
int *saveexitval = job.exitval;
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
int argcnt;
483
memset((char*)sp, 0, sizeof(*sp));
484
sfsync(shp->outpool);
485
sh_sigcheck(shp);
486
shp->savesig = -1;
487
if(argsav = sh_arguse(shp))
488
argcnt = argsav->dolrefcnt;
489
if(shp->curenv==0)
490
{
491
subshell_data=0;
492
subenv = 0;
493
}
494
shp->curenv = ++subenv;
495
savst = shp->st;
496
sh_pushcontext(shp,&buff,SH_JMPSUB);
497
subshell = shp->subshell+1;
498
SH_SUBSHELLNOD->nvalue.s = subshell;
499
shp->subshell = subshell;
500
sp->prev = subshell_data;
501
sp->shp = shp;
502
sp->sig = 0;
503
subshell_data = sp;
504
sp->errcontext = &buff.err;
505
sp->var = shp->var_tree;
506
sp->options = shp->options;
507
sp->jobs = job_subsave();
508
sp->subdup = shp->subdup;
509
#if SHOPT_COSHELL
510
sp->coshell = shp->coshell;
511
shp->coshell = 0;
512
#endif /* SHOPT_COSHELL */
513
/* make sure initialization has occurred */
514
if(!shp->pathlist)
515
{
516
shp->pathinit = 1;
517
path_get(shp,".");
518
shp->pathinit = 0;
519
}
520
sp->pathlist = path_dup((Pathcomp_t*)shp->pathlist);
521
sp->pwdfd = -1;
522
if(!shp->pwd)
523
path_pwd(shp,0);
524
sp->bckpid = shp->bckpid;
525
if(comsub)
526
sh_stats(STAT_COMSUB);
527
else
528
job.curpgid = 0;
529
sp->subshare = shp->subshare;
530
sp->comsub = shp->comsub;
531
shp->subshare = comsub==2 || (comsub==1 && sh_isoption(SH_SUBSHARE));
532
if(comsub)
533
shp->comsub = comsub;
534
if(!comsub || !shp->subshare)
535
{
536
struct subshell *xp;
537
sp->shpwd = shp->pwd;
538
#ifdef _lib_fchdir
539
for(xp=sp->prev; xp; xp=xp->prev)
540
{
541
if(xp->pwdfd>0 && strcmp(xp->pwd,shp->pwd)==0)
542
{
543
sp->pwdfd = xp->pwdfd;
544
break;
545
}
546
}
547
if(sp->pwdfd<0)
548
{
549
int n = open(".",O_RDONLY);
550
if(O_SEARCH && errno==EACCES)
551
n = open(".",O_RDONLY);
552
if(n>=0)
553
{
554
sp->pwdfd = n;
555
if(n<10)
556
{
557
sp->pwdfd = fcntl(n,F_DUPFD,10);
558
close(n);
559
}
560
if(sp->pwdfd>0)
561
{
562
fcntl(sp->pwdfd,F_SETFD,FD_CLOEXEC);
563
sp->pwdclose = 1;
564
}
565
}
566
}
567
#endif
568
sp->pwd = (shp->pwd?strdup(shp->pwd):0);
569
sp->mask = shp->mask;
570
sh_stats(STAT_SUBSHELL);
571
/* save trap table */
572
shp->st.otrapcom = 0;
573
shp->st.otrap = savst.trap;
574
if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0])
575
{
576
nsig += sizeof(char*);
577
memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig);
578
/* this nonsense needed for $(trap) */
579
shp->st.otrapcom = (char**)savsig;
580
}
581
sp->cpid = shp->cpid;
582
sp->coutpipe = shp->coutpipe;
583
sp->cpipe = shp->cpipe[1];
584
shp->cpid = 0;
585
sh_sigreset(0);
586
}
587
jmpval = sigsetjmp(buff.buff,0);
588
if(jmpval==0)
589
{
590
if(comsub)
591
{
592
/* disable job control */
593
shp->spid = 0;
594
sp->jobcontrol = job.jobcontrol;
595
sp->monitor = (sh_isstate(SH_MONITOR)!=0);
596
job.jobcontrol=0;
597
sh_offstate(SH_MONITOR);
598
sp->pipe = sp;
599
/* save sfstdout and status */
600
sp->saveout = sfswap(sfstdout,NIL(Sfio_t*));
601
sp->fdstatus = shp->fdstatus[1];
602
sp->tmpfd = -1;
603
sp->pipefd = -1;
604
/* use sftmp() file for standard output */
605
if(!(iop = sftmp(PIPE_BUF)))
606
{
607
sfswap(sp->saveout,sfstdout);
608
errormsg(SH_DICT,ERROR_system(1),e_tmpcreate);
609
}
610
sfswap(iop,sfstdout);
611
sfset(sfstdout,SF_READ,0);
612
shp->fdstatus[1] = IOWRITE;
613
if(!(sp->nofork = sh_state(SH_NOFORK)))
614
sh_onstate(SH_NOFORK);
615
flags |= sh_state(SH_NOFORK);
616
}
617
else if(sp->prev)
618
{
619
sp->pipe = sp->prev->pipe;
620
flags &= ~sh_state(SH_NOFORK);
621
}
622
if(shp->savesig < 0)
623
{
624
shp->savesig = 0;
625
sh_exec(t,flags);
626
}
627
}
628
if(comsub!=2 && jmpval!=SH_JMPSUB && shp->st.trapcom[0] && shp->subshell)
629
{
630
/* trap on EXIT not handled by child */
631
char *trap=shp->st.trapcom[0];
632
shp->st.trapcom[0] = 0; /* prevent recursion */
633
shp->oldexit = shp->exitval;
634
sh_trap(trap,0);
635
free(trap);
636
}
637
sh_popcontext(shp,&buff);
638
if(shp->subshell==0) /* must be child process */
639
{
640
subshell_data = sp->prev;
641
if(jmpval==SH_JMPSCRIPT)
642
siglongjmp(*shp->jmplist,jmpval);
643
shp->exitval &= SH_EXITMASK;
644
sh_done(shp,0);
645
}
646
if(!shp->savesig)
647
shp->savesig = -1;
648
nv_restore(sp);
649
if(comsub)
650
{
651
/* re-enable job control */
652
if(!sp->nofork)
653
sh_offstate(SH_NOFORK);
654
job.jobcontrol = sp->jobcontrol;
655
if(sp->monitor)
656
sh_onstate(SH_MONITOR);
657
if(sp->pipefd>=0)
658
{
659
/* sftmp() file has been returned into pipe */
660
iop = sh_iostream(shp,sp->pipefd);
661
sfclose(sfstdout);
662
}
663
else
664
{
665
/* move tmp file to iop and restore sfstdout */
666
iop = sfswap(sfstdout,NIL(Sfio_t*));
667
if(!iop)
668
{
669
/* maybe locked try again */
670
sfclrlock(sfstdout);
671
iop = sfswap(sfstdout,NIL(Sfio_t*));
672
}
673
if(iop && sffileno(iop)==1)
674
{
675
int fd=sfsetfd(iop,3);
676
if(fd<0)
677
{
678
shp->toomany = 1;
679
((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
680
errormsg(SH_DICT,ERROR_system(1),e_toomany);
681
}
682
if(fd >= shp->gd->lim.open_max)
683
sh_iovalidfd(shp,fd);
684
shp->sftable[fd] = iop;
685
fcntl(fd,F_SETFD,FD_CLOEXEC);
686
shp->fdstatus[fd] = (shp->fdstatus[1]|IOCLEX);
687
shp->fdstatus[1] = IOCLOSE;
688
}
689
sfset(iop,SF_READ,1);
690
}
691
sfswap(sp->saveout,sfstdout);
692
/* check if standard output was preserved */
693
if(sp->tmpfd>=0)
694
{
695
close(1);
696
if (fcntl(sp->tmpfd,F_DUPFD,1) != 1)
697
duped++;
698
sh_close(sp->tmpfd);
699
}
700
shp->fdstatus[1] = sp->fdstatus;
701
}
702
path_delete((Pathcomp_t*)shp->pathlist);
703
shp->pathlist = (void*)sp->pathlist;
704
job_subrestore(sp->jobs);
705
shp->jobenv = savecurenv;
706
job.curpgid = savejobpgid;
707
job.exitval = saveexitval;
708
shp->bckpid = sp->bckpid;
709
if(sp->shpwd) /* restore environment if saved */
710
{
711
int n;
712
shp->options = sp->options;
713
if(sp->salias)
714
{
715
shp->alias_tree = dtview(sp->salias,0);
716
table_unset(sp->salias,0);
717
dtclose(sp->salias);
718
}
719
if(sp->sfun)
720
{
721
shp->fun_tree = dtview(sp->sfun,0);
722
table_unset(sp->sfun,1);
723
dtclose(sp->sfun);
724
}
725
n = shp->st.trapmax-savst.trapmax;
726
sh_sigreset(1);
727
if(n>0)
728
memset(&shp->st.trapcom[savst.trapmax],0,n*sizeof(char*));
729
shp->st = savst;
730
shp->curenv = savecurenv;
731
shp->st.otrap = 0;
732
if(nsig)
733
{
734
memcpy((char*)&shp->st.trapcom[0],savsig,nsig);
735
free((void*)savsig);
736
}
737
shp->options = sp->options;
738
if(!shp->pwd || strcmp(sp->pwd,shp->pwd))
739
{
740
/* restore PWDNOD */
741
Namval_t *pwdnod = sh_scoped(shp,PWDNOD);
742
if(shp->pwd)
743
{
744
if(sp->pwdfd >=0)
745
{
746
if(fchdir(sp->pwdfd)<0)
747
chdir(sp->pwd);
748
}
749
else
750
chdir(sp->pwd);
751
shp->pwd=sp->pwd;
752
path_newdir(shp,shp->pathlist);
753
}
754
if(nv_isattr(pwdnod,NV_NOFREE))
755
pwdnod->nvalue.cp = (const char*)sp->pwd;
756
}
757
else if(sp->shpwd != shp->pwd)
758
{
759
shp->pwd = sp->pwd;
760
if(PWDNOD->nvalue.cp==sp->shpwd)
761
PWDNOD->nvalue.cp = sp->pwd;
762
}
763
else
764
free((void*)sp->pwd);
765
if(sp->pwdclose)
766
close(sp->pwdfd);
767
if(sp->mask!=shp->mask)
768
umask(shp->mask=sp->mask);
769
if(shp->coutpipe!=sp->coutpipe)
770
{
771
sh_close(shp->coutpipe);
772
sh_close(shp->cpipe[1]);
773
}
774
shp->cpid = sp->cpid;
775
shp->cpipe[1] = sp->cpipe;
776
shp->coutpipe = sp->coutpipe;
777
}
778
shp->subshare = sp->subshare;
779
shp->comsub = sp->comsub;
780
shp->subdup = sp->subdup;
781
#if SHOPT_COSHELL
782
shp->coshell = sp->coshell;
783
#endif /* SHOPT_COSHELL */
784
if(shp->subshell)
785
SH_SUBSHELLNOD->nvalue.s = --shp->subshell;
786
subshell = shp->subshell;
787
subshell_data = sp->prev;
788
if(!argsav || argsav->dolrefcnt==argcnt)
789
sh_argfree(shp,argsav,0);
790
if(shp->topfd != buff.topfd)
791
sh_iorestore(shp,buff.topfd|IOSUBSHELL,jmpval);
792
if(sp->sig)
793
{
794
if(sp->prev)
795
sp->prev->sig = sp->sig;
796
else
797
{
798
kill(getpid(),sp->sig);
799
sh_chktrap(shp);
800
}
801
}
802
sh_sigcheck(shp);
803
shp->trapnote = 0;
804
nsig = shp->savesig;
805
shp->savesig = 0;
806
if(nsig>0)
807
kill(getpid(),nsig);
808
if(sp->subpid)
809
job_wait(sp->subpid);
810
if(comsub && iop && sp->pipefd<0)
811
sfseek(iop,(off_t)0,SEEK_SET);
812
if(shp->trapnote)
813
sh_chktrap(shp);
814
if(shp->exitval > SH_EXITSIG)
815
{
816
int sig = shp->exitval&SH_EXITMASK;
817
if(sig==SIGINT || sig== SIGQUIT)
818
kill(getpid(),sig);
819
}
820
if(duped)
821
{
822
((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
823
shp->toomany = 1;
824
errormsg(SH_DICT,ERROR_system(1),e_redirect);
825
}
826
if(shp->ignsig)
827
kill(getpid(),shp->ignsig);
828
if(jmpval==SH_JMPSUB && shp->lastsig)
829
kill(getpid(),shp->lastsig);
830
if(jmpval && shp->toomany)
831
siglongjmp(*shp->jmplist,jmpval);
832
return(iop);
833
}
834
835