1 /***********************************************************************
2  *                                                                      *
3  *               This software is part of the ast package               *
4  *          Copyright (c) 1982-2014 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 <dgkorn@gmail.com>                     *
18  *                                                                      *
19  ***********************************************************************/
20 //
21 // UNIX shell parse tree executer.
22 //
23 // David Korn
24 // AT&T Labs
25 //
26 #include "config_ast.h"  // IWYU pragma: keep
27 
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <limits.h>
31 #include <math.h>
32 #include <setjmp.h>
33 #include <signal.h>
34 #include <stdbool.h>
35 #include <stddef.h>
36 #include <stdint.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40 #include <sys/times.h>
41 #include <unistd.h>
42 
43 #if _hdr_stdlib
44 #include <stdlib.h>
45 #elif _hdr_malloc
46 #include <malloc.h>
47 #endif
48 
49 #include "argnod.h"
50 #include "ast.h"
51 #include "ast_assert.h"
52 #include "builtins.h"
53 #include "cdt.h"
54 #include "defs.h"
55 #include "error.h"
56 #include "fault.h"
57 #include "fcin.h"
58 #include "history.h"
59 #include "io.h"
60 #include "jobs.h"
61 #include "name.h"
62 #include "option.h"
63 #include "path.h"
64 #include "sfio.h"
65 #include "shcmd.h"
66 #include "shnodes.h"
67 #include "shtable.h"
68 #include "stk.h"
69 #include "streval.h"
70 #include "terminal.h"
71 #include "test.h"
72 #include "variables.h"
73 
74 #if USE_SPAWN
75 #include "spawnvex.h"
76 #endif
77 
78 #define SH_NTFORK SH_TIMING
79 
80 extern int nice(int);
81 #if USE_SPAWN
82 static_fn pid_t sh_ntfork(Shell_t *, const Shnode_t *, char *[], int *, int);
83 #endif  // USE_SPAWN
84 
85 static_fn void sh_funct(Shell_t *, Namval_t *, int, char *[], struct argnod *, int);
86 static_fn void coproc_init(Shell_t *, int pipes[]);
87 
88 static Timer_t *timeout;
89 static char nlock;
90 static char pipejob;
91 static int restorefd;
92 #if USE_SPAWN
93 static int restorevex;
94 #endif
95 
96 struct funenv {
97     Namval_t *node;
98     struct argnod *env;
99     Namval_t **nref;
100 };
101 
102 #if USE_SPAWN
io_usevex(struct ionod * iop)103 static_fn int io_usevex(struct ionod *iop) {
104     struct ionod *first = iop;
105     for (; iop; iop = iop->ionxt) {
106         if ((iop->iofile & IODOC) && !(iop->iofile & IOQUOTE) && iop != first) return 0;
107     }
108     return IOUSEVEX;
109 }
110 #endif  // USE_SPAWN
111 #if 1
112 #undef IOUSEVEX
113 #define IOUSEVEX 0
114 #endif
115 
116 // ======== command execution ========
117 
118 #if !has_dev_fd
fifo_check(void * handle)119 static_fn void fifo_check(void *handle) {
120     Shell_t *shp = handle;
121     pid_t pid = getppid();
122     if (pid == 1) {
123         unlink(shp->fifo);
124         sh_done(shp, 0);
125     }
126 }
127 #endif  // !has_dev_fd
128 
129 #if _lib_getrusage
130 
131 // Use getrusage() rather than times() since the former typically has higher resolution.
132 #include <sys/resource.h>
133 
get_cpu_times(struct timeval * tv_usr,struct timeval * tv_sys)134 static_fn void get_cpu_times(struct timeval *tv_usr, struct timeval *tv_sys) {
135     struct rusage usage_self, usage_child;
136 
137     getrusage(RUSAGE_SELF, &usage_self);
138     getrusage(RUSAGE_CHILDREN, &usage_child);
139     timeradd(&usage_self.ru_utime, &usage_child.ru_utime, tv_usr);
140     timeradd(&usage_self.ru_stime, &usage_child.ru_stime, tv_sys);
141 }
142 
143 #else  // _lib_getrusage
144 
get_cpu_times(struct timeval * tv_usr,struct timeval * tv_sys)145 static_fn void get_cpu_times(struct timeval *tv_usr, struct timeval *tv_sys) {
146     struct timeval tv1, tv2;
147     double dtime;
148     long clk_tck = sysconf(_SC_CLK_TCK);
149     struct tms cpu_times;
150     times(&cpu_times);
151 
152     dtime = (double)cpu_times.tms_utime / clk_tck;
153     tv1.tv_sec = dtime / 60;
154     tv1.tv_usec = 1000000 * (dtime - tv1.tv_sec);
155     dtime = (double)cpu_times.tms_cutime / clk_tck;
156     tv2.tv_sec = dtime / 60;
157     tv2.tv_usec = 1000000 * (dtime - tv2.tv_sec);
158     timeradd(&tv1, &tv2, tv_usr);
159 
160     dtime = (double)cpu_times.tms_stime / clk_tck;
161     tv1.tv_sec = dtime / 60;
162     tv1.tv_usec = 1000000 * (dtime - tv1.tv_sec);
163     dtime = (double)cpu_times.tms_cstime / clk_tck;
164     tv2.tv_sec = dtime / 60;
165     tv2.tv_usec = 1000000 * (dtime - tv2.tv_sec);
166     timeradd(&tv1, &tv2, tv_sys);
167 }
168 
169 #endif  // _lib_getrusage
170 
timeval_to_double(struct timeval tv)171 static inline double timeval_to_double(struct timeval tv) {
172     return (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0);
173 }
174 
175 //
176 // The following two functions allow command substituion for non-builtins to use a pipe and to wait
177 // for the pipe to close before restoring to a temp file.
178 //
179 static int subpipe[3], subdup, tsetio, usepipe;
180 
iousepipe(Shell_t * shp)181 static_fn void iousepipe(Shell_t *shp) {
182     int i;
183     int fd = sffileno(sfstdout);
184 
185     if (!sh_iovalidfd(shp, fd)) abort();
186     if (usepipe) {
187         usepipe++;
188         sh_iounpipe(shp);
189     }
190     sh_rpipe(subpipe);
191     usepipe++;
192     if (shp->comsub != 1) {
193         subpipe[2] = sh_fcntl(subpipe[1], F_DUPFD, 10);
194         sh_close(subpipe[1]);
195         return;
196     }
197     subpipe[2] = sh_fcntl(fd, F_DUPFD_CLOEXEC, 10);
198     if (!sh_iovalidfd(shp, subpipe[2])) abort();
199     shp->fdstatus[subpipe[2]] = shp->fdstatus[1];
200 
201     close(fd);
202     i = fcntl(subpipe[1], F_DUPFD, fd);
203     assert(i != -1);  // it should be impossible for the fcntl() to fail
204 
205     shp->fdstatus[1] = shp->fdstatus[subpipe[1]] & ~IOCLEX;
206     sh_close(subpipe[1]);
207     subdup = shp->subdup;
208     if (subdup) {
209         for (i = 0; i < 10; i++) {
210             if (subdup & (1 << i)) {
211                 sh_close(i);
212                 (void)fcntl(1, F_DUPFD, i);  // this can't fail
213                 shp->fdstatus[i] = shp->fdstatus[1];
214             }
215         }
216     }
217 }
218 
sh_iounpipe(Shell_t * shp)219 void sh_iounpipe(Shell_t *shp) {
220     int n;
221     char buff[SF_BUFSIZE];
222     int fd = sffileno(sfstdout);
223 
224     if (!usepipe) return;
225     --usepipe;
226     if (shp->comsub > 1) {
227         sh_close(subpipe[2]);
228         while (read(subpipe[0], buff, sizeof(buff)) > 0) {
229             ;  // empty loop
230         }
231         goto done;
232     }
233 
234     close(fd);
235     n = fcntl(subpipe[2], F_DUPFD, fd);
236     assert(n != -1);  // it should be impossible for the fcntl() to fail
237 
238     shp->fdstatus[1] = shp->fdstatus[subpipe[2]];
239     if (subdup) {
240         for (n = 0; n < 10; n++) {
241             if (subdup & (1 << n)) {
242                 sh_close(n);
243                 (void)fcntl(1, F_DUPFD, n);  // this can't fail so we don't check the return value
244                 shp->fdstatus[n] = shp->fdstatus[1];
245             }
246         }
247     }
248     shp->subdup = 0;
249     sh_close(subpipe[2]);
250     if (usepipe == 0) {
251         while (1) {
252             while (job.waitsafe && job.savesig == SIGCHLD) {
253                 if (!vmbusy()) {
254                     job.in_critical++;
255                     job_reap(SIGCHLD);
256                     job.in_critical--;
257                     break;
258                 }
259                 sh_delay(1);
260             }
261             if ((n = read(subpipe[0], buff, sizeof(buff))) == 0) break;
262             if (n > 0) {
263                 sfwrite(sfstdout, buff, n);
264             } else if (errno != EINTR) {
265                 break;
266             }
267         }
268     }
269 done:
270     sh_close(subpipe[0]);
271     subpipe[0] = -1;
272     tsetio = 0;
273     usepipe = 0;
274 }
275 
276 //
277 // Print time <t> in h:m:s format with precision <p>.
278 //
l_time(Sfio_t * outfile,struct timeval * tv,int precision)279 static_fn void l_time(Sfio_t *outfile, struct timeval *tv, int precision) {
280     int hr = tv->tv_sec / (60 * 60);
281     int min = (tv->tv_sec / 60) % 60;
282     int sec = tv->tv_sec % 60;
283     int frac = tv->tv_usec;
284 
285     // Scale fraction from micro to milli, centi, or deci second according to precision.
286     for (int n = 3 + (3 - precision); n > 0; --n) frac /= 10;
287 
288     if (hr) sfprintf(outfile, "%dh", hr);
289     if (precision) {
290         sfprintf(outfile, "%dm%d%c%0*ds", min, sec, getdecimal(), precision, frac);
291     } else {
292         sfprintf(outfile, "%dm%ds", min, sec);
293     }
294 }
295 
296 #define TM_REAL_IDX 0
297 #define TM_USR_IDX 1
298 #define TM_SYS_IDX 2
299 
p_time(Shell_t * shp,Sfio_t * out,const char * format,struct timeval tm[3])300 static_fn void p_time(Shell_t *shp, Sfio_t *out, const char *format, struct timeval tm[3]) {
301     int c, n, offset = stktell(shp->stk);
302     const char *first;
303     struct timeval tv_cpu_sum;
304     struct timeval *tvp;
305     Stk_t *stkp = shp->stk;
306 
307     for (first = format; *format; format++) {
308         c = *format;
309         if (c != '%') continue;
310         bool l_modifier = false;
311         int precision = 3;
312 
313         sfwrite(stkp, first, format - first);
314         c = *++format;
315         if (c == '\0') {
316             // If a lone percent is the last character of the format pretend
317             // the user had written `%%` for a literal percent.
318             sfwrite(stkp, "%", 1);
319             first = format + 1;
320             break;
321         } else if (c == '%') {
322             first = format;
323             continue;
324         }
325 
326         if (c >= '0' && c <= '9') {
327             precision = (c > '3') ? 3 : (c - '0');
328             c = *++format;
329         }
330 
331         if (c == 'P') {
332             struct timeval tv_real = tm[TM_REAL_IDX];
333             struct timeval tv_cpu;
334             timeradd(&tm[TM_USR_IDX], &tm[TM_SYS_IDX], &tv_cpu);
335 
336             double d = timeval_to_double(tv_real);
337             if (d) d = 100.0 * timeval_to_double(tv_cpu) / d;
338             sfprintf(stkp, "%.*f", precision, d);
339             first = format + 1;
340             continue;
341         }
342 
343         if (c == 'l') {
344             l_modifier = true;
345             c = *++format;
346         }
347 
348         if (c == 'R') {
349             tvp = &tm[TM_REAL_IDX];
350         } else if (c == 'U') {
351             tvp = &tm[TM_USR_IDX];
352         } else if (c == 'S') {
353             tvp = &tm[TM_SYS_IDX];
354         } else if (c == 'C') {
355             timeradd(&tm[TM_USR_IDX], &tm[TM_SYS_IDX], &tv_cpu_sum);
356             tvp = &tv_cpu_sum;
357         } else {
358             errormsg(SH_DICT, ERROR_exit(0), e_badtformat, c);
359             continue;
360         }
361 
362         if (l_modifier) {
363             l_time(stkp, tvp, precision);
364         } else {
365             // Scale fraction from micro to milli, centi, or deci second according to precision.
366             int frac = tvp->tv_usec;
367             for (int n = 3 + (3 - precision); n > 0; --n) frac /= 10;
368             sfprintf(stkp, "%d.%0*d", tvp->tv_sec, precision, frac);
369         }
370         first = format + 1;
371     }
372 
373     if (format > first) sfwrite(stkp, first, format - first);
374     sfputc(stkp, '\n');
375     n = stktell(stkp) - offset;
376     sfwrite(out, stkptr(stkp, offset), n);
377     stkseek(stkp, offset);
378 }
379 
380 //
381 // Clear argument pointers that point into the stack.
382 //
383 static_fn int xec_p_arg(Shell_t *, struct argnod *, int);
384 static_fn int xec_p_switch(Shell_t *, struct regnod *);
385 
xec_p_comarg(Shell_t * shp,struct comnod * com)386 static_fn int xec_p_comarg(Shell_t *shp, struct comnod *com) {
387     Namval_t *np = com->comnamp;
388     int n = xec_p_arg(shp, com->comset, ARG_ASSIGN);
389     if (com->comarg && (com->comtyp & COMSCAN)) n += xec_p_arg(shp, com->comarg, 0);
390     if (com->comstate && np) {
391         // Call builtin to cleanup state.
392         Shbltin_t *bp = &shp->bltindata;
393         void *save_ptr = bp->ptr;
394         void *save_data = bp->data;
395         bp->bnode = np;
396         bp->vnode = com->comnamq;
397         bp->ptr = nv_context(np);
398         bp->data = com->comstate;
399         // Was bp->flags = SH_END_OPTIM but no builtin actually uses the flags structure member
400         // and it's companion symbols, SH_BEGIN_OPTIM, isn't used anywhere.
401         bp->flags = 0;
402         funptr(np)(0, NULL, bp);
403         bp->ptr = save_ptr;
404         bp->data = save_data;
405     }
406     com->comstate = NULL;
407     if (com->comarg && !np) n++;
408     return n;
409 }
410 
411 extern void sh_optclear(Shell_t *, void *);
412 
sh_tclear(Shell_t * shp,Shnode_t * t)413 static_fn int sh_tclear(Shell_t *shp, Shnode_t *t) {
414     if (!t) return 0;
415 
416     int n;
417     switch (t->tre.tretyp & COMMSK) {
418         case TTIME:
419         case TPAR: {
420             return sh_tclear(shp, t->par.partre);
421         }
422         case TCOM: {
423             return xec_p_comarg(shp, (struct comnod *)t);
424         }
425         case TSETIO:
426         case TFORK: {
427             return sh_tclear(shp, t->fork.forktre);
428         }
429         case TIF: {
430             n = sh_tclear(shp, t->if_.iftre);
431             n += sh_tclear(shp, t->if_.thtre);
432             n += sh_tclear(shp, t->if_.eltre);
433             return n;
434         }
435         case TWH: {
436             n = 0;
437             if (t->wh.whinc) n = sh_tclear(shp, (Shnode_t *)(t->wh.whinc));
438             n += sh_tclear(shp, t->wh.whtre);
439             n += sh_tclear(shp, t->wh.dotre);
440             return n;
441         }
442         case TLST:
443         case TAND:
444         case TORF:
445         case TFIL: {
446             n = sh_tclear(shp, t->lst.lstlef);
447             return n + sh_tclear(shp, t->lst.lstrit);
448         }
449         case TARITH: {
450             return xec_p_arg(shp, t->ar.arexpr, ARG_ARITH);
451         }
452         case TFOR: {
453             n = sh_tclear(shp, t->for_.fortre);
454             return n + sh_tclear(shp, (Shnode_t *)t->for_.forlst);
455         }
456         case TSW: {
457             n = xec_p_arg(shp, t->sw.swarg, 0);
458             return n + xec_p_switch(shp, t->sw.swlst);
459         }
460         case TFUN: {
461             n = sh_tclear(shp, t->funct.functtre);
462             return n + sh_tclear(shp, (Shnode_t *)t->funct.functargs);
463         }
464         case TTST: {
465             if ((t->tre.tretyp & TPAREN) == TPAREN) {
466                 return sh_tclear(shp, t->lst.lstlef);
467             }
468             n = xec_p_arg(shp, &(t->lst.lstlef->arg), 0);
469             if (t->tre.tretyp & TBINARY) n += xec_p_arg(shp, &(t->lst.lstrit->arg), 0);
470             return n;
471         }
472         default: { return 0; }
473     }
474 }
475 
xec_p_arg(Shell_t * shp,struct argnod * arg,int flag)476 static_fn int xec_p_arg(Shell_t *shp, struct argnod *arg, int flag) {
477     while (arg) {
478         if (strlen(arg->argval) || (arg->argflag == ARG_RAW)) {
479             arg->argchn.ap = NULL;
480         } else if (flag == 0) {
481             sh_tclear(shp, (Shnode_t *)arg->argchn.ap);
482         } else {
483             sh_tclear(shp, ((struct fornod *)arg->argchn.ap)->fortre);
484         }
485         arg = arg->argnxt.ap;
486     }
487     return 0;
488 }
489 
xec_p_switch(Shell_t * shp,struct regnod * reg)490 static_fn int xec_p_switch(Shell_t *shp, struct regnod *reg) {
491     int n = 0;
492     while (reg) {
493         n += xec_p_arg(shp, reg->regptr, 0);
494         n += sh_tclear(shp, reg->regcom);
495         reg = reg->regnxt;
496     }
497     return n;
498 }
499 
out_pattern(Sfio_t * iop,const char * cp,int n)500 static_fn void out_pattern(Sfio_t *iop, const char *cp, int n) {
501     int c;
502 
503     do {
504         switch (c = *cp) {
505             case 0: {
506                 if (n < 0) return;
507                 c = n;
508                 break;
509             }
510             case '\n': {
511                 sfputr(iop, "$'\\n", '\'');
512                 continue;
513             }
514             case '\\': {
515                 if (!(c = *++cp)) c = '\\';
516             }
517             // FALLTHRU
518             case ' ':
519             case '<':
520             case '>':
521             case ';':
522             case '$':
523             case '`':
524             case '\t': {
525                 sfputc(iop, '\\');
526                 break;
527             }
528             default: { break; }
529         }
530         sfputc(iop, c);
531     } while (*cp++);
532 }
533 
out_string(Sfio_t * iop,const char * cp,int c,int quoted)534 static_fn void out_string(Sfio_t *iop, const char *cp, int c, int quoted) {
535     if (quoted) {
536         int n = stktell(stkstd);
537         cp = sh_fmtq(cp);
538         if (iop == stkstd && cp == stkptr(stkstd, n)) {
539             *stkptr(stkstd, stktell(stkstd) - 1) = c;
540             return;
541         }
542     }
543     sfputr(iop, cp, c);
544 }
545 
546 struct Level {
547     Namfun_t namfun;
548     short maxlevel;
549 };
550 
551 //
552 // This is for a debugger but it hasn't been tested yet. If a debug script sets .sh.level it should
553 // set up the scope as if you were executing in that level.
554 //
put_level(Namval_t * np,const void * val,nvflag_t flags,Namfun_t * fp)555 static_fn void put_level(Namval_t *np, const void *val, nvflag_t flags, Namfun_t *fp) {
556     Shell_t *shp = sh_ptr(np);
557     Shscope_t *sp;
558     struct Level *lp = (struct Level *)fp;
559     int16_t level, oldlevel = (int16_t)nv_getnum(np);
560 
561     nv_putv(np, val, flags, fp);
562     if (!val) {
563         fp = nv_stack(np, NULL);
564         if (fp && !fp->nofree) free(fp);
565         return;
566     }
567     level = nv_getnum(np);
568     if (level < 0 || level > lp->maxlevel) {
569         nv_putv(np, (char *)&oldlevel, NV_INT16, fp);
570         // Perhaps this should be an error.
571         return;
572     }
573     if (level == oldlevel) return;
574     sp = sh_getscope(shp, level, SEEK_SET);
575     if (sp) {
576         sh_setscope(shp, sp);
577         error_info.id = sp->cmdname;
578     }
579 }
580 
581 static const Namdisc_t level_disc = {.dsize = sizeof(struct Level), .putval = put_level};
582 
init_level(Shell_t * shp,int level)583 static_fn struct Level *init_level(Shell_t *shp, int level) {
584     struct Level *lp = calloc(1, sizeof(struct Level));
585 
586     lp->maxlevel = level;
587     _nv_unset(VAR_sh_level, 0);
588     nv_onattr(VAR_sh_level, NV_INT16 | NV_NOFREE);
589     shp->last_root = nv_dict(VAR_sh);
590     nv_putval(VAR_sh_level, (char *)&lp->maxlevel, NV_INT16);
591     lp->namfun.disc = &level_disc;
592     nv_disc(VAR_sh_level, &lp->namfun, DISC_OP_FIRST);
593     return lp;
594 }
595 
596 //
597 // Write the current command on the stack and make it available as .sh.command.
598 //
sh_debug(Shell_t * shp,const char * trap,const char * name,const char * subscript,char * const argv[],int flags)599 int sh_debug(Shell_t *shp, const char *trap, const char *name, const char *subscript,
600              char *const argv[], int flags) {
601     Stk_t *stkp = shp->stk;
602     struct sh_scoped savst;
603     Namval_t *np = VAR_sh_command;
604     char *sav = stkptr(stkp, 0);
605     int n = 4, offset = stktell(stkp);
606     const char *cp = "+=( ";
607     Sfio_t *iop = stkstd;
608     short level;
609 
610     if (shp->indebug) return 0;
611     shp->indebug = 1;
612     if (name) {
613         sfputr(iop, name, -1);
614         if (subscript) {
615             sfputc(iop, '[');
616             out_string(iop, subscript, ']', 1);
617         }
618         if (!(flags & ARG_APPEND)) cp += 1, n -= 1;
619         if (!(flags & ARG_ASSIGN)) n -= 2;
620         sfwrite(iop, cp, n);
621     }
622     if (*argv && !(flags & ARG_RAW)) out_string(iop, *argv++, ' ', 0);
623     n = (flags & ARG_ARITH);
624     while ((cp = *argv++)) {
625         if ((flags & ARG_EXP) && argv[1] == 0) {
626             out_pattern(iop, cp, ' ');
627         } else {
628             out_string(iop, cp, ' ', n ? 0 : (flags & (ARG_RAW | ARG_NOGLOB)) || *argv);
629         }
630     }
631     if (flags & ARG_ASSIGN) {
632         sfputc(iop, ')');
633     } else if (iop == stkstd) {
634         *stkptr(stkp, stktell(stkp) - 1) = 0;
635     }
636     STORE_VT(np->nvalue, const_cp, stkfreeze(stkp, 1));
637     // Now setup .sh.level variable.
638     shp->st.lineno = error_info.line;
639     level = shp->fn_depth + shp->dot_depth;
640     shp->last_root = nv_dict(VAR_sh);
641     if (!VAR_sh_level->nvfun || !VAR_sh_level->nvfun->disc ||
642         nv_isattr(VAR_sh_level, NV_INT16 | NV_NOFREE) != (NV_INT16 | NV_NOFREE)) {
643         init_level(shp, level);
644     } else {
645         nv_putval(VAR_sh_level, (char *)&level, NV_INT16);
646     }
647     savst = shp->st;
648     shp->st.trap[SH_DEBUGTRAP] = 0;
649     n = sh_trap(shp, trap, 0);
650     STORE_VT(np->nvalue, const_cp, NULL);
651     shp->indebug = 0;
652     if (shp->st.cmdname) error_info.id = shp->st.cmdname;
653     nv_putval(VAR_sh_file, shp->st.filename, NV_NOFREE);
654     nv_putval(VAR_sh_fun, shp->st.funname, NV_NOFREE);
655     shp->st = savst;
656     if (sav != stkptr(stkp, 0)) {
657         stkset(stkp, sav, 0);
658     } else {
659         stkseek(stkp, offset);
660     }
661     return n;
662 }
663 
664 //
665 // Returns true when option -<c> is specified.
666 //
checkopt(char * argv[],int c)667 static_fn bool checkopt(char *argv[], int c) {
668     char *cp;
669 
670     while ((cp = *++argv)) {
671         if (*cp == '+') continue;
672         if (*cp != '-' || cp[1] == '-') break;
673         if (strchr(++cp, c)) return 1;
674         if (*cp == 'h' && cp[1] == 0 && *++argv == 0) break;
675     }
676     return false;
677 }
678 
free_list(struct openlist * olist)679 static_fn void free_list(struct openlist *olist) {
680     struct openlist *item, *next;
681 
682     for (item = olist; item; item = next) {
683         next = item->next;
684         free(item);
685     }
686 }
687 
688 //
689 // Set ${.sh.name} and ${.sh.subscript}.
690 // Set _ to reference for ${.sh.name}[$.sh.subscript].
691 //
set_instance(Shell_t * shp,Namval_t * nq,Namval_t * node,struct Namref * nr)692 static_fn nvflag_t set_instance(Shell_t *shp, Namval_t *nq, Namval_t *node, struct Namref *nr) {
693     char *sp = NULL;
694     char *cp;
695     Namarr_t *ap;
696     Namval_t *np;
697 
698     if (!nv_isattr(nq, NV_MINIMAL | NV_EXPORT | NV_ARRAY) && (np = nq->nvenv) && nv_isarray(np)) {
699         nq = np;
700     } else if (nv_isattr(nq, NV_MINIMAL) == NV_MINIMAL && !nv_type(nq) &&
701                (np = nv_typeparent(nq))) {
702         nq = np;
703     }
704     cp = nv_name(nq);
705     memset(nr, 0, sizeof(*nr));
706     nr->np = nq;
707     nr->root = shp->var_tree;
708     nr->table = shp->last_table;
709     if (!nr->table && shp->namespace) nr->table = shp->namespace;
710     shp->instance = 1;
711     ap = nv_arrayptr(nq);
712     if (ap) {
713         sp = nv_getsub(nq);
714         if (sp) nr->sub = strdup(sp);
715     }
716     shp->instance = 0;
717     if (shp->var_tree != shp->var_base && !nv_search_namval(nq, nr->root, NV_NOSCOPE)) {
718         nr->root = shp->namespace ? nv_dict(shp->namespace) : shp->var_base;
719     }
720     nv_putval(VAR_sh_name, cp, NV_NOFREE);
721     memcpy(node, VAR_underscore, sizeof(*node));
722     STORE_VT(VAR_underscore->nvalue, nrp, nr);
723     nv_setattr(VAR_underscore, NV_REF | NV_NOFREE);
724     VAR_underscore->nvfun = NULL;
725     VAR_underscore->nvenv = NULL;
726     if (ap && nr->sub) {
727         nv_putval(VAR_sh_subscript, nr->sub, NV_NOFREE);
728         return ap->flags & ARRAY_SCAN;
729     }
730     return 0;
731 }
732 
unset_instance(Namval_t * nq,Namval_t * node,struct Namref * nr,nvflag_t mode)733 static_fn void unset_instance(Namval_t *nq, Namval_t *node, struct Namref *nr, nvflag_t mode) {
734     UNUSED(nq);
735 
736     STORE_VT(VAR_underscore->nvalue, nrp, FETCH_VT(node->nvalue, nrp));
737     nv_setattr(VAR_underscore, node->nvflag);
738     VAR_underscore->nvfun = node->nvfun;
739     if (nr->sub) {
740         nv_putsub(nr->np, nr->sub, 0, mode);
741         free(nr->sub);
742     }
743     _nv_unset(VAR_sh_name, 0);
744     _nv_unset(VAR_sh_subscript, 0);
745 }
746 
openstream(Shell_t * shp,struct ionod * iop,int * save)747 static_fn Sfio_t *openstream(Shell_t *shp, struct ionod *iop, int *save) {
748     Sfio_t *sp;
749     int savein;
750     int fd = sh_redirect(shp, iop, 3);
751 
752     savein = dup(0);
753     if (fd == 0) fd = savein;
754     sp = sfnew(NULL, NULL, SF_UNBOUND, fd, SF_READ);
755     close(0);
756     if (sh_open("/dev/null", O_RDONLY | O_CLOEXEC) != 0) abort();
757     shp->offsets[0] = -1;
758     shp->offsets[1] = 0;
759     *save = savein;
760     return sp;
761 }
762 
enter_namespace(Shell_t * shp,Namval_t * nsp)763 static_fn Namval_t *enter_namespace(Shell_t *shp, Namval_t *nsp) {
764     Namval_t *path = nsp, *fpath = nsp, *onsp = shp->namespace;
765     Dt_t *root = NULL;
766     Dt_t *oroot = NULL;
767     char *val;
768 
769     if (nsp) {
770         if (!nv_istable(nsp)) {
771             nsp = NULL;
772         } else if (nv_dict(nsp)->view != shp->var_base) {
773             return onsp;
774         }
775     }
776     if (!nsp && !onsp) return NULL;
777     if (onsp == nsp) return nsp;
778     if (onsp) {
779         oroot = nv_dict(onsp);
780         if (!nsp) {
781             path = nv_search(VAR_PATH->nvname, oroot, NV_NOSCOPE);
782             fpath = nv_search(VAR_FPATH->nvname, oroot, NV_NOSCOPE);
783         }
784         if (shp->var_tree == oroot) {
785             shp->var_tree = shp->var_tree->view;
786             oroot = shp->var_base;
787         }
788     }
789     if (nsp) {
790         if (shp->var_tree == shp->var_base) {
791             shp->var_tree = nv_dict(nsp);
792         } else {
793             for (root = shp->var_tree; root->view != oroot; root = root->view) {
794                 ;  // empty loop
795             }
796             dtview(root, nv_dict(nsp));
797         }
798     }
799     shp->namespace = nsp;
800     if (path && (path = nv_search(VAR_PATH->nvname, shp->var_tree, NV_NOSCOPE)) &&
801         (val = nv_getval(path))) {
802         nv_putval(path, val, NV_RDONLY);
803     }
804     if (fpath && (fpath = nv_search(VAR_FPATH->nvname, shp->var_tree, NV_NOSCOPE)) &&
805         (val = nv_getval(fpath))) {
806         nv_putval(fpath, val, NV_RDONLY);
807     }
808     return onsp;
809 }
810 
forked_child(Shell_t * shp,const Shnode_t * t,int flags,int type,bool no_fork,char * com0,char ** com,pid_t parent,int topfd,int vexi)811 __attribute__((noreturn)) static_fn void forked_child(Shell_t *shp, const Shnode_t *t, int flags,
812                                                       int type, bool no_fork, char *com0,
813                                                       char **com, pid_t parent, int topfd,
814                                                       int vexi) {
815 #if !USE_SPAWN
816     UNUSED(vexi);
817 #endif
818     // This is the FORKED branch (child) of execute.
819     volatile int jmpval;
820     checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
821     struct ionod *iop;
822     int rewrite = 0;
823     if (no_fork) sh_sigreset(shp, 2);
824     sh_pushcontext(shp, buffp, SH_JMPEXIT);
825     jmpval = sigsetjmp(buffp->buff, 0);
826     if (jmpval) goto done;
827     if ((type & FINT) && !sh_isstate(shp, SH_MONITOR)) {
828         // Default std input for &.
829         sh_signal(SIGINT, (sh_sigfun_t)(SIG_IGN));
830         sh_signal(SIGQUIT, (sh_sigfun_t)(SIG_IGN));
831         shp->sigflag[SIGINT] = SH_SIGOFF;
832         shp->sigflag[SIGQUIT] = SH_SIGOFF;
833         if (!shp->st.ioset) {
834             if (sh_close(0) >= 0) {
835                 int tmp_fd = sh_open("/dev/null", O_RDONLY, 0);
836                 assert(tmp_fd == 0);
837             }
838         }
839     }
840     sh_offstate(shp, SH_MONITOR);
841     // Pipe in or out.
842     if ((type & FAMP) && sh_isoption(shp, SH_BGNICE)) nice(4);
843 
844 #if !has_dev_fd
845     if (shp->fifo && (type & (FPIN | FPOU))) {
846         int fn, fd = (type & FPIN) ? 0 : 1;
847         Timer_t *fifo_timer = sh_timeradd(500, 1, fifo_check, shp);
848         fn = sh_open(shp->fifo, fd ? O_WRONLY : O_RDONLY);
849         timerdel(fifo_timer);
850         sh_iorenumber(shp, fn, fd);
851         sh_close(fn);
852         sh_delay(.001);
853         unlink(shp->fifo);
854         free(shp->fifo);
855         shp->fifo = NULL;
856         type &= ~(FPIN | FPOU);
857     }
858 #endif  // !has_dev_fd
859     if (type & FPIN) {
860         sh_iorenumber(shp, shp->inpipe[0], 0);
861         if (!(type & FPOU) || (type & FCOOP)) sh_close(shp->inpipe[1]);
862     }
863     if (type & FPOU) {
864         sh_iorenumber(shp, shp->outpipe[1], 1);
865         sh_pclose(shp->outpipe);
866     }
867     if ((type & COMMSK) != TCOM) {
868         error_info.line = t->fork.forkline - shp->st.firstline;
869     }
870     if (shp->topfd) sh_iounsave(shp);
871     topfd = shp->topfd;
872     if (com0 && (iop = t->tre.treio)) {
873         for (; iop; iop = iop->ionxt) {
874             if (iop->iofile & IOREWRITE) rewrite = 1;
875         }
876     }
877     sh_redirect(shp, t->tre.treio, 1 | IOUSEVEX);
878     if (rewrite) {
879         job_lock();
880         while ((parent = fork()) < 0) _sh_fork(shp, parent, 0, NULL);
881         if (parent) {
882             job.toclear = 0;
883             job_post(shp, parent, 0);
884             job_wait(parent);
885             sh_iorestore(shp, topfd, SH_JMPCMD);
886 #if USE_SPAWN
887             if (shp->vexp->cur > vexi) sh_vexrestore(shp, vexi);
888 #endif
889             sh_done(shp, (shp->exitval & SH_EXITSIG) ? (shp->exitval & SH_EXITMASK) : 0);
890         }
891         job_unlock();
892     }
893     if ((type & COMMSK) != TCOM) {
894         // Don't clear job table for out pipes so that jobs comand can be used in a
895         // pipeline.
896         if (!no_fork && !(type & FPOU)) job_clear(shp);
897         sh_exec(shp, t->fork.forktre, flags | sh_state(SH_NOFORK) | sh_state(SH_FORKED));
898     } else if (com0) {
899         sh_offoption(shp, SH_ERREXIT);
900         sh_freeup(shp);
901         path_exec(shp, com0, com, t->com.comset);
902     }
903 done:
904     sh_popcontext(shp, buffp);
905     if (jmpval > SH_JMPEXIT) siglongjmp(shp->jmplist->buff, jmpval);
906     sh_done(shp, 0);
907 }
908 
sh_exec(Shell_t * shp,const Shnode_t * t,int flags)909 int sh_exec(Shell_t *shp, const Shnode_t *t, int flags) {
910     sh_sigcheck(shp);
911 
912     if (!t) return shp->exitval;
913     if (shp->st.execbrk) return shp->exitval;
914     if (sh_isoption(shp, SH_NOEXEC)) return shp->exitval;
915 
916     Stk_t *stkp = shp->stk;
917     int type = flags;
918     char *com0 = NULL;
919     int errorflg = (type & sh_state(SH_ERREXIT)) | (flags & ARG_OPTIMIZE);
920     int execflg = (type & sh_state(SH_NOFORK));
921     int execflg2 = (type & sh_state(SH_FORKED));
922     int mainloop = (type & sh_state(SH_INTERACTIVE));
923 #if USE_SPAWN
924     int ntflag = (type & sh_state(SH_NTFORK));
925 #else
926     int ntflag = 0;
927 #endif
928     int topfd = shp->topfd;
929     char *sav = stkptr(stkp, 0);
930     char *cp = NULL;
931     char **com = NULL;
932     char *comn;
933     int argn;
934     int skipexitset = 0;
935 #if USE_SPAWN
936     int vexi = shp->vexp->cur;
937 #else
938     int vexi = 0;
939 #endif
940     pid_t *procsub = NULL;
941     volatile int was_interactive = 0;
942     volatile int was_errexit = sh_isstate(shp, SH_ERREXIT);
943     volatile int was_monitor = sh_isstate(shp, SH_MONITOR);
944     volatile int echeck = 0;
945 
946     if (flags & sh_state(SH_INTERACTIVE)) {
947         if (pipejob == 2) job_unlock();
948         nlock = 0;
949         pipejob = 0;
950         job.curpgid = 0;
951         job.curjobid = 0;
952         flags &= ~sh_state(SH_INTERACTIVE);
953     }
954     sh_offstate(shp, SH_ERREXIT);
955     sh_offstate(shp, SH_DEFPATH);
956     if (was_errexit & flags) sh_onstate(shp, SH_ERREXIT);
957     if (was_monitor & flags) sh_onstate(shp, SH_MONITOR);
958     type = t->tre.tretyp;
959     if (!shp->intrap) shp->oldexit = shp->exitval;
960     shp->exitval = 0;
961     shp->lastsig = 0;
962     shp->lastpath = NULL;
963     if (shp->exittrap || shp->errtrap) execflg = 0;
964     switch (type & COMMSK) {
965         case TCOM: {
966             struct argnod *argp;
967             char *trap;
968             Namval_t *np, *nq, *last_table;
969             struct ionod *io;
970             int command = 0;
971             nvflag_t nvflags = NV_ASSIGN;
972             shp->bltindata.invariant = type >> (COMBITS + 2);
973             shp->bltindata.pwdfd = shp->pwdfd;
974             type &= (COMMSK | COMSCAN);
975             sh_stats(STAT_SCMDS);
976             error_info.line = t->com.comline - shp->st.firstline;
977 #if USE_SPAWN
978             spawnvex_add(shp->vex, SPAWN_frame, 0, 0, 0);
979 #endif
980             com = sh_argbuild(shp, &argn, &(t->com), flags & ARG_OPTIMIZE);
981             procsub = shp->procsub;
982             shp->procsub = NULL;
983             echeck = 1;
984             if (t->tre.tretyp & COMSCAN) {
985                 argp = t->com.comarg;
986                 if (argp && *com && !(argp->argflag & ARG_RAW)) sh_sigcheck(shp);
987             }
988             np = t->com.comnamp;
989             nq = t->com.comnamq;
990             if (np && shp->namespace && nq != shp->namespace &&
991                 nv_isattr(np, NV_BLTIN | NV_INTEGER | BLT_SPC) != (NV_BLTIN | BLT_SPC)) {
992                 Namval_t *mp;
993                 mp = sh_fsearch(shp, com[0], 0);
994                 if (mp) {
995                     nq = shp->namespace;
996                     np = mp;
997                 }
998             }
999             com0 = com[0];
1000             shp->xargexit = 0;
1001             while (np == SYSCOMMAND) {
1002                 int n = b_command(0, com, &shp->bltindata);
1003                 if (n == 0) break;
1004                 command += n;
1005                 np = NULL;
1006                 if (!(com0 = *(com += n))) break;
1007                 np = nv_bfsearch(com0, shp->bltin_tree, &nq, &cp);
1008             }
1009             if (shp->xargexit) {
1010                 shp->xargmin -= command;
1011                 shp->xargmax -= command;
1012             } else {
1013                 shp->xargmin = 0;
1014             }
1015             argn -= command;
1016             if (np && is_abuiltin(np)) {
1017                 if (!command) {
1018                     Namval_t *mp;
1019                     if (shp->namespace && (mp = sh_fsearch(shp, np->nvname, 0))) {
1020                         np = mp;
1021                     } else {
1022                         np = dtsearch(shp->fun_tree, np);
1023                     }
1024                 }
1025             }
1026             if (com0) {
1027                 if (!np && !strchr(com0, '/')) {
1028                     Dt_t *root = command ? shp->bltin_tree : shp->fun_tree;
1029                     np = nv_bfsearch(com0, root, &nq, &cp);
1030                     if (shp->namespace && !nq && !cp) np = sh_fsearch(shp, com0, 0);
1031                 }
1032                 comn = com[argn - 1];
1033             }
1034             io = t->tre.treio;
1035         tryagain:
1036             shp->envlist = argp = t->com.comset;
1037             if (shp->envlist) {
1038                 if (argn == 0 ||
1039                     (np && (nv_isattr(np, BLT_DCL) || (!command && nv_isattr(np, BLT_SPC))))) {
1040                     Namval_t *tp = NULL;
1041                     if (argn) {
1042                         if (checkopt(com, 'A')) {
1043                             nvflags |= NV_ARRAY;
1044                         } else if (checkopt(com, 'a')) {
1045                             nvflags |= NV_IARRAY;
1046                         }
1047                     }
1048                     if (np) nvflags |= NV_UNJUST;
1049                     if (np == SYSLOCAL) {
1050                         if (!nv_getval(VAR_sh_fun)) {
1051                             errormsg(SH_DICT, ERROR_exit(1), "%s: can only be used in a function",
1052                                      com0);
1053                             __builtin_unreachable();
1054                         }
1055                         if (!shp->st.var_local) {
1056                             sh_scope(shp, NULL, 0);
1057                             shp->st.var_local = shp->var_tree;
1058                         }
1059                     }
1060                     if (np == SYSTYPESET || (np && FETCH_VT(np->nvalue, shbltinp) ==
1061                                                        FETCH_VT(SYSTYPESET->nvalue, shbltinp))) {
1062                         if (np != SYSTYPESET) {
1063                             shp->typeinit = np;
1064                             tp = nv_type(np);
1065                         }
1066                         if (checkopt(com, 'C')) nvflags |= NV_COMVAR;
1067                         if (checkopt(com, 'S')) nvflags |= NV_STATIC;
1068                         if (checkopt(com, 'm')) nvflags |= NV_MOVE;
1069                         if (checkopt(com, 'n')) {
1070                             nvflags |= NV_NOREF;
1071                         } else if (argn >= 3 && checkopt(com, 'T')) {
1072                             if (shp->namespace) {
1073                                 char *sp, *xp;
1074                                 if (!shp->strbuf2) shp->strbuf2 = sfstropen();
1075                                 sfprintf(shp->strbuf2, "%s%s%c", NV_CLASS, nv_name(shp->namespace),
1076                                          0);
1077                                 char *p = sfstruse(shp->strbuf2);
1078                                 assert(p);
1079                                 shp->prefix = strdup(p);
1080                                 xp = shp->prefix + strlen(NV_CLASS);
1081                                 for (sp = xp + 1; sp;) {
1082                                     sp = strchr(sp, '.');
1083                                     if (sp) *sp = 0;
1084                                     nv_open(shp->prefix, shp->var_base, NV_VARNAME);
1085                                     if (sp) *sp++ = '.';
1086                                 }
1087                             } else {
1088                                 shp->prefix = NV_CLASS;
1089                             }
1090                             nvflags |= NV_TYPE;
1091                         }
1092                         if ((shp->fn_depth && !shp->prefix) || np == SYSLOCAL) {
1093                             nvflags |= NV_NOSCOPE;
1094                         }
1095                     } else if (np == SYSEXPORT) {
1096                         nvflags |= NV_EXPORT;
1097                     }
1098                     if (nvflags & (NV_EXPORT | NV_NOREF)) {
1099                         nvflags |= NV_IDENT;
1100                     } else {
1101                         nvflags |= NV_VARNAME;
1102                     }
1103                     if (np && nv_isattr(np, BLT_DCL)) nvflags |= NV_DECL;
1104                     if (t->com.comtyp & COMFIXED) ((Shnode_t *)t)->com.comtyp &= ~COMFIXED;
1105                     shp->nodelist = sh_setlist(shp, argp, nvflags, tp);
1106                     if (np == shp->typeinit) shp->typeinit = NULL;
1107                     shp->envlist = argp;
1108                     argp = NULL;
1109                 }
1110             }
1111             last_table = shp->last_table;
1112             shp->last_table = NULL;
1113             if ((io || argn)) {
1114                 Shbltin_t *bp = NULL;
1115                 static char *argv[2] = {NULL, NULL};
1116                 int tflags = 1;
1117                 if (np && nv_isattr(np, BLT_DCL)) tflags |= 2;
1118                 if (argn == 0) {
1119                     // Fake 'true' built-in.
1120                     np = SYSTRUE;
1121                     argv[0] = nv_name(np);
1122                     com = argv;
1123                 }
1124                 // set +x doesn't echo.
1125                 else if ((t->tre.tretyp & FSHOWME) && sh_isoption(shp, SH_SHOWME)) {
1126                     int ison = sh_isoption(shp, SH_XTRACE);
1127                     if (!ison) sh_onoption(shp, SH_XTRACE);
1128                     sh_trace(shp, com - command, tflags);
1129                     if (io) sh_redirect(shp, io, SH_SHOWME | IOHERESTRING);
1130                     if (!ison) sh_offoption(shp, SH_XTRACE);
1131                     break;
1132                 } else if ((np != SYSSET) && sh_isoption(shp, SH_XTRACE)) {
1133                     sh_trace(shp, com - command, tflags);
1134                 }
1135                 trap = shp->st.trap[SH_DEBUGTRAP];
1136                 if (trap) {
1137                     int n = sh_debug(shp, trap, NULL, NULL, com, ARG_RAW);
1138                     if (n == 255 && shp->fn_depth + shp->dot_depth) {
1139                         np = SYSRETURN;
1140                         argn = 1;
1141                         com[0] = np->nvname;
1142                         com[1] = 0;
1143                         io = 0;
1144                         argp = NULL;
1145                     } else if (n == 2) {
1146                         break;
1147                     }
1148                 }
1149                 if (io) sfsync(shp->outpool);
1150                 shp->lastpath = NULL;
1151                 if (!np && !strchr(com0, '/')) {
1152                     if (path_search(shp, com0, NULL, 1)) {
1153                         error_info.line = t->com.comline - shp->st.firstline;
1154                         if (!shp->namespace || !(np = sh_fsearch(shp, com0, 0))) {
1155                             np = nv_search(com0, shp->fun_tree, 0);
1156                         }
1157                         if (!np || !FETCH_VT(np->nvalue, ip)) {
1158                             Namval_t *mp = nv_search(com0, shp->bltin_tree, 0);
1159                             if (mp) np = mp;
1160                         } else if ((t->com.comtyp & COMFIXED) && nv_type(np)) {
1161                             ((Shnode_t *)t)->com.comtyp &= ~COMFIXED;
1162                             goto tryagain;
1163                         }
1164                     } else {
1165                         if ((np = nv_search(com0, shp->track_tree, 0)) &&
1166                             !nv_isattr(np, NV_NOALIAS) && FETCH_VT(np->nvalue, const_cp)) {
1167                             np = nv_search(nv_getval(np), shp->bltin_tree, 0);
1168                         } else {
1169                             np = NULL;
1170                         }
1171                     }
1172                 }
1173                 if (np && pipejob == 2) {
1174                     if (shp->comsub == 1 && np && is_abuiltin(np) && *np->nvname == '/') {
1175                         np = NULL;
1176                     } else {
1177                         job_unlock();
1178                         nlock--;
1179                         pipejob = 1;
1180                     }
1181                 }
1182                 // Check for builtins.
1183                 if (np && is_abuiltin(np)) {
1184                     volatile int scope = 0, share = 0;
1185                     volatile void *save_ptr;
1186                     volatile void *save_data;
1187                     int jmpval, save_prompt;
1188                     int was_nofork = execflg ? sh_isstate(shp, SH_NOFORK) : 0;
1189                     checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
1190                     volatile unsigned long was_vi = 0, was_emacs = 0, was_gmacs = 0;
1191 #if !O_SEARCH
1192                     struct stat statb;
1193 #endif  // O_SEARCH
1194                     bp = &shp->bltindata;
1195                     save_ptr = bp->ptr;
1196                     save_data = bp->data;
1197 #if !O_SEARCH
1198                     memset(&statb, 0, sizeof(struct stat));
1199 #endif  // O_SEARCH
1200                     if (strchr(nv_name(np), '/')) {
1201                         // Disable editors for built-in versions of commands on PATH.
1202                         was_vi = sh_isoption(shp, SH_VI);
1203                         was_emacs = sh_isoption(shp, SH_EMACS);
1204                         was_gmacs = sh_isoption(shp, SH_GMACS);
1205                         sh_offoption(shp, SH_VI);
1206                         sh_offoption(shp, SH_EMACS);
1207                         sh_offoption(shp, SH_GMACS);
1208                     }
1209                     if (execflg) sh_onstate(shp, SH_NOFORK);
1210                     sh_pushcontext(shp, buffp, SH_JMPCMD);
1211                     jmpval = sigsetjmp(buffp->buff, 1);
1212                     if (jmpval == 0) {
1213                         if (!(nv_isattr(np, BLT_ENV))) error_info.flags |= ERROR_SILENT;
1214                         errorpush(&buffp->err, 0);
1215                         if (io) {
1216                             struct openlist *item;
1217                             if (np == SYSEXEC) {
1218                                 type = 1 + !com[1];
1219                             } else {
1220                                 type = (execflg && !shp->subshell && !shp->st.trapcom[0]);
1221                             }
1222                             shp->redir0 = 1;
1223                             sh_redirect(shp, io,
1224                                         type | (FETCH_VT(np->nvalue, shbltinp) == b_source
1225                                                     ? 0
1226                                                     : IOHERESTRING | IOUSEVEX));
1227                             for (item = buffp->olist; item; item = item->next) item->strm = NULL;
1228                         }
1229                         if (!nv_isattr(np, BLT_ENV) && !nv_isattr(np, BLT_SPC)) {
1230                             if (!shp->pwd) {
1231                                 path_pwd(shp);
1232 #if !O_SEARCH
1233                             } else if (shp->pwdfd >= 0) {
1234                                 fstat(shp->pwdfd, &statb);
1235                             } else if (shp->pwd) {
1236                                 stat(e_dot, &statb);
1237 #endif  // O_SEARCH
1238                             }
1239                             sfsync(NULL);
1240                             share = sfset(sfstdin, SF_SHARE, 0);
1241                             sh_onstate(shp, SH_STOPOK);
1242                             sfpool(sfstderr, NULL, SF_WRITE);
1243                             sfset(sfstderr, SF_LINE, 1);
1244                             save_prompt = shp->nextprompt;
1245                             shp->nextprompt = 0;
1246                         }
1247                         if (argp) {
1248                             scope++;
1249                             sh_scope(shp, argp, 0);
1250                         }
1251                         opt_info.index = opt_info.offset = 0;
1252                         opt_info.disc = NULL;
1253                         error_info.id = *com;
1254                         if (argn) shp->exitval = 0;
1255                         shp->bltinfun = funptr(np);
1256                         bp->bnode = np;
1257                         bp->vnode = nq;
1258                         bp->ptr = nv_context(np);
1259                         bp->data = t->com.comstate;
1260                         bp->sigset = 0;
1261                         bp->notify = 0;
1262                         bp->flags = ((flags & ARG_OPTIMIZE) != 0);
1263                         if (shp->subshell && nv_isattr(np, BLT_NOSFIO)) sh_subtmpfile(shp);
1264                         if (execflg && !shp->subshell && !shp->st.trapcom[0] &&
1265                             !shp->st.trap[SH_ERRTRAP] && shp->fn_depth == 0 &&
1266                             !nv_isattr(np, BLT_ENV)) {
1267                             // Do close-on-exec.
1268                             int fd;
1269                             for (fd = 0; fd < shp->gd->lim.open_max; fd++) {
1270                                 if ((shp->fdstatus[fd] & IOCLEX) && fd != shp->infd &&
1271                                     (fd != shp->pwdfd)) {
1272                                     sh_close(fd);
1273                                 }
1274                             }
1275                         }
1276                         if (argn) {
1277                             shp->exitval = (*shp->bltinfun)(argn, com, bp);
1278                             sfsync(NULL);
1279                         }
1280                         if (error_info.flags & ERROR_INTERACTIVE) tty_check(STDERR_FILENO);
1281                         ((Shnode_t *)t)->com.comstate = shp->bltindata.data;
1282                         bp->data = (void *)save_data;
1283                         if (shp->exitval && errno == EINTR && shp->lastsig) {
1284                             shp->exitval = SH_EXITSIG | shp->lastsig;
1285                         } else if (!nv_isattr(np, BLT_EXIT)) {
1286                             shp->exitval &= SH_EXITMASK;
1287                         }
1288                     } else {
1289                         struct openlist *item;
1290                         for (item = buffp->olist; item; item = item->next) {
1291                             if (item->strm) {
1292                                 sfclrlock(item->strm);
1293                                 if (shp->gd->hist_ptr && item->strm == shp->gd->hist_ptr->histfp) {
1294                                     hist_close(shp->gd->hist_ptr);
1295                                 } else {
1296                                     sfclose(item->strm);
1297                                 }
1298                             }
1299                         }
1300                         if (shp->bltinfun && (error_info.flags & ERROR_NOTIFY)) {
1301                             (*shp->bltinfun)(-2, com, bp);
1302                             sfsync(NULL);
1303                         }
1304                         // Failure on special built-ins fatal.
1305                         if (jmpval <= SH_JMPCMD && (!nv_isattr(np, BLT_SPC) || command)) {
1306                             jmpval = 0;
1307                         }
1308                     }
1309 #if USE_SPAWN
1310                     if (np != SYSEXEC && shp->vex->cur) {
1311 #if 1
1312                         spawnvex_apply(shp->vex, 0, SPAWN_RESET | SPAWN_FRAME);
1313 #else
1314                         int fd;
1315                         spawnvex_apply(shp->vex, 0, SPAWN_RESET | SPAWN_FRAME);
1316                         if (shp->comsub && (fd = sffileno(sfstdout)) != 1 && fd >= 0)
1317                             spawnvex_add(shp->vex, fd, 1, 0, 0);
1318 #endif
1319                     }
1320 #endif
1321                     bp->bnode = NULL;
1322                     if (bp->ptr != nv_context(np)) np->nvfun = (Namfun_t *)bp->ptr;
1323                     if (execflg && !was_nofork) sh_offstate(shp, SH_NOFORK);
1324                     if (!(nv_isattr(np, BLT_ENV))) {
1325 #if O_SEARCH
1326                         while ((sh_fchdir(shp->pwdfd) < 0) && errno == EINTR) errno = 0;
1327 #else   // O_SEARCH
1328                         if (shp->pwd || (shp->pwdfd >= 0)) {
1329                             struct stat stata;
1330                             stat(e_dot, &stata);
1331                             // Restore directory changed.
1332                             if (statb.st_ino != stata.st_ino || statb.st_dev != stata.st_dev) {
1333                                 // Chdir for directories on HSM/tapeworms may take minutes.
1334                                 int err = errno;
1335                                 if (shp->pwdfd >= 0) {
1336                                     while ((fchdir(shp->pwdfd) < 0) && errno == EINTR) {
1337                                         errno = err;
1338                                     }
1339                                 } else {
1340                                     while ((chdir(shp->pwd) < 0) && errno == EINTR) errno = err;
1341                                 }
1342                             }
1343                         }
1344 #endif  // O_SEARCH
1345                         sh_offstate(shp, SH_STOPOK);
1346                         if (share & SF_SHARE) sfset(sfstdin, SF_PUBLIC | SF_SHARE, 1);
1347                         sfset(sfstderr, SF_LINE, 0);
1348                         sfpool(sfstderr, shp->outpool, SF_WRITE);
1349                         sfpool(sfstdin, NULL, SF_WRITE);
1350                         shp->nextprompt = save_prompt;
1351                     }
1352                     sh_popcontext(shp, buffp);
1353                     errorpop(&buffp->err);
1354                     error_info.flags &= ~(ERROR_SILENT | ERROR_NOTIFY);
1355                     shp->bltinfun = 0;
1356                     if (buffp->olist) free_list(buffp->olist);
1357                     if (was_vi) {
1358                         sh_onoption(shp, SH_VI);
1359                     } else if (was_emacs) {
1360                         sh_onoption(shp, SH_EMACS);
1361                     } else if (was_gmacs) {
1362                         sh_onoption(shp, SH_GMACS);
1363                     }
1364                     if (scope) sh_unscope(shp);
1365                     bp->ptr = (void *)save_ptr;
1366                     bp->data = (void *)save_data;
1367                     // Don't restore for subshell exec.
1368                     if ((shp->topfd > topfd) && !(shp->subshell && np == SYSEXEC)) {
1369                         sh_iorestore(shp, topfd, jmpval);
1370                     }
1371 #if USE_SPAWN
1372                     if (shp->vexp->cur > vexi) sh_vexrestore(shp, vexi);
1373 #endif
1374                     shp->redir0 = 0;
1375                     if (jmpval) siglongjmp(shp->jmplist->buff, jmpval);
1376                     if (shp->exitval >= 0) goto setexit;
1377                     np = NULL;
1378                     type = 0;
1379                 }
1380                 // Check for functions.
1381                 if (!command && np && nv_isattr(np, NV_FUNCTION)) {
1382                     volatile int indx;
1383                     int jmpval = 0;
1384                     checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
1385                     Namval_t node;
1386                     Namval_t *namespace = NULL;
1387                     struct Namref nr;
1388                     nvflag_t mode;
1389                     struct slnod *slp;
1390                     if (!FETCH_VT(np->nvalue, ip)) {
1391                         indx = path_search(shp, com0, NULL, 0);
1392                         if (indx == 1) {
1393                             if (shp->namespace) {
1394                                 np = sh_fsearch(shp, com0, 0);
1395                             } else {
1396                                 np = nv_search(com0, shp->fun_tree, NV_NOSCOPE);
1397                             }
1398                         }
1399 
1400                         assert(np);  // Coverity CID#253708
1401                         if (!FETCH_VT(np->nvalue, ip)) {
1402                             if (indx == 1) {
1403                                 errormsg(SH_DICT, ERROR_exit(0), e_defined, com0);
1404                                 shp->exitval = ERROR_NOEXEC;
1405                             } else {
1406                                 errormsg(SH_DICT, ERROR_exit(0), e_found, "function");
1407                                 shp->exitval = ERROR_NOENT;
1408                             }
1409                             goto setexit;
1410                         }
1411                     }
1412                     // Increase refcnt for unset.
1413                     slp = (struct slnod *)np->nvenv;
1414                     sh_funstaks(slp->slchild, 1);
1415                     stklink(slp->slptr);
1416                     if (nq) {
1417                         Namval_t *mp = NULL;
1418                         if (nv_isattr(np, NV_STATICF) && (mp = nv_type(nq))) nq = mp;
1419                         shp->last_table = last_table;
1420                         mode = set_instance(shp, nq, &node, &nr);
1421                     }
1422                     if (io) {
1423                         indx = shp->topfd;
1424                         sh_pushcontext(shp, buffp, SH_JMPCMD);
1425                         jmpval = sigsetjmp(buffp->buff, 0);
1426                     }
1427                     if (jmpval == 0) {
1428                         if (io) indx = sh_redirect(shp, io, execflg | IOUSEVEX);
1429                         if (*np->nvname == '.') {
1430                             char *ep;
1431                             bool type = 0;
1432                             cp = np->nvname + 1;
1433                             if (strncmp(cp, "sh.type.", 8) == 0) {
1434                                 cp += 8;
1435                                 type = true;
1436                             }
1437                             ep = strrchr(cp, '.');
1438                             if (ep) {
1439                                 if (type) {
1440                                     while (--ep > cp && *ep != '.') {
1441                                         ;  // empty loop
1442                                     }
1443                                 }
1444                                 *ep = 0;
1445                                 namespace = nv_search(cp - 1, shp->var_base, NV_NOSCOPE);
1446                                 *ep = '.';
1447                             }
1448                         }
1449                         namespace = enter_namespace(shp, namespace);
1450                         sh_funct(shp, np, argn, com, t->com.comset, (flags & ~ARG_OPTIMIZE));
1451                     }
1452                     enter_namespace(shp, namespace);
1453 #if USE_SPAWN
1454                     spawnvex_apply(shp->vex, 0, SPAWN_RESET | SPAWN_FRAME);
1455                     if (shp->vexp->cur > vexi) sh_vexrestore(shp, vexi);
1456 #endif
1457                     if (io) {
1458                         if (buffp->olist) free_list(buffp->olist);
1459                         sh_popcontext(shp, buffp);
1460                         sh_iorestore(shp, indx, jmpval);
1461                     }
1462                     if (nq) unset_instance(nq, &node, &nr, mode);
1463                     sh_funstaks(slp->slchild, -1);
1464                     stkclose(slp->slptr);
1465                     if (jmpval > SH_JMPFUN || (io && jmpval > SH_JMPIO)) {
1466                         siglongjmp(shp->jmplist->buff, jmpval);
1467                     }
1468                     goto setexit;
1469                 }
1470             } else if (!io) {
1471 #if USE_SPAWN
1472                 spawnvex_apply(shp->vex, 0, SPAWN_RESET | SPAWN_FRAME);
1473 #endif
1474             setexit:
1475                 exitset(shp);
1476                 break;
1477             }
1478         }
1479         // FALLTHRU
1480         case TFORK: {
1481             pid_t parent;
1482             bool no_fork;
1483             int jobid;
1484             int pipes[3];
1485 #if USE_SPAWN
1486             bool unpipe = false;
1487 #endif
1488 
1489             if (shp->subshell) {
1490                 sh_subtmpfile(shp);
1491                 if ((type & (FAMP | TFORK)) == (FAMP | TFORK)) {
1492                     if (shp->comsub && !(shp->fdstatus[1] & IONOSEEK)) {
1493                         iousepipe(shp);
1494 #if USE_SPAWN
1495                         unpipe = true;
1496 #endif  // USE_SPAWN
1497                     }
1498                     sh_subfork();
1499                 }
1500             }
1501             no_fork =
1502                 !ntflag && !(type & (FAMP | FPOU)) && !shp->subshell &&
1503                 !(shp->st.trapcom[SIGINT] && *shp->st.trapcom[SIGINT]) && !shp->st.trapcom[0] &&
1504                 !shp->st.trap[SH_ERRTRAP] && shp->jmplist->mode != SH_JMPEVAL &&
1505                 (execflg2 ||
1506                  (execflg && shp->fn_depth == 0 && !(pipejob && sh_isoption(shp, SH_PIPEFAIL))));
1507             if (sh_isstate(shp, SH_PROFILE) || shp->dot_depth) {
1508                 // Disable foreground job monitor.
1509                 if (!(type & FAMP)) {
1510                     sh_offstate(shp, SH_MONITOR);
1511 #if has_dev_fd
1512                 } else if (!(type & FINT)) {
1513                     sh_offstate(shp, SH_MONITOR);
1514 #endif  // has_dev_fd
1515                 }
1516             }
1517             if (no_fork) {
1518                 job.parent = parent = 0;
1519             } else {
1520                 if (((type & (FAMP | FINT)) == (FAMP | FINT)) &&
1521                     (job.maxjob = nv_getnum(VAR_JOBMAX)) > 0) {
1522                     while (job.numbjob >= job.maxjob) {
1523                         job_lock();
1524                         job_reap(0);
1525                         job_unlock();
1526                     }
1527                 }
1528                 nv_getval(VAR_RANDOM);
1529                 restorefd = shp->topfd;
1530 #if USE_SPAWN
1531                 restorevex = shp->vexp->cur;
1532 #endif
1533                 if (type & FCOOP) {
1534                     pipes[2] = 0;
1535                     coproc_init(shp, pipes);
1536                 }
1537 
1538 #if USE_SPAWN
1539                 if (com) {
1540                     parent = sh_ntfork(shp, t, com, &jobid, ntflag);
1541                 } else {
1542                     parent = sh_fork(shp, type, &jobid);
1543                 }
1544 
1545                 if (parent < 0) {
1546 #if USE_SPAWN
1547                     if (shp->comsub == 1 && usepipe && unpipe) sh_iounpipe(shp);
1548 #endif  // USE_SPAWN
1549                     break;
1550                 }
1551 #else   // USE_SPAWN
1552                 parent = sh_fork(shp, type, &jobid);
1553 #endif  // USE_SPAWN
1554             }
1555             job.parent = parent;
1556             if (!job.parent) {
1557                 forked_child(shp, t, flags, type, no_fork, com0, com, parent, topfd, vexi);
1558                 __builtin_unreachable();
1559             }
1560             // This is the parent branch of fork. It may or may not wait for the child.
1561             if (pipejob == 2) {
1562                 pipejob = 1;
1563                 nlock--;
1564                 job_unlock();
1565             }
1566             if (shp->subshell) shp->spid = parent;
1567             if (type & FPCL) sh_close(shp->inpipe[0]);
1568             if (type & (FCOOP | FAMP)) {
1569                 shp->bckpid = parent;
1570             } else if (!(type & (FAMP | FPOU))) {
1571                 if (!sh_isoption(shp, SH_MONITOR)) {
1572                     if (!(shp->sigflag[SIGINT] & (SH_SIGFAULT | SH_SIGOFF))) {
1573                         sh_sigtrap(shp, SIGINT);
1574                     }
1575                     shp->trapnote |= SH_SIGIGNORE;
1576                 }
1577                 if (shp->pipepid) {
1578                     shp->pipepid = parent;
1579                 } else {
1580                     job_wait(parent);
1581                     if (parent == shp->spid) shp->spid = 0;
1582                 }
1583                 if (shp->topfd > topfd) sh_iorestore(shp, topfd, 0);
1584 #if USE_SPAWN
1585                 if (shp->vexp->cur > vexi) sh_vexrestore(shp, vexi);
1586 #endif
1587                 if (usepipe && tsetio && subdup) sh_iounpipe(shp);
1588                 if (!sh_isoption(shp, SH_MONITOR)) {
1589                     shp->trapnote &= ~SH_SIGIGNORE;
1590                     if (shp->exitval == (SH_EXITSIG | SIGINT)) kill(getpid(), SIGINT);
1591                 }
1592             }
1593             if (type & FAMP) {
1594                 if (sh_isstate(shp, SH_PROFILE) || sh_isstate(shp, SH_INTERACTIVE)) {
1595                     /* print job number */
1596 #ifdef JOBS
1597                     sfprintf(sfstderr, "[%d]\t%d\n", jobid, parent);
1598 #else   // JOBS
1599                     sfprintf(sfstderr, "%d\n", parent);
1600 #endif  // JOBS
1601                 }
1602             }
1603             break;
1604         }
1605         case TSETIO: {
1606             // Don't create a new process, just save and restore io-streams.
1607             pid_t pid;
1608             int jmpval, waitall;
1609             int simple = (t->fork.forktre->tre.tretyp & COMMSK) == TCOM;
1610             checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
1611             if (shp->subshell) execflg = 0;
1612             sh_pushcontext(shp, buffp, SH_JMPIO);
1613             if (type & FPIN) {
1614                 was_interactive = sh_isstate(shp, SH_INTERACTIVE);
1615                 sh_offstate(shp, SH_INTERACTIVE);
1616                 shp->pipepid = simple;
1617                 sh_iosave(shp, 0, shp->topfd, NULL);
1618                 sh_iorenumber(shp, shp->inpipe[0], 0);
1619                 // if read end of pipe is a simple command treat as non-sharable to improve
1620                 // performance.
1621                 if (simple) sfset(sfstdin, SF_PUBLIC | SF_SHARE, 0);
1622                 waitall = job.waitall;
1623                 job.waitall = 0;
1624                 pid = job.parent;
1625             } else {
1626                 error_info.line = t->fork.forkline - shp->st.firstline;
1627             }
1628             jmpval = sigsetjmp(buffp->buff, 0);
1629             if (jmpval == 0) {
1630                 if (shp->comsub) tsetio = 1;
1631                 sh_redirect(shp, t->fork.forkio, execflg);
1632                 (t->fork.forktre)->tre.tretyp |= t->tre.tretyp & FSHOWME;
1633                 t = t->fork.forktre;
1634 #if SHOPT_BASH
1635                 if ((t->tre.tretyp & COMMSK) == TCOM && sh_isoption(shp, SH_BASH) &&
1636                     !sh_isoption(shp, SH_LASTPIPE)) {
1637                     Shnode_t *tt = stkalloc(shp->stk, sizeof(Shnode_t));
1638                     tt->par.partyp = type = TPAR;
1639                     tt->par.partre = (Shnode_t *)t;
1640                     t = tt;
1641                 }
1642 #endif  // SHOPT_BASH
1643                 sh_exec(shp, t, flags & ~simple);
1644             } else {
1645                 sfsync(shp->outpool);
1646             }
1647             sh_popcontext(shp, buffp);
1648             sh_iorestore(shp, buffp->topfd, jmpval);
1649 #if USE_SPAWN
1650             if (shp->vexp->cur > vexi) sh_vexrestore(shp, buffp->vexi);
1651 #endif
1652             if (buffp->olist) free_list(buffp->olist);
1653             if (type & FPIN) {
1654                 job.waitall = waitall;
1655                 type = shp->exitval;
1656                 if (!(type & SH_EXITSIG)) {
1657                     // Wait for remainder of pipline.
1658                     if (shp->pipepid > 1 && shp->comsub != 1) {
1659                         job_wait(shp->pipepid);
1660                         type = shp->exitval;
1661                     } else {
1662                         job_wait(waitall ? pid : 0);
1663                     }
1664                     if (type || !sh_isoption(shp, SH_PIPEFAIL)) shp->exitval = type;
1665                 }
1666                 shp->pipepid = 0;
1667                 shp->st.ioset = 0;
1668                 if (simple && was_errexit) {
1669                     echeck = 1;
1670                     sh_onstate(shp, SH_ERREXIT);
1671                 }
1672             }
1673             if (jmpval > SH_JMPIO) siglongjmp(shp->jmplist->buff, jmpval);
1674             break;
1675         }
1676         case TPAR: {
1677             echeck = 1;
1678             flags &= ~ARG_OPTIMIZE;
1679             if (!shp->subshell && !shp->st.trapcom[0] && !shp->st.trap[SH_ERRTRAP] &&
1680                 (flags & sh_state(SH_NOFORK))) {
1681                 char *savsig;
1682                 int nsig, jmpval;
1683                 checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
1684                 shp->st.otrapcom = NULL;
1685 
1686                 nsig = shp->st.trapmax;
1687                 if (nsig > 0 || shp->st.trapcom[0]) {
1688                     int trapcom_size = (shp->st.trapmax + 1) * sizeof(char *);
1689                     savsig = malloc(trapcom_size);
1690                     memcpy(savsig, shp->st.trapcom, trapcom_size);
1691                     shp->st.otrapcom = (char **)savsig;
1692                 }
1693                 sh_sigreset(shp, 0);
1694                 sh_pushcontext(shp, buffp, SH_JMPEXIT);
1695                 jmpval = sigsetjmp(buffp->buff, 0);
1696                 if (jmpval == 0) sh_exec(shp, t->par.partre, flags);
1697                 sh_popcontext(shp, buffp);
1698                 if (jmpval > SH_JMPEXIT) siglongjmp(shp->jmplist->buff, jmpval);
1699                 if (shp->exitval > 256) shp->exitval -= 128;
1700                 sh_done(shp, 0);
1701             } else if (((type = t->par.partre->tre.tretyp) & FAMP) && ((type & COMMSK) == TFORK)) {
1702                 pid_t pid;
1703                 sfsync(NULL);
1704                 while ((pid = fork()) < 0) _sh_fork(shp, pid, 0, 0);
1705                 if (pid == 0) {
1706                     sh_exec(shp, t->par.partre, flags);
1707                     shp->st.trapcom[0] = 0;
1708                     sh_offoption(shp, SH_INTERACTIVE);
1709                     sh_done(shp, 0);
1710                 }
1711             } else {
1712                 sh_subshell(shp, t->par.partre, flags, 0);
1713             }
1714             break;
1715         }
1716         case TFIL: {
1717             // This code sets up a pipe. All elements of the pipe are started by the parent. The
1718             // last element executes in current environment.
1719             int pvo[3];  // old pipe for multi-stage
1720             int pvn[3];  // current set up pipe
1721             int savepipe = pipejob;
1722             int savelock = nlock;
1723             int showme = t->tre.tretyp & FSHOWME;
1724             int n, waitall, savewaitall = job.waitall;
1725             int savejobid = job.curjobid;
1726             int *exitval = NULL, *saveexitval = job.exitval;
1727             pid_t savepgid = job.curpgid;
1728             job.exitval = NULL;
1729             job.curjobid = 0;
1730             if (shp->subshell) {
1731                 sh_subtmpfile(shp);
1732                 if (shp->comsub == 1 && !(shp->fdstatus[1] & IONOSEEK)) iousepipe(shp);
1733             }
1734             shp->inpipe = pvo;
1735             shp->outpipe = pvn;
1736             pvo[1] = -1;
1737             if (sh_isoption(shp, SH_PIPEFAIL)) {
1738                 const Shnode_t *tn = t;
1739                 job.waitall = 2;
1740                 job.curpgid = 0;
1741                 while ((tn = tn->lst.lstrit) && tn->tre.tretyp == TFIL) job.waitall++;
1742                 exitval = job.exitval = stkalloc(shp->stk, job.waitall * sizeof(int));
1743                 memset(exitval, 0, job.waitall * sizeof(int));
1744             } else {
1745                 job.waitall |= !pipejob && sh_isstate(shp, SH_MONITOR);
1746             }
1747             job_lock();
1748             nlock++;
1749             do {
1750                 // Create the pipe.
1751                 sh_pipe(pvn);
1752                 // Execute out part of pipe no wait.
1753                 (t->lst.lstlef)->tre.tretyp |= showme;
1754                 type = sh_exec(shp, t->lst.lstlef, errorflg);
1755                 // Close out-part of pipe.
1756                 sh_close(pvn[1]);
1757                 pipejob = 1;
1758                 // Save the pipe stream-ids.
1759                 pvo[0] = pvn[0];
1760                 // Pipeline all in one process group.
1761                 t = t->lst.lstrit;
1762             }
1763             // Repeat until end of pipeline.
1764             while (!type && t->tre.tretyp == TFIL);
1765             shp->inpipe = pvn;
1766             shp->outpipe = NULL;
1767             pipejob = 2;
1768             waitall = job.waitall;
1769             job.waitall = 0;
1770             if (type == 0) {
1771                 // Execute last element of pipeline in the current process.
1772                 ((Shnode_t *)t)->tre.tretyp |= showme;
1773                 sh_exec(shp, t, flags);
1774             } else {
1775                 // Execution failure, close pipe.
1776                 sh_pclose(pvn);
1777             }
1778             if (pipejob == 2) job_unlock();
1779             if ((pipejob = savepipe) && nlock < savelock) pipejob = 1;
1780             n = shp->exitval;
1781             job.waitall = waitall;
1782             if (job.waitall) {
1783                 if (sh_isstate(shp, SH_MONITOR)) {
1784                     job_wait(0);
1785                 } else {
1786                     shp->intrap++;
1787                     job_wait(0);
1788                     shp->intrap--;
1789                 }
1790             }
1791             if (n == 0 && exitval) {
1792                 while (exitval <= --job.exitval) {
1793                     if (*job.exitval) {
1794                         n = *job.exitval;
1795                         break;
1796                     }
1797                 }
1798             }
1799             shp->exitval = n;
1800 #ifdef SIGTSTP
1801             if (!pipejob && sh_isstate(shp, SH_MONITOR) && sh_isoption(shp, SH_INTERACTIVE)) {
1802                 tcsetpgrp(JOBTTY, shp->gd->pid);
1803             }
1804 #endif  // SIGTSTP
1805             job.curpgid = savepgid;
1806             job.exitval = saveexitval;
1807             job.waitall = savewaitall;
1808             job.curjobid = savejobid;
1809             break;
1810         }
1811         case TLST: {
1812             // A list of commands are executed here.
1813             do {
1814                 sh_exec(shp, t->lst.lstlef, errorflg | (flags & ARG_OPTIMIZE));
1815                 t = t->lst.lstrit;
1816             } while (t->tre.tretyp == TLST);
1817             sh_exec(shp, t, flags);
1818             break;
1819         }
1820         case TAND: {
1821             if (type & TTEST) skipexitset++;
1822             if (sh_exec(shp, t->lst.lstlef, (flags & ARG_OPTIMIZE)) == 0) {
1823                 sh_exec(shp, t->lst.lstrit, flags);
1824             }
1825             break;
1826         }
1827         case TORF: {
1828             if (type & TTEST) skipexitset++;
1829             if (sh_exec(shp, t->lst.lstlef, flags & ARG_OPTIMIZE) != 0) {
1830                 sh_exec(shp, t->lst.lstrit, flags);
1831             }
1832             break;
1833         }
1834         case TFOR: {  // for and select
1835             char **args;
1836             int nargs;
1837             Namval_t *np;
1838             int flag = errorflg | ARG_OPTIMIZE;
1839             struct dolnod *argsav = NULL;
1840             struct comnod *tp;
1841             char *trap;
1842             char *nullptr = NULL;
1843             int nameref, refresh = 1;
1844             char *av[5];
1845             int jmpval = shp->jmplist->mode;
1846             checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
1847             void *optlist = shp->optlist;
1848             shp->optlist = NULL;
1849             sh_tclear(shp, t->for_.fortre);
1850             sh_pushcontext(shp, buffp, jmpval);
1851             jmpval = sigsetjmp(buffp->buff, 0);
1852             if (jmpval) goto endfor;
1853             error_info.line = t->for_.forline - shp->st.firstline;
1854             if (!(tp = t->for_.forlst)) {
1855                 args = shp->st.dolv + 1;
1856                 nargs = shp->st.dolc;
1857                 argsav = sh_arguse(shp);
1858             } else {
1859                 args = sh_argbuild(shp, &argn, tp, 0);
1860                 nargs = argn;
1861             }
1862             np = nv_open(t->for_.fornam, shp->var_tree, NV_NOARRAY | NV_VARNAME | NV_NOREF);
1863             nameref = nv_isref(np) != 0;
1864             shp->st.loopcnt++;
1865             cp = *args;
1866             while (cp && shp->st.execbrk == 0) {
1867                 if (t->tre.tretyp & COMSCAN) {
1868                     char *val;
1869                     int save_prompt;
1870                     // Reuse.
1871                     if (refresh) {
1872                         sh_menu(shp, sfstderr, nargs, args);
1873                         refresh = 0;
1874                     }
1875                     save_prompt = shp->nextprompt;
1876                     shp->nextprompt = 3;
1877                     shp->timeout = 0;
1878                     shp->exitval =
1879                         sh_readline(shp, &nullptr, NULL, 0, 1, (size_t)0, 1000 * shp->st.tmout);
1880                     shp->nextprompt = save_prompt;
1881                     if (shp->exitval || sfeof(sfstdin) || sferror(sfstdin)) {
1882                         shp->exitval = 1;
1883                         break;
1884                     }
1885                     if (!(val = nv_getval(sh_scoped(shp, VAR_REPLY)))) {
1886                         continue;
1887                     } else {
1888                         if (*(cp = val) == 0) {
1889                             refresh++;
1890                             goto check;
1891                         }
1892                         while ((type = *cp++)) {
1893                             if (type < '0' && type > '9') break;
1894                         }
1895                         if (type != 0) {
1896                             type = nargs;
1897                         } else {
1898                             type = (int)strtol(val, NULL, 10) - 1;
1899                         }
1900                         if (type < 0 || type >= nargs) {
1901                             cp = "";
1902                         } else {
1903                             cp = args[type];
1904                         }
1905                     }
1906                 }
1907                 if (nameref) {
1908                     nv_offattr(np, NV_REF | NV_TABLE);
1909                 } else if (nv_isattr(np, NV_ARRAY)) {
1910                     nv_putsub(np, NULL, 0L, 0);
1911                 }
1912                 nv_putval(np, cp, 0);
1913                 if (nameref) {
1914                     nv_setref(np, NULL, NV_VARNAME);
1915                     nv_onattr(np, NV_TABLE);
1916                 }
1917                 trap = shp->st.trap[SH_DEBUGTRAP];
1918                 if (trap) {
1919                     av[0] = (t->tre.tretyp & COMSCAN) ? "select" : "for";
1920                     av[1] = t->for_.fornam;
1921                     av[2] = "in";
1922                     av[3] = cp;
1923                     av[4] = 0;
1924                     sh_debug(shp, trap, NULL, NULL, av, 0);
1925                 }
1926                 sh_exec(shp, t->for_.fortre, flag);
1927                 flag &= ~ARG_OPTIMIZE;
1928                 if (t->tre.tretyp & COMSCAN) {
1929                     if ((cp = nv_getval(sh_scoped(shp, VAR_REPLY))) && *cp == 0) refresh++;
1930                 } else {
1931                     cp = *++args;
1932                 }
1933             check:
1934                 if (shp->st.breakcnt < 0) shp->st.execbrk = (++shp->st.breakcnt != 0);
1935             }
1936             if (nameref) nv_offattr(np, NV_TABLE);
1937         endfor:
1938             sh_popcontext(shp, buffp);
1939             sh_tclear(shp, t->for_.fortre);
1940             sh_optclear(shp, optlist);
1941             if (jmpval) siglongjmp(shp->jmplist->buff, jmpval);
1942             if (shp->st.breakcnt > 0) shp->st.execbrk = (--shp->st.breakcnt != 0);
1943             shp->st.loopcnt--;
1944             sh_argfree(shp, argsav);
1945             nv_close(np);
1946             break;
1947         }
1948         case TWH: {  // while and until
1949             volatile int r = 0;
1950             int first = ARG_OPTIMIZE;
1951             Shnode_t *tt = t->wh.whtre;
1952             Sfio_t *iop = NULL;
1953             int savein;
1954             int jmpval = shp->jmplist->mode;
1955             checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
1956             void *optlist = shp->optlist;
1957             shp->optlist = NULL;
1958             sh_tclear(shp, t->wh.whtre);
1959             sh_tclear(shp, t->wh.dotre);
1960             sh_pushcontext(shp, buffp, jmpval);
1961             jmpval = sigsetjmp(buffp->buff, 0);
1962             if (jmpval) goto endwhile;
1963             if (type == TWH && tt->tre.tretyp == TCOM && !tt->com.comarg && tt->com.comio) {
1964                 iop = openstream(shp, tt->com.comio, &savein);
1965                 if (tt->com.comset) sh_setlist(shp, tt->com.comset, NV_IDENT | NV_ASSIGN, 0);
1966             }
1967             shp->st.loopcnt++;
1968             while (shp->st.execbrk == 0) {
1969                 if (iop) {
1970                     if (!(shp->cur_line = sfgetr(iop, '\n', SF_STRING))) break;
1971                 } else if ((sh_exec(shp, tt, first) == 0) != (type == TWH)) {
1972                     break;
1973                 }
1974                 r = sh_exec(shp, t->wh.dotre, first | errorflg);
1975                 if (shp->st.breakcnt < 0) shp->st.execbrk = (++shp->st.breakcnt != 0);
1976                 // This is for the arithmetic for.
1977                 if (shp->st.execbrk == 0 && t->wh.whinc) {
1978                     sh_exec(shp, (Shnode_t *)t->wh.whinc, first);
1979                 }
1980                 first = 0;
1981                 errorflg &= ~ARG_OPTIMIZE;
1982                 shp->offsets[0] = -1;
1983                 shp->offsets[1] = 0;
1984             }
1985         endwhile:
1986             sh_popcontext(shp, buffp);
1987             sh_tclear(shp, t->wh.whtre);
1988             sh_tclear(shp, t->wh.dotre);
1989             sh_optclear(shp, optlist);
1990             if (jmpval) siglongjmp(shp->jmplist->buff, jmpval);
1991             if (shp->st.breakcnt > 0) shp->st.execbrk = (--shp->st.breakcnt != 0);
1992             shp->st.loopcnt--;
1993             shp->exitval = r;
1994             if (iop) {
1995                 int err = errno;
1996                 sfclose(iop);
1997                 while (close(0) < 0 && errno == EINTR) errno = err;
1998                 int dup_fd = dup(savein);  // it has to return zero
1999                 assert(dup_fd == 0);
2000                 shp->cur_line = NULL;
2001             }
2002             break;
2003         }
2004         case TARITH: {  // (( expression ))
2005             char *trap;
2006             char *arg[4];
2007             error_info.line = t->ar.arline - shp->st.firstline;
2008             arg[0] = "((";
2009             if (!(t->ar.arexpr->argflag & ARG_RAW)) {
2010                 arg[1] = sh_macpat(shp, t->ar.arexpr, (flags & ARG_OPTIMIZE) | ARG_ARITH);
2011             } else {
2012                 arg[1] = t->ar.arexpr->argval;
2013             }
2014             arg[2] = "))";
2015             arg[3] = 0;
2016             trap = shp->st.trap[SH_DEBUGTRAP];
2017             if (trap) {
2018                 sh_debug(shp, trap, NULL, NULL, arg, ARG_ARITH);
2019             }
2020             if (sh_isoption(shp, SH_XTRACE)) {
2021                 sh_trace(shp, NULL, 0);
2022                 sfprintf(sfstderr, "((%s))\n", arg[1]);
2023             }
2024             if (t->ar.arcomp) {
2025                 shp->exitval = !arith_exec((Arith_t *)t->ar.arcomp);
2026             } else {
2027                 shp->exitval = !sh_arith(shp, arg[1]);
2028             }
2029             break;
2030         }
2031         case TIF: {
2032             if (sh_exec(shp, t->if_.iftre, flags & ARG_OPTIMIZE) == 0) {
2033                 sh_exec(shp, t->if_.thtre, flags);
2034             } else if (t->if_.eltre) {
2035                 sh_exec(shp, t->if_.eltre, flags);
2036             } else {
2037                 shp->exitval = 0;  // force zero exit for if-then-fi
2038             }
2039             break;
2040         }
2041         case TSW: {
2042             Shnode_t *tt = (Shnode_t *)t;
2043             char *trap, *r = sh_macpat(shp, tt->sw.swarg, flags & ARG_OPTIMIZE);
2044             error_info.line = t->sw.swline - shp->st.firstline;
2045             t = (Shnode_t *)(tt->sw.swlst);
2046             trap = shp->st.trap[SH_DEBUGTRAP];
2047             if (trap) {
2048                 char *av[4];
2049                 av[0] = "case";
2050                 av[1] = r;
2051                 av[2] = "in";
2052                 av[3] = 0;
2053                 sh_debug(shp, trap, NULL, NULL, av, 0);
2054             }
2055             while (t) {
2056                 struct argnod *rex = (struct argnod *)t->reg.regptr;
2057                 while (rex) {
2058                     char *s;
2059                     if (rex->argflag & ARG_MAC) {
2060                         s = sh_macpat(shp, rex, (flags & ARG_OPTIMIZE) | ARG_EXP | ARG_CASE);
2061                         while (*s == '\\' && s[1] == 0) s += 2;
2062                     } else {
2063                         s = rex->argval;
2064                     }
2065                     type = (rex->argflag & ARG_RAW);
2066                     if ((type && strcmp(r, s) == 0) || (!type && strmatch(r, s))) {
2067                         do {
2068                             sh_exec(shp, t->reg.regcom,
2069                                     (t->reg.regflag ? (flags & sh_state(SH_ERREXIT)) : flags));
2070                         } while (t->reg.regflag && (t = (Shnode_t *)t->reg.regnxt));
2071                         t = 0;
2072                         break;
2073                     } else {
2074                         rex = rex->argnxt.ap;
2075                     }
2076                 }
2077                 if (t) t = (Shnode_t *)t->reg.regnxt;
2078             }
2079             break;
2080         }
2081         case TTIME: {  // time the command
2082             const char *format = e_timeformat;
2083             struct timeval ta, tb, tm[3];
2084             struct timeval before_usr, before_sys, after_usr, after_sys;
2085 
2086             if (type != TTIME) {
2087                 sh_exec(shp, t->par.partre, flags & ARG_OPTIMIZE);
2088                 shp->exitval = !shp->exitval;
2089                 break;
2090             }
2091             gettimeofday(&tb, NULL);
2092             get_cpu_times(&before_usr, &before_sys);
2093             if (t->par.partre) {
2094                 if (shp->subshell && shp->comsub == 1) sh_subfork();
2095                 long timer_on = sh_isstate(shp, SH_TIMING);
2096                 job.waitall = 1;
2097                 sh_onstate(shp, SH_TIMING);
2098                 sh_exec(shp, t->par.partre, flags & ARG_OPTIMIZE);
2099                 if (!timer_on) sh_offstate(shp, SH_TIMING);
2100                 job.waitall = 0;
2101             }
2102             get_cpu_times(&after_usr, &after_sys);
2103             gettimeofday(&ta, NULL);
2104             timersub(&ta, &tb, &tm[TM_REAL_IDX]);  // calculate elapsed real-time
2105             timersub(&after_usr, &before_usr, &tm[TM_USR_IDX]);
2106             timersub(&after_sys, &before_sys, &tm[TM_SYS_IDX]);
2107 
2108             if (t->par.partre) {
2109                 Namval_t *np = nv_open("TIMEFORMAT", shp->var_tree, NV_NOADD);
2110                 if (np) {
2111                     format = nv_getval(np);
2112                     nv_close(np);
2113                 }
2114                 if (!format) format = e_timeformat;
2115             } else {
2116                 format = strchr(format + 1, '\n') + 1;
2117             }
2118             if (format && *format) p_time(shp, sfstderr, sh_translate(format), tm);
2119             break;
2120         }
2121         case TFUN: {
2122             Namval_t *np = NULL;
2123             struct slnod *slp;
2124             char *fname = ((struct functnod *)t)->functnam;
2125             Namval_t *npv = 0, *mp;
2126             cp = strrchr(fname, '.');
2127             if (t->tre.tretyp == TNSPACE) {
2128                 Namval_t *oldnspace = NULL;
2129                 int offset = stktell(stkp);
2130                 nvflag_t nvflags = NV_NOARRAY | NV_VARNAME;
2131                 char *sp, *xp;
2132                 sfputc(stkp, '.');
2133                 sfputr(stkp, fname, 0);
2134                 xp = stkptr(stkp, offset);
2135                 for (sp = xp + 1; sp;) {
2136                     sp = strchr(sp, '.');
2137                     if (sp) *sp = 0;
2138                     np = nv_open(xp, shp->var_tree, nvflags);
2139                     if (sp) *sp++ = '.';
2140                 }
2141                 if (!nv_istable(np)) {
2142                     Dt_t *root = dtopen(&_Nvdisc, Dtoset);
2143                     dtuserdata(root, shp, 1);
2144                     nv_mount(np, NULL, root);
2145                     STORE_VT(np->nvalue, const_cp, Empty);
2146                     dtview(root, shp->var_base);
2147                 }
2148                 oldnspace = enter_namespace(shp, np);
2149                 sh_exec(shp, t->for_.fortre, nvflags | sh_state(SH_ERREXIT));
2150                 enter_namespace(shp, oldnspace);
2151                 break;
2152             }
2153             // Look for discipline functions.
2154             error_info.line = t->funct.functline - shp->st.firstline;
2155             // Function names cannot be special builtin.
2156             if (cp || shp->prefix) {
2157                 int offset = stktell(stkp);
2158                 if (shp->prefix) {
2159                     cp = shp->prefix;
2160                     shp->prefix = NULL;
2161                     npv = nv_open(cp, shp->var_tree, NV_NOARRAY | NV_VARNAME);
2162                     shp->prefix = cp;
2163                     cp = fname;
2164                 } else {
2165                     sfwrite(stkp, fname, cp++ - fname);
2166                     sfputc(stkp, 0);
2167                     npv = nv_open(stkptr(stkp, offset), shp->var_tree, NV_NOARRAY | NV_VARNAME);
2168                 }
2169                 offset = stktell(stkp);
2170                 sfprintf(stkp, "%s.%s%c", nv_name(npv), cp, 0);
2171                 fname = stkptr(stkp, offset);
2172             } else if ((mp = nv_search(fname, shp->bltin_tree, 0)) && nv_isattr(mp, BLT_SPC)) {
2173                 errormsg(SH_DICT, ERROR_exit(1), e_badfun, fname);
2174                 __builtin_unreachable();
2175             }
2176             if (shp->namespace && !shp->prefix && *fname != '.') {
2177                 np = sh_fsearch(shp, fname, NV_ADD | NV_NOSCOPE);
2178             }
2179             if (!np) {
2180                 np = nv_open(fname, sh_subfuntree(shp, true), NV_NOARRAY | NV_VARNAME | NV_NOSCOPE);
2181             }
2182             if (npv) {
2183                 if (!shp->mktype) cp = nv_setdisc(npv, cp, np, (Namfun_t *)npv);
2184                 if (!cp) {
2185                     errormsg(SH_DICT, ERROR_exit(1), e_baddisc, fname);
2186                     __builtin_unreachable();
2187                 }
2188             }
2189             if (FETCH_VT(np->nvalue, rp)) {
2190                 struct Ufunction *rp = FETCH_VT(np->nvalue, rp);
2191                 slp = (struct slnod *)np->nvenv;
2192                 sh_funstaks(slp->slchild, -1);
2193                 stkclose(slp->slptr);
2194                 if (rp->sdict) {
2195                     Namval_t *nq;
2196                     shp->last_root = rp->sdict;
2197                     for (mp = dtfirst(rp->sdict); mp; mp = nq) {
2198                         _nv_unset(mp, NV_RDONLY);
2199                         nq = dtnext(rp->sdict, mp);
2200                         nv_delete(mp, rp->sdict, 0);
2201                     }
2202                     dtclose(rp->sdict);
2203                     rp->sdict = NULL;
2204                 }
2205                 if (shp->funload) {
2206                     if (!shp->fpathdict) free(FETCH_VT(np->nvalue, rp));
2207                     STORE_VT(np->nvalue, rp, NULL);
2208                 }
2209             }
2210             if (!FETCH_VT(np->nvalue, rp)) {
2211                 struct Ufunction *rp =
2212                     calloc(1, sizeof(struct Ufunction) + (shp->funload ? sizeof(Dtlink_t) : 0));
2213                 STORE_VT(np->nvalue, rp, rp);
2214             }
2215             if (t->funct.functstak) {
2216                 static Dtdisc_t _Rpdisc = {.key = offsetof(struct Ufunction, fname),
2217                                            .size = -1,
2218                                            .link = sizeof(struct Ufunction)};
2219                 struct functnod *fp;
2220                 struct comnod *ac = t->funct.functargs;
2221                 slp = t->funct.functstak;
2222                 sh_funstaks(slp->slchild, 1);
2223                 stklink(slp->slptr);
2224                 np->nvenv = (Namval_t *)slp;
2225                 nv_funtree(np) = (int *)(t->funct.functtre);
2226                 FETCH_VT(np->nvalue, rp)->hoffset = t->funct.functloc;
2227                 FETCH_VT(np->nvalue, rp)->lineno = t->funct.functline;
2228                 FETCH_VT(np->nvalue, rp)->nspace = shp->namespace;
2229                 FETCH_VT(np->nvalue, rp)->fname = NULL;
2230                 FETCH_VT(np->nvalue, rp)->argv = ac ? ((struct dolnod *)ac->comarg)->dolval + 1 : 0;
2231                 FETCH_VT(np->nvalue, rp)->argc = ac ? ((struct dolnod *)ac->comarg)->dolnum : 0;
2232                 FETCH_VT(np->nvalue, rp)->fdict = shp->fun_tree;
2233                 fp = (struct functnod *)(slp + 1);
2234                 if (fp->functtyp == (TFUN | FAMP)) FETCH_VT(np->nvalue, rp)->fname = fp->functnam;
2235                 nv_setsize(np, fp->functline);
2236                 nv_offattr(np, NV_FPOSIX);
2237                 if (shp->funload) {
2238                     struct Ufunction *rp = FETCH_VT(np->nvalue, rp);
2239                     rp->np = np;
2240                     if (!shp->fpathdict) shp->fpathdict = dtopen(&_Rpdisc, Dtobag);
2241                     if (shp->fpathdict) {
2242                         dtuserdata(shp->fpathdict, shp, 1);
2243                         dtinsert(shp->fpathdict, rp);
2244                     }
2245                 }
2246             } else {
2247                 _nv_unset(np, 0);
2248             }
2249             if (type & FPOSIX) {
2250                 nv_onattr(np, NV_FUNCTION | NV_FPOSIX);
2251             } else {
2252                 nv_onattr(np, NV_FUNCTION);
2253             }
2254             if (type & FPIN) nv_onattr(np, NV_FTMP);
2255             if (type & FOPTGET) nv_onattr(np, NV_OPTGET);
2256             if (type & FSHVALUE) nv_onattr(np, NV_SHVALUE);
2257             break;
2258         }
2259         case TTST: {  // new test compound command
2260             int n;
2261             char *left;
2262             int negate = (type & TNEGATE) != 0;
2263             if (type & TTEST) skipexitset++;
2264             error_info.line = t->tst.tstline - shp->st.firstline;
2265             echeck = 1;
2266             if ((type & TPAREN) == TPAREN) {
2267                 sh_exec(shp, t->lst.lstlef, flags & ARG_OPTIMIZE);
2268                 n = !shp->exitval;
2269             } else {
2270                 bool traceon = 0;
2271                 char *right;
2272                 char *trap;
2273                 char *argv[6];
2274                 int savexit = shp->savexit;
2275                 n = type >> TSHIFT;
2276                 left = sh_macpat(shp, &(t->lst.lstlef->arg), flags & ARG_OPTIMIZE);
2277                 if (type & TBINARY) {
2278                     right = sh_macpat(
2279                         shp, &(t->lst.lstrit->arg),
2280                         ((n == TEST_PEQ || n == TEST_PNE) ? ARG_EXP : 0) | (flags & ARG_OPTIMIZE));
2281                 }
2282                 shp->savexit = savexit;
2283                 trap = shp->st.trap[SH_DEBUGTRAP];
2284                 if (trap) {
2285                     argv[0] = (type & TNEGATE) ? ((char *)e_tstbegin) : "[[";
2286                 }
2287                 if (sh_isoption(shp, SH_XTRACE)) {
2288                     traceon = sh_trace(shp, NULL, 0);
2289                     sfwrite(sfstderr, e_tstbegin, (type & TNEGATE ? 5 : 3));
2290                 }
2291                 if (type & TUNARY) {
2292                     if (traceon) sfprintf(sfstderr, "-%c %s", n, sh_fmtq(left));
2293                     if (trap) {
2294                         char unop[3];
2295                         unop[0] = '-';
2296                         unop[1] = n;
2297                         unop[2] = 0;
2298                         argv[1] = unop;
2299                         argv[2] = left;
2300                         argv[3] = "]]";
2301                         argv[4] = 0;
2302                         sh_debug(shp, trap, NULL, NULL, argv, 0);
2303                     }
2304                     n = test_unop(shp, n, left);
2305                 } else if (type & TBINARY) {
2306                     char *op;
2307                     int pattern = 0;
2308                     if (trap || traceon) op = (char *)(shtab_testops + (n & 037) - 1)->sh_name;
2309                     type >>= TSHIFT;
2310                     if (type == TEST_PEQ || type == TEST_PNE) pattern = ARG_EXP;
2311                     if (trap) {
2312                         argv[1] = left;
2313                         argv[2] = op;
2314                         argv[3] = right;
2315                         argv[4] = "]]";
2316                         argv[5] = 0;
2317                         sh_debug(shp, trap, NULL, NULL, argv, pattern);
2318                     }
2319                     n = test_binop(shp, n, left, right);
2320                     if (traceon) {
2321                         sfprintf(sfstderr, "%s %s ", sh_fmtq(left), op);
2322                         if (pattern) {
2323                             out_pattern(sfstderr, right, -1);
2324                         } else {
2325                             sfputr(sfstderr, sh_fmtq(right), -1);
2326                         }
2327                     }
2328                 }
2329                 if (traceon) sfwrite(sfstderr, e_tstend, 4);
2330             }
2331             shp->exitval = ((!n) ^ negate);
2332             if (!skipexitset) exitset(shp);
2333             break;
2334         }
2335         default: { break; }
2336     }
2337 
2338     if (procsub && *procsub) {
2339         pid_t pid;
2340         int exitval = shp->exitval;
2341         while ((pid = *procsub++)) job_wait(pid);
2342         shp->exitval = exitval;
2343     }
2344     if (shp->trapnote || (shp->exitval && sh_isstate(shp, SH_ERREXIT) && t && echeck)) {
2345         sh_chktrap(shp);
2346     }
2347     // Set $_.
2348     if (mainloop && com0) {
2349         // Store last argument here if it fits.
2350         static char lastarg[PATH_MAX];
2351         if (sh_isstate(shp, SH_FORKED)) sh_done(shp, 0);
2352         if (shp->lastarg != lastarg && shp->lastarg) free(shp->lastarg);
2353         // Although this node is marked as NV_NOFREE, it should get free'd above when $_ is
2354         // reset
2355         nv_onattr(VAR_underscore, NV_NOFREE);
2356         if (strlen(comn) < sizeof(lastarg)) {
2357             shp->lastarg = strcpy(lastarg, comn);
2358         } else {
2359             shp->lastarg = strdup(comn);
2360         }
2361     }
2362     if (!skipexitset) exitset(shp);
2363     if (!(flags & ARG_OPTIMIZE)) {
2364         if (sav != stkptr(stkp, 0)) {
2365             stkset(stkp, sav, 0);
2366         } else if (stktell(stkp)) {
2367             stkseek(stkp, 0);
2368         }
2369     }
2370     if (shp->trapnote & SH_SIGSET) sh_exit(shp, SH_EXITSIG | shp->lastsig);
2371     if (was_interactive) sh_onstate(shp, SH_INTERACTIVE);
2372     if (was_monitor && sh_isoption(shp, SH_MONITOR)) sh_onstate(shp, SH_MONITOR);
2373     if (was_errexit) sh_onstate(shp, SH_ERREXIT);
2374 
2375     return shp->exitval;
2376 }
2377 
2378 //
2379 // Print out the command line if set -x is on.
2380 //
sh_trace(Shell_t * shp,char * argv[],int nl)2381 bool sh_trace(Shell_t *shp, char *argv[], int nl) {
2382     char *cp;
2383     int bracket = 0;
2384     int decl = (nl & 2);
2385     nl &= ~2;
2386     if (sh_isoption(shp, SH_XTRACE)) {
2387         // Make this trace atomic.
2388         sfset(sfstderr, SF_SHARE | SF_PUBLIC, 0);
2389         if (!(cp = nv_getval(sh_scoped(shp, VAR_PS4)))) {
2390             cp = "+ ";
2391         } else {
2392             shp->intrace = 1;
2393             sh_offoption(shp, SH_XTRACE);
2394             cp = sh_mactry(shp, cp);
2395             sh_onoption(shp, SH_XTRACE);
2396             shp->intrace = 0;
2397         }
2398         if (*cp) sfputr(sfstderr, cp, -1);
2399         if (argv) {
2400             char *argv0 = *argv;
2401             nl = (nl ? '\n' : -1);
2402             // Don't quote [ and [[.
2403             cp = argv[0];
2404             if (*cp == '[' && (!cp[1] || (!cp[2] && cp[1] == '['))) {
2405                 sfputr(sfstderr, cp, *++argv ? ' ' : nl);
2406                 bracket = 1;
2407             }
2408             while ((cp = *argv++)) {
2409                 if (bracket == 0 || *argv || *cp != ']') cp = sh_fmtq(cp);
2410                 if (decl && shp->prefix && cp != argv0 && *cp != '-') {
2411                     if (*cp == '.' && cp[1] == 0) {
2412                         cp = shp->prefix;
2413                     } else {
2414                         sfputr(sfstderr, shp->prefix, '.');
2415                     }
2416                 }
2417                 sfputr(sfstderr, cp, *argv ? ' ' : nl);
2418             }
2419             sfset(sfstderr, SF_SHARE | SF_PUBLIC, 1);
2420         }
2421         return true;
2422     }
2423     return false;
2424 }
2425 
2426 //
2427 // This routine creates a subshell by calling fork().
2428 // If ((flags&COMASK)==TCOM), then fork() is permitted.
2429 // If fork fails, the shell sleeps for exponentially longer periods
2430 //   and tries again until a limit is reached.
2431 // SH_FORKLIM is the max period between forks - power of 2 usually.
2432 // Currently shell tries after 2,4,8,16, and 32 seconds and then quits
2433 // Failures cause the routine to error exit.
2434 // Parent links to here-documents are removed by the child.
2435 // Traps are reset by the child.
2436 // The process-id of the child is returned to the parent, 0 to the child.
2437 //
timed_out(void * handle)2438 static_fn void timed_out(void *handle) {
2439     UNUSED(handle);
2440     timeout = NULL;
2441 }
2442 
2443 //
2444 // Called by parent and child after fork by sh_fork().
2445 //
_sh_fork(Shell_t * shp,pid_t parent,int flags,int * jobid)2446 pid_t _sh_fork(Shell_t *shp, pid_t parent, int flags, int *jobid) {
2447     static long forkcnt = 1000L;
2448     pid_t curpgid = job.curpgid;
2449     pid_t postid = (flags & FAMP) ? 0 : curpgid;
2450     int sig, nochild;
2451 
2452     if (parent < 0) {
2453         sh_sigcheck(shp);
2454         forkcnt *= 2;
2455         if (forkcnt > 1000L * SH_FORKLIM) {
2456             forkcnt = 1000L;
2457             errormsg(SH_DICT, ERROR_system(ERROR_NOEXEC), e_nofork);
2458             __builtin_unreachable();
2459         }
2460         timeout = sh_timeradd(forkcnt, 0, timed_out, NULL);
2461         nochild = job_wait((pid_t)1);
2462         if (timeout) {
2463             if (nochild) {
2464                 pause();
2465             } else if (forkcnt > 1000L) {
2466                 forkcnt /= 2;
2467             }
2468             timerdel(timeout);
2469             timeout = NULL;
2470         }
2471         return -1;
2472     }
2473     forkcnt = 1000L;
2474     if (parent) {
2475         int myjob, waitall = job.waitall;
2476         shp->gd->nforks++;
2477         if (job.toclear) job_clear(shp);
2478         job.waitall = waitall;
2479 #ifdef JOBS
2480         // First process defines process group.
2481         if (sh_isstate(shp, SH_MONITOR)) {
2482             // errno==EPERM means that an earlier processes completed.  Make parent the job group
2483             // id.
2484             if (postid == 0) job.curpgid = job.jobcontrol ? parent : getpid();
2485             if (job.jobcontrol || (flags & FAMP)) {
2486                 if (setpgid(parent, job.curpgid) < 0 && errno == EPERM) setpgid(parent, parent);
2487             }
2488         }
2489 #endif  // JOBS
2490         if (!sh_isstate(shp, SH_MONITOR) && job.waitall && postid == 0) job.curpgid = parent;
2491         if (flags & FCOOP) shp->cpid = parent;
2492         if (!postid && job.curjobid && (flags & FPOU)) postid = job.curpgid;
2493         if (!postid && (flags & (FAMP | FINT)) == (FAMP | FINT)) postid = 1;
2494         myjob = job_post(shp, parent, postid);
2495         if (job.waitall && (flags & FPOU)) {
2496             if (!job.curjobid) job.curjobid = myjob;
2497             if (job.exitval) job.exitval++;
2498         }
2499         if (flags & FAMP) job.curpgid = curpgid;
2500         if (jobid) *jobid = myjob;
2501         if (shp->comsub == 1 && usepipe) {
2502             if (!tsetio || !subdup) {
2503 #if USE_SPAWN
2504                 if (shp->vexp->cur > restorevex) sh_vexrestore(shp, restorevex);
2505 #endif
2506                 if (shp->topfd > restorefd) sh_iorestore(shp, restorefd, 0);
2507                 sh_iounpipe(shp);
2508             }
2509         }
2510         return parent;
2511     }
2512     shp->outpipepid = ((flags & FPOU) ? getpid() : 0);
2513     // This is the child process.
2514     if (shp->trapnote & SH_SIGTERM) sh_exit(shp, SH_EXITSIG | SIGTERM);
2515     shp->gd->nforks = 0;
2516     timerdel(NULL);
2517 #ifdef JOBS
2518     if (!job.jobcontrol && !(flags & FAMP)) sh_offstate(shp, SH_MONITOR);
2519     if (sh_isstate(shp, SH_MONITOR)) {
2520         parent = getpid();
2521         if (postid == 0) job.curpgid = parent;
2522         while (setpgid(0, job.curpgid) < 0 && job.curpgid != parent) job.curpgid = parent;
2523 #ifdef SIGTSTP
2524         if (job.curpgid == parent && !(flags & FAMP)) tcsetpgrp(job.fd, job.curpgid);
2525 #endif  // SIGTSTP
2526     }
2527 #ifdef SIGTSTP
2528     if (job.jobcontrol) {
2529         sh_signal(SIGTTIN, (sh_sigfun_t)(SIG_DFL));
2530         sh_signal(SIGTTOU, (sh_sigfun_t)(SIG_DFL));
2531         sh_signal(SIGTSTP, (sh_sigfun_t)(SIG_DFL));
2532     }
2533 #endif  // SIGTSTP
2534     job.jobcontrol = 0;
2535 #endif  // JOBS
2536     job.toclear = 1;
2537     shp->login_sh = 0;
2538     sh_offoption(shp, SH_LOGIN_SHELL);
2539     sh_onstate(shp, SH_FORKED);
2540     sh_onstate(shp, SH_NOLOG);
2541     if (shp->fn_reset) shp->fn_depth = shp->fn_reset = 0;
2542     // Reset remaining signals to parent except for those `lost' by trap.
2543     if (!(flags & FSHOWME)) sh_sigreset(shp, 2);
2544     shp->subshell = 0;
2545     shp->comsub = 0;
2546     shp->spid = 0;
2547     if ((flags & FAMP) && shp->coutpipe > 1) sh_close(shp->coutpipe);
2548     sig = shp->savesig;
2549     shp->savesig = 0;
2550     if (sig > 0) kill(getpid(), sig);
2551     sh_sigcheck(shp);
2552     usepipe = 0;
2553     return 0;
2554 }
2555 
sh_fork(Shell_t * shp,int flags,int * jobid)2556 pid_t sh_fork(Shell_t *shp, int flags, int *jobid) {
2557     pid_t parent;
2558     sigset_t set, oset;
2559 
2560     if (!shp->pathlist) path_get(shp, "");
2561     sfsync(NULL);
2562     shp->trapnote &= ~SH_SIGTERM;
2563     job_fork(-1);
2564     sigfillset(&set);
2565     sigprocmask(SIG_BLOCK, &set, &oset);
2566     while (_sh_fork(shp, parent = fork(), flags, jobid) < 0) {
2567         ;  // empty loop
2568     }
2569     sh_stats(STAT_FORKS);
2570 #if USE_SPAWN
2571     if (parent == 0 && shp->vex) {
2572         spawnvex_apply(shp->vex, 0, 0);
2573         spawnvex_apply(shp->vexp, 0, SPAWN_RESET);
2574     }
2575 #endif  // USE_SPAWN
2576     sigprocmask(SIG_SETMASK, &oset, NULL);
2577     job_fork(parent);
2578     return parent;
2579 }
2580 
2581 struct Tdata {
2582     Shell_t *sh;
2583     Namval_t *tp;
2584     void *extra[2];
2585 };
2586 
2587 //
2588 // Add exports from previous scope to the new scope.
2589 //
local_exports(Namval_t * np,void * data)2590 static_fn void local_exports(Namval_t *np, void *data) {
2591     Shell_t *shp = ((struct Tdata *)data)->sh;
2592     Namval_t *mp;
2593     char *cp;
2594 
2595     if (nv_isarray(np)) nv_putsub(np, NULL, 0, 0);
2596     cp = nv_getval(np);
2597     if (cp && (mp = nv_search(nv_name(np), shp->var_tree, NV_ADD | NV_NOSCOPE)) && nv_isnull(mp)) {
2598         nv_putval(mp, cp, 0);
2599         nv_setattr(mp, np->nvflag);
2600     }
2601 }
2602 
2603 //
2604 // This routine executes .sh.math functions from within ((...))).
2605 //
sh_mathfun(Shell_t * shp,void * fp,int nargs,Sfdouble_t * arg)2606 Sfdouble_t sh_mathfun(Shell_t *shp, void *fp, int nargs, Sfdouble_t *arg) {
2607     // The initialization of this var isn't really needed because it is indirectly modified by the
2608     // sh_funscope() call below. But this stops lint tools from complaining that we're returning
2609     // garbage from an uninitialized var.
2610     Sfdouble_t d = 0.0;
2611     Namval_t node, *mp, *nref[9], **nr = nref;
2612     char *argv[2];
2613     struct funenv funenv;
2614     int i;
2615 
2616     Namval_t *np = fp;
2617     funenv.node = np;
2618     funenv.nref = nref;
2619     funenv.env = NULL;
2620     memcpy(&node, VAR_sh_value, sizeof(node));
2621     VAR_sh_value->nvfun = NULL;
2622     VAR_sh_value->nvenv = NULL;
2623     nv_setattr(VAR_sh_value, NV_LDOUBLE | NV_NOFREE);
2624     STORE_VT(VAR_sh_value->nvalue, sfdoublep, NULL);
2625     for (i = 0; i < nargs; i++) {
2626         *nr++ = mp = nv_namptr(shp->mathnodes, i);
2627         STORE_VT(mp->nvalue, sfdoublep, arg++);
2628     }
2629     *nr = 0;
2630     STORE_VT(VAR_sh_value->nvalue, sfdoublep, &d);
2631     argv[0] = np->nvname;
2632     argv[1] = NULL;
2633     sh_funscope(shp, 1, argv, 0, &funenv, 0);
2634     while ((mp = *nr++)) STORE_VT(mp->nvalue, sfdoublep, NULL);
2635     VAR_sh_value->nvfun = node.nvfun;
2636     nv_setattr(VAR_sh_value, node.nvflag);
2637     VAR_sh_value->nvenv = node.nvenv;
2638     STORE_VT(VAR_sh_value->nvalue, sfdoublep, FETCH_VT(node.nvalue, sfdoublep));
2639     return d;
2640 }
2641 
sh_funct(Shell_t * shp,Namval_t * np,int argn,char * argv[],struct argnod * envlist,int execflg)2642 static_fn void sh_funct(Shell_t *shp, Namval_t *np, int argn, char *argv[], struct argnod *envlist,
2643                         int execflg) {
2644     struct funenv fun;
2645     char *fname = nv_getval(VAR_sh_fun);
2646     struct Level *lp = (struct Level *)(VAR_sh_level->nvfun);
2647     int level, pipepid = shp->pipepid;
2648 
2649     shp->pipepid = 0;
2650     sh_stats(STAT_FUNCT);
2651     if (!lp->namfun.disc) lp = init_level(shp, 0);
2652     if ((struct sh_scoped *)shp->topscope != shp->st.self) sh_setscope(shp, shp->topscope);
2653     level = lp->maxlevel = shp->dot_depth + shp->fn_depth + 1;
2654     STORE_VT(VAR_sh_level->nvalue, i16, lp->maxlevel);
2655     shp->st.lineno = error_info.line;
2656     FETCH_VT(np->nvalue, rp)->running += 2;
2657     if (nv_isattr(np, NV_FPOSIX) && !sh_isoption(shp, SH_BASH)) {
2658         int loopcnt = shp->st.loopcnt;
2659         shp->posix_fun = np;
2660         shp->st.funname = nv_name(np);
2661         shp->last_root = nv_dict(VAR_sh);
2662         nv_putval(VAR_sh_fun, nv_name(np), NV_NOFREE);
2663         opt_info.index = opt_info.offset = 0;
2664         error_info.errors = 0;
2665         shp->st.loopcnt = 0;
2666         if (argn == 1) {
2667             // The vast majority of the time this is called with argn == 1 so optimize that case.
2668             // The first arg is ignored and could be anything.
2669             char *source_argv[3] = {"sh_funct", argv[0], NULL};
2670             b_source(2, source_argv, &shp->bltindata);
2671         } else {
2672             char **source_argv = malloc((argn + 2) * sizeof(char *));
2673             source_argv[0] = "sh_funct";
2674             source_argv[argn + 1] = NULL;
2675             memcpy(source_argv + 1, argv, argn * sizeof(char *));
2676             b_source(argn + 1, source_argv, &shp->bltindata);
2677             free(source_argv);
2678         }
2679         shp->st.loopcnt = loopcnt;
2680     } else {
2681         fun.env = envlist;
2682         fun.node = np;
2683         fun.nref = NULL;
2684         sh_funscope(shp, argn, argv, 0, &fun, execflg);
2685     }
2686     if (level-- != nv_getnum(VAR_sh_level)) {
2687         Shscope_t *sp = sh_getscope(shp, 0, SEEK_END);
2688         sh_setscope(shp, sp);
2689     }
2690     lp->maxlevel = level;
2691     STORE_VT(VAR_sh_level->nvalue, i16, lp->maxlevel);
2692     shp->last_root = nv_dict(VAR_sh);
2693     nv_putval(VAR_sh_fun, fname, NV_NOFREE);
2694     nv_putval(VAR_sh_file, shp->st.filename, NV_NOFREE);
2695     shp->pipepid = pipepid;
2696     FETCH_VT(np->nvalue, rp)->running -= 2;
2697     if (FETCH_VT(np->nvalue, rp) && FETCH_VT(np->nvalue, rp)->running == 1) {
2698         FETCH_VT(np->nvalue, rp)->running = 0;
2699         _nv_unset(np, NV_RDONLY);
2700     }
2701 }
2702 
2703 //
2704 // External interface to execute a function without arguments. <np> is the function node. If <nq> is
2705 // not-null, then sh.name and sh.subscript will be set.
2706 //
sh_fun(Shell_t * shp,Namval_t * np,Namval_t * nq,char * argv[])2707 int sh_fun(Shell_t *shp, Namval_t *np, Namval_t *nq, char *argv[]) {
2708     int offset;
2709     char *base;
2710     Namval_t node;
2711     struct Namref nr;
2712     nvflag_t mode;
2713     char *prefix = shp->prefix;
2714     int n = 0;
2715     char *av[3];
2716 
2717     Fcin_t save;
2718     fcsave(&save);
2719     offset = stktell(shp->stk);
2720     if (offset > 0) base = stkfreeze(shp->stk, 0);
2721     shp->prefix = NULL;
2722     if (!argv) {
2723         argv = av + 1;
2724         argv[1] = 0;
2725     }
2726     argv[0] = nv_name(np);
2727     while (argv[n]) n++;
2728     if (nq) mode = set_instance(shp, nq, &node, &nr);
2729     if (is_abuiltin(np)) {
2730         int jmpval;
2731         checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
2732         Shbltin_t *bp = &shp->bltindata;
2733         sh_pushcontext(shp, buffp, SH_JMPCMD);
2734         jmpval = sigsetjmp(buffp->buff, 1);
2735         if (jmpval == 0) {
2736             bp->bnode = np;
2737             bp->ptr = nv_context(np);
2738             errorpush(&buffp->err, 0);
2739             error_info.id = argv[0];
2740             opt_info.index = opt_info.offset = 0;
2741             opt_info.disc = NULL;
2742             shp->exitval = 0;
2743             shp->exitval = (funptr(np))(n, argv, bp);
2744         }
2745         sh_popcontext(shp, buffp);
2746         if (jmpval > SH_JMPCMD) siglongjmp(shp->jmplist->buff, jmpval);
2747     } else {
2748         sh_funct(shp, np, n, argv, NULL, sh_isstate(shp, SH_ERREXIT));
2749     }
2750     if (nq) unset_instance(nq, &node, &nr, mode);
2751     fcrestore(&save);
2752     if (offset > 0) stkset(shp->stk, base, offset);
2753     shp->prefix = prefix;
2754     return shp->exitval;
2755 }
2756 
2757 //
2758 // Set up pipe for cooperating process.
2759 //
coproc_init(Shell_t * shp,int pipes[])2760 static_fn void coproc_init(Shell_t *shp, int pipes[]) {
2761     int outfd;
2762     if (shp->coutpipe >= 0 && shp->cpid) {
2763         errormsg(SH_DICT, ERROR_exit(1), e_copexists);
2764         __builtin_unreachable();
2765     }
2766     shp->cpid = 0;
2767     if (shp->cpipe[0] <= 0 || shp->cpipe[1] <= 0) {
2768         // First co-process.
2769         sh_pclose(shp->cpipe);
2770         sh_pipe(shp->cpipe);
2771         outfd = shp->cpipe[1];
2772         if (outfd < 10) {
2773             int fd = sh_fcntl(shp->cpipe[1], F_DUPFD_CLOEXEC, 10);
2774             if (fd >= 10) {
2775                 shp->fdstatus[fd] = (shp->fdstatus[outfd] & ~IOCLEX);
2776                 sh_close(outfd);
2777                 shp->fdstatus[outfd] = IOCLOSE;
2778                 shp->cpipe[1] = fd;
2779             }
2780         }
2781         shp->fdptrs[shp->cpipe[0]] = shp->cpipe;
2782     }
2783     shp->outpipe = shp->cpipe;
2784     sh_pipe(shp->inpipe = pipes);
2785     shp->coutpipe = shp->inpipe[1];
2786     shp->fdptrs[shp->coutpipe] = &shp->coutpipe;
2787 }
2788 
2789 #if USE_SPAWN
2790 
sigreset(Shell_t * shp,int mode)2791 static_fn void sigreset(Shell_t *shp, int mode) {
2792     char *trap;
2793     int sig = shp->st.trapmax;
2794 
2795     while (sig-- > 0) {
2796 #ifdef SIGCLD
2797 #if SIGCLD != SIGCHLD
2798         if (sig == SIGCLD) continue;
2799 #endif
2800 #endif
2801         if (sig == SIGCHLD) continue;
2802         if (shp->sigflag[sig] & SH_SIGOFF) return;
2803         trap = shp->st.trapcom[sig];
2804         if (trap && *trap == 0) {
2805             sh_signal(sig, mode ? (sh_sigfun_t)sh_fault : (sh_sigfun_t)(SIG_IGN));
2806         }
2807     }
2808 }
2809 
2810 //
2811 // A combined fork/exec for systems with slow or non-existent fork().
2812 //
sh_ntfork(Shell_t * shp,const Shnode_t * t,char * argv[],int * jobid,int flag)2813 static_fn pid_t sh_ntfork(Shell_t *shp, const Shnode_t *t, char *argv[], int *jobid, int flag) {
2814     static pid_t spawnpid;
2815     static int savetype;
2816     static int savejobid;
2817     checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
2818     int otype = 0, jmpval, jobfork = 0, lineno = shp->st.firstline;
2819     volatile int scope = 0, sigwasset = 0;
2820     char **arge, *path;
2821     volatile pid_t grp = 0;
2822     Pathcomp_t *pp;
2823 
2824     if (flag) {
2825         otype = savetype;
2826         savetype = 0;
2827     }
2828     sh_pushcontext(shp, buffp, SH_JMPCMD);
2829     errorpush(&buffp->err, ERROR_SILENT);
2830     jmpval = sigsetjmp(buffp->buff, 0);
2831     if (jmpval == 0) {
2832         if ((otype & FINT) && !sh_isstate(shp, SH_MONITOR)) {
2833             sh_signal(SIGQUIT, (sh_sigfun_t)(SIG_IGN));
2834             sh_signal(SIGINT, (sh_sigfun_t)(SIG_IGN));
2835         }
2836         spawnpid = -1;
2837         if (t->com.comio) {
2838             shp->errorfd = error_info.fd;
2839 #if 1
2840             sh_redirect(shp, t->com.comio, io_usevex(t->com.comio));
2841 #else
2842             sh_redirect(shp, t->com.comio, 0);
2843 #endif
2844         }
2845         error_info.id = *argv;
2846         if (t->com.comset) {
2847             scope++;
2848             sh_scope(shp, t->com.comset, 0);
2849         }
2850         if (!strchr(path = argv[0], '/')) {
2851             Namval_t *np;
2852             np = nv_search(path, shp->track_tree, 0);
2853             if (np && !nv_isattr(np, NV_NOALIAS) && FETCH_VT(np->nvalue, const_cp)) {
2854                 path = nv_getval(np);
2855             } else if (path_absolute(shp, path, NULL)) {
2856                 path = stkptr(shp->stk, PATH_OFFSET);
2857                 stkfreeze(shp->stk, 0);
2858             } else {
2859                 pp = path_get(shp, path);
2860                 while (pp) {
2861                     if (pp->len == 1 && *pp->name == '.') break;
2862                     pp = pp->next;
2863                 }
2864                 if (!pp) path = 0;
2865             }
2866         } else if (sh_isoption(shp, SH_RESTRICTED)) {
2867             errormsg(SH_DICT, ERROR_exit(1), e_restricted, path);
2868             __builtin_unreachable();
2869         }
2870         if (!path) {
2871             spawnpid = -1;
2872             goto fail;
2873         }
2874         arge = sh_envgen(shp);
2875         // Restore firstline in case LINENO was exported.
2876         shp->st.firstline = lineno;
2877         shp->exitval = 0;
2878 #ifdef JOBS
2879         if (sh_isstate(shp, SH_MONITOR) && (job.jobcontrol || (otype & FAMP))) {
2880             if ((otype & FAMP) || job.curpgid == 0) {
2881                 grp = 1;
2882             } else {
2883                 grp = job.curpgid;
2884             }
2885         }
2886 #endif  // JOBS
2887 
2888         sfsync(NULL);
2889         sigreset(shp, 0);  // set signals to ignore
2890         sigwasset++;
2891         // Find first path that has a library component.
2892         for (pp = path_get(shp, argv[0]); pp && !pp->lib; pp = pp->next) {
2893             ;  // empty loop
2894         }
2895         job_fork(-1);
2896         jobfork = 1;
2897         spawnpid = path_spawn(shp, path, argv, arge, pp, (grp << 1) | 1);
2898         if (spawnpid < 0 && errno == ENOEXEC) {
2899             char *devfd;
2900             int fd = open(path, O_RDONLY);
2901             argv[-1] = argv[0];
2902             argv[0] = path;
2903             if (fd >= 0) {
2904                 struct stat statb;
2905                 sfprintf(shp->strbuf, "/dev/fd/%d", fd);
2906                 if (stat(devfd = sfstruse(shp->strbuf), &statb) >= 0) argv[0] = devfd;
2907             }
2908             if (!shp->gd->shpath) shp->gd->shpath = pathshell();
2909             spawnpid = path_spawn(shp, shp->gd->shpath, &argv[-1], arge, pp, (grp << 1) | 1);
2910             if (fd >= 0) sh_close(fd);
2911             argv[0] = argv[-1];
2912         }
2913     fail:
2914         if (jobfork && spawnpid < 0) job_fork(0);
2915         if (spawnpid < 0) {
2916             switch (errno = shp->path_err) {
2917                 case ENOENT: {
2918                     errormsg(SH_DICT, ERROR_system(ERROR_NOENT), e_found + 4);
2919                     __builtin_unreachable();
2920                 }
2921                 default: {
2922                     errormsg(SH_DICT, ERROR_system(ERROR_NOEXEC), e_exec + 4);
2923                     __builtin_unreachable();
2924                 }
2925             }
2926         }
2927     } else {
2928         exitset(shp);
2929     }
2930     sh_popcontext(shp, buffp);
2931     if (buffp->olist) free_list(buffp->olist);
2932     if (sigwasset) sigreset(shp, 1); /* restore ignored signals */
2933     if (scope) {
2934         sh_unscope(shp);
2935         if (jmpval == SH_JMPSCRIPT) {
2936             sh_setlist(shp, t->com.comset, NV_EXPORT | NV_IDENT | NV_ASSIGN, 0);
2937         }
2938     }
2939     if (t->com.comio && (jmpval || spawnpid <= 0)) {
2940         sh_iorestore(shp, buffp->topfd, jmpval);
2941 #if USE_SPAWN
2942         if (shp->vexp->cur > buffp->vexi) sh_vexrestore(shp, buffp->vexi);
2943 #endif
2944     }
2945     if (jmpval > SH_JMPCMD) siglongjmp(shp->jmplist->buff, jmpval);
2946     if (spawnpid > 0) {
2947         _sh_fork(shp, spawnpid, otype, jobid);
2948         job_fork(spawnpid);
2949 #ifdef JOBS
2950         if (grp == 1) job.curpgid = spawnpid;
2951 #ifdef SIGTSTP
2952         if (grp > 0 && !(otype & FAMP)) {
2953             while (tcsetpgrp(job.fd, job.curpgid) < 0 && job.curpgid != spawnpid) {
2954                 job.curpgid = spawnpid;
2955             }
2956         }
2957 #endif  // SIGTSTP
2958 #endif  // JOBS
2959         savejobid = *jobid;
2960         if (otype) return 0;
2961     }
2962     return spawnpid;
2963 }
2964 
2965 #endif  // USE_SPAWN
2966 
2967 //
2968 // This routine is used to execute the given function <fun> in a new scope. If <fun> is NULL, then
2969 // arg points to a structure containing a pointer to a function that will be executed in the current
2970 // environment.
2971 //
sh_funscope(Shell_t * shp,int argn,char * argv[],int (* fun)(void *),void * arg,int execflg)2972 int sh_funscope(Shell_t *shp, int argn, char *argv[], int (*fun)(void *), void *arg, int execflg) {
2973     UNUSED(argn);
2974     char *trap;
2975     int nsig;
2976     struct dolnod *argsav = NULL;
2977     struct dolnod *saveargfor;
2978     struct sh_scoped savst, *prevscope;
2979     struct argnod *envlist = NULL;
2980     int isig, jmpval;
2981     volatile int r = 0;
2982     int n;
2983     char **savsig;
2984     struct funenv *fp = NULL;
2985     checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
2986     Namval_t *nspace = shp->namespace;
2987     Dt_t *last_root = shp->last_root;
2988     Shopt_t options;
2989 
2990     options = shp->options;
2991     if (shp->fn_depth == 0) {
2992         shp->glob_options = shp->options;
2993     } else {
2994         shp->options = shp->glob_options;
2995     }
2996     prevscope = shp->st.self;
2997     *prevscope = shp->st;
2998     sh_offoption(shp, SH_ERREXIT);
2999     shp->st.prevst = prevscope;
3000     memset(&savst, 0, sizeof(savst));
3001     shp->st.self = &savst;
3002     shp->topscope = (Shscope_t *)shp->st.self;
3003     shp->st.opterror = shp->st.optchar = 0;
3004     shp->st.optindex = 1;
3005     shp->st.loopcnt = 0;
3006     if (!fun) {
3007         fp = (struct funenv *)arg;
3008         shp->st.real_fun = FETCH_VT((fp->node)->nvalue, rp);
3009         envlist = fp->env;
3010     }
3011     prevscope->save_tree = shp->var_tree;
3012     n = dtvnext(prevscope->save_tree) != (shp->namespace ? shp->var_base : 0);
3013     sh_scope(shp, envlist, 1);
3014     if (n) {
3015         struct Tdata tdata;
3016         memset(&tdata, 0, sizeof(tdata));
3017         tdata.sh = shp;
3018         // Eliminate parent scope.
3019         nv_scan(prevscope->save_tree, local_exports, &tdata, NV_EXPORT, NV_EXPORT | NV_NOSCOPE);
3020     }
3021     shp->st.save_tree = shp->var_tree;
3022     if (!fun) {
3023         if (nv_isattr(fp->node, NV_TAGGED)) {
3024             sh_onoption(shp, SH_XTRACE);
3025         } else {
3026             sh_offoption(shp, SH_XTRACE);
3027         }
3028     }
3029     shp->st.cmdname = argv[0];
3030     // Save trap table.
3031     nsig = shp->st.trapmax;
3032     if (nsig > 0 || shp->st.trapcom[0]) {
3033         savsig = malloc(nsig * sizeof(char *));
3034         // Contents of shp->st.trapcom may change
3035         for (isig = 0; isig < nsig; ++isig) {
3036             savsig[isig] = shp->st.trapcom[isig] ? strdup(shp->st.trapcom[isig]) : NULL;
3037         }
3038     }
3039     sh_sigreset(shp, 0);
3040     argsav = sh_argnew(shp, argv, &saveargfor);
3041     sh_pushcontext(shp, buffp, SH_JMPFUN);
3042     errorpush(&buffp->err, 0);
3043     error_info.id = argv[0];
3044     shp->st.var_local = shp->var_tree;
3045     if (!fun) {
3046         shp->st.filename = FETCH_VT(fp->node->nvalue, rp)->fname;
3047         shp->st.funname = nv_name(fp->node);
3048         shp->last_root = nv_dict(VAR_sh);
3049         nv_putval(VAR_sh_file, shp->st.filename, NV_NOFREE);
3050         nv_putval(VAR_sh_fun, shp->st.funname, NV_NOFREE);
3051     }
3052     if ((execflg & sh_state(SH_NOFORK))) shp->end_fn = 1;
3053     jmpval = sigsetjmp(buffp->buff, 0);
3054     if (jmpval == 0) {
3055         if (shp->fn_depth++ > MAXDEPTH) {
3056             shp->toomany = 1;
3057             siglongjmp(shp->jmplist->buff, SH_JMPERRFN);
3058         } else if (fun) {
3059             r = (*fun)(arg);
3060         } else {
3061             char **args = shp->st.real_fun->argv;
3062             Namval_t *np, *nq, **nref;
3063             nref = fp->nref;
3064             if (nref) {
3065                 shp->last_root = NULL;
3066                 for (r = 0; args[r]; r++) {
3067                     np = nv_search(args[r], shp->var_tree, NV_NOSCOPE | NV_ADD);
3068                     if (!np || !*nref) continue;
3069 
3070                     nq = *nref++;
3071                     struct Namref *nrp = calloc(1, sizeof(struct Namref));
3072                     STORE_VT(np->nvalue, nrp, nrp);
3073                     if (nv_isattr(nq, NV_LDOUBLE) == NV_LDOUBLE) {
3074                         nrp->np = nq;
3075                     } else {
3076                         // TODO: Figure out where the assignment to nq->nvalue.ldp is occurring.
3077                         // This used to be the sole use of `pointerof()` which simply did what
3078                         // we're now doing. But when spelled out like this it is obvious there
3079                         // is a problem.
3080                         nrp->np = (void *)((uintptr_t)*FETCH_VT(nq->nvalue, sfdoublep));
3081                         nv_onattr(nq, NV_LDOUBLE);
3082                     }
3083                     nv_onattr(np, NV_REF | NV_NOFREE);
3084                 }
3085             }
3086             sh_exec(shp, (Shnode_t *)(nv_funtree((fp->node))), execflg | SH_ERREXIT);
3087             r = shp->exitval;
3088         }
3089     }
3090     if (shp->topscope != (Shscope_t *)shp->st.self) sh_setscope(shp, shp->topscope);
3091     if (--shp->fn_depth == 1 && jmpval == SH_JMPERRFN) {
3092         errormsg(SH_DICT, ERROR_exit(1), e_toodeep, argv[0]);
3093         __builtin_unreachable();
3094     }
3095     sh_popcontext(shp, buffp);
3096     sh_unscope(shp);
3097     shp->namespace = nspace;
3098     shp->var_tree = prevscope->save_tree;
3099     sh_argreset(shp, argsav, saveargfor);
3100     trap = shp->st.trapcom[0];
3101     shp->st.trapcom[0] = 0;
3102     sh_sigreset(shp, 1);
3103     shp->st = *prevscope;
3104     shp->topscope = (Shscope_t *)prevscope;
3105     nv_getval(sh_scoped(shp, VAR_IFS));
3106     shp->end_fn = 0;
3107     if (nsig) {
3108         for (isig = 0; isig < nsig; ++isig) {
3109             if (shp->st.trapcom[isig]) {
3110                 free(shp->st.trapcom[isig]);
3111             }
3112         }
3113         memcpy(shp->st.trapcom, savsig, nsig * sizeof(char *));
3114         free(savsig);
3115     }
3116     shp->trapnote = 0;
3117     shp->options = options;
3118     shp->last_root = last_root;
3119     if (jmpval == SH_JMPSUB) siglongjmp(shp->jmplist->buff, jmpval);
3120     if (trap) {
3121         sh_trap(shp, trap, 0);
3122         free(trap);
3123     }
3124     if (jmpval) r = shp->exitval;
3125     if (!sh_isstate(shp, SH_IOPROMPT) && r > SH_EXITSIG &&
3126         ((r & SH_EXITMASK) == SIGINT || ((r & SH_EXITMASK) == SIGQUIT))) {
3127         kill(getpid(), r & SH_EXITMASK);
3128     }
3129     if (jmpval > SH_JMPFUN) {
3130         sh_chktrap(shp);
3131         siglongjmp(shp->jmplist->buff, jmpval);
3132     }
3133     return r;
3134 }
3135 
3136 //
3137 // Given stream <iop> compile and execute.
3138 //
sh_eval(Shell_t * shp,Sfio_t * iop,int mode)3139 int sh_eval(Shell_t *shp, Sfio_t *iop, int mode) {
3140     Shnode_t *t;
3141     struct slnod *saveslp = shp->st.staklist;
3142     int jmpval;
3143     checkpt_t *pp = shp->jmplist;
3144     checkpt_t *buffp = stkalloc(shp->stk, sizeof(checkpt_t));
3145     static Sfio_t *io_save;
3146     volatile bool traceon = false;
3147     volatile int lineno = 0;
3148     int binscript = shp->binscript;
3149     char comsub = shp->comsub;
3150     Sfio_t *iosaved = io_save;
3151 
3152     io_save = iop;  // preserve correct value across longjmp
3153     shp->binscript = 0;
3154     shp->comsub = 0;
3155 #define SH_TOPFUN 0x8000  // this is a temporary tksh hack
3156     if (mode & SH_TOPFUN) {
3157         mode ^= SH_TOPFUN;
3158         shp->fn_reset = 1;
3159     }
3160     sh_pushcontext(shp, buffp, SH_JMPEVAL);
3161     buffp->olist = pp->olist;
3162     jmpval = sigsetjmp(buffp->buff, 0);
3163     while (jmpval == 0) {
3164         if (mode & SH_READEVAL) {
3165             lineno = shp->inlineno;
3166             traceon = sh_isoption(shp, SH_XTRACE);
3167             if (traceon) sh_offoption(shp, SH_XTRACE);
3168         }
3169         t = sh_parse(shp, iop, (mode & (SH_READEVAL | SH_FUNEVAL)) ? mode & SH_FUNEVAL : SH_NL);
3170         if (!(mode & SH_FUNEVAL) || !sfreserve(iop, 0, 0)) {
3171             if (!(mode & SH_READEVAL)) sfclose(iop);
3172             io_save = 0;
3173             mode &= ~SH_FUNEVAL;
3174         }
3175         mode &= ~SH_READEVAL;
3176         if (!sh_isoption(shp, SH_VERBOSE)) sh_offstate(shp, SH_VERBOSE);
3177         if ((mode & ~SH_FUNEVAL) && shp->gd->hist_ptr) {
3178             hist_flush(shp->gd->hist_ptr);
3179             mode = sh_state(SH_INTERACTIVE);
3180         }
3181         sh_exec(shp, t,
3182                 sh_isstate(shp, SH_ERREXIT) | sh_isstate(shp, SH_NOFORK) | (mode & ~SH_FUNEVAL));
3183         if (!io_save) break;
3184     }
3185     sh_popcontext(shp, buffp);
3186     shp->binscript = binscript;
3187     shp->comsub = comsub;
3188     if (traceon) sh_onoption(shp, SH_XTRACE);
3189     if (lineno) shp->inlineno = lineno;
3190     if (io_save) sfclose(io_save);
3191     io_save = iosaved == iop ? 0 : iosaved; /* io_save is static so assignment is meaningful. */
3192     sh_freeup(shp);
3193     shp->st.staklist = saveslp;
3194     shp->fn_reset = 0;
3195     if (jmpval > SH_JMPEVAL) siglongjmp(shp->jmplist->buff, jmpval);
3196     return shp->exitval;
3197 }
3198 
sh_run(Shell_t * shp,int argn,char * argv[])3199 int sh_run(Shell_t *shp, int argn, char *argv[]) {
3200     struct dolnod *dp;
3201     struct comnod *t = stkalloc(shp->stk, sizeof(struct comnod));
3202     int savtop = stktell(shp->stk);
3203     char *savptr = stkfreeze(stkstd, 0);
3204     Shbltin_t bltindata;
3205 
3206     bltindata = shp->bltindata;
3207     memset(t, 0, sizeof(struct comnod));
3208     dp = stkalloc(shp->stk,
3209                   sizeof(struct dolnod) + ARG_SPARE * sizeof(char *) + argn * sizeof(char *));
3210     dp->dolnum = argn;
3211     dp->dolbot = ARG_SPARE;
3212     memcpy(dp->dolval + ARG_SPARE, argv, (argn + 1) * sizeof(char *));
3213     t->comarg = (struct argnod *)dp;
3214     if (!strchr(argv[0], '/')) {
3215         t->comnamp = nv_bfsearch(argv[0], shp->fun_tree, (Namval_t **)&t->comnamq, NULL);
3216     }
3217     argn = sh_exec(shp, (Shnode_t *)t, sh_isstate(shp, SH_ERREXIT));
3218     shp->bltindata = bltindata;
3219     if (savptr != stkptr(shp->stk, 0)) {
3220         stkset(shp->stk, savptr, savtop);
3221     } else {
3222         stkseek(shp->stk, savtop);
3223     }
3224     return argn;
3225 }
3226