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 // Input/output file processing
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 <netdb.h>
32 #include <netinet/in.h>
33 #include <signal.h>
34 #include <stdarg.h>
35 #include <stdbool.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43 
44 #include "argnod.h"
45 #include "ast.h"
46 #include "ast_assert.h"
47 #include "ast_regex.h"
48 #include "builtins.h"
49 #include "defs.h"
50 #include "edit.h"
51 #include "error.h"
52 #include "fault.h"
53 #include "history.h"
54 #include "io.h"
55 #include "jobs.h"
56 #include "name.h"
57 #include "path.h"
58 #include "sfio.h"
59 #include "shcmd.h"
60 #include "shnodes.h"
61 #include "stk.h"
62 #include "terminal.h"
63 #include "timeout.h"
64 #include "variables.h"
65 
66 #if USE_SPAWN
67 #include "spawnvex.h"
68 #endif
69 
70 #ifdef FNDELAY
71 #ifdef EAGAIN
72 #if EAGAIN != EWOULDBLOCK
73 #undef EAGAIN
74 #define EAGAIN EWOULDBLOCK
75 #endif
76 #else
77 #define EAGAIN EWOULDBLOCK
78 #endif  // EAGAIN
79 #ifndef O_NONBLOCK
80 #define O_NONBLOCK FNDELAY
81 #endif  // !O_NONBLOCK
82 #endif  // FNDELAY
83 
84 #ifndef ERROR_PIPE
85 #ifdef ECONNRESET
86 #define ERROR_PIPE(e) ((e) == EPIPE || (e) == ECONNRESET || (e) == EIO)
87 #else
88 #define ERROR_PIPE(e) ((e) == EPIPE || (e) == EIO)
89 #endif
90 #endif
91 
92 #define RW_ALL (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH)
93 
94 static void *timeout = NULL;
95 static_fn int (*fdnotify)(int, int);
96 
97 #if _pipe_socketpair && !_stream_peek
98 
99 // Emulate `pipe()` via `socketpair()`.
100 #undef pipe
101 #define pipe _io_socketpair
102 
103 #if _socketpair_shutdown_mode
104 
_io_socketpair(int fd[2])105 static_fn int _io_socketpair(int fd[2]) {
106     if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) return -1;
107     if (shutdown(fd[1], SHUT_RD) == -1) return -1;
108     if (fchmod(fd[1], S_IWUSR) == -1) return -1;
109     if (shutdown(fd[0], SHUT_WR) == -1) return -1;
110     if (fchmod(fd[0], S_IRUSR) == -1) return -1;
111     return 0;
112 }
113 
114 #else  // _socketpair_shutdown_mode
115 
_io_socketpair(int fd[2])116 static_fn int _io_socketpair(int fd[2]) {
117     if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) return -1;
118     if (shutdown(fd[1], SHUT_RD) == -1) return -1;
119     if (shutdown(fd[0], SHUT_WR) == -1) return -1;
120     return 0;
121 }
122 
123 #endif  // _socketpair_shutdown_mode
124 #endif  // _pipe_socketpair && !_stream_peek
125 
126 struct fdsave {
127     int orig_fd;  /* original file descriptor */
128     int save_fd;  /* saved file descriptor */
129     int subshell; /* saved for subshell */
130     char *tname;  /* name used with >; */
131 };
132 
133 struct Iodisc {
134     Sfdisc_t disc;
135     Shell_t *sh;
136 };
137 
138 static_fn int subexcept(Sfio_t *, int, void *, Sfdisc_t *);
139 static_fn int eval_exceptf(Sfio_t *, int, void *, Sfdisc_t *);
140 static_fn int slowexcept(Sfio_t *, int, void *, Sfdisc_t *);
141 static_fn int pipeexcept(Sfio_t *, int, void *, Sfdisc_t *);
142 static_fn ssize_t piperead(Sfio_t *, void *, size_t, Sfdisc_t *);
143 static_fn ssize_t slowread(Sfio_t *, void *, size_t, Sfdisc_t *);
144 static_fn ssize_t subread(Sfio_t *, void *, size_t, Sfdisc_t *);
145 static_fn ssize_t tee_write(Sfio_t *, const void *, size_t, Sfdisc_t *);
146 static_fn int io_prompt(Shell_t *, Sfio_t *, int);
147 static_fn int io_heredoc(Shell_t *, struct ionod *, const char *, int);
148 static_fn void sftrack(Sfio_t *, int, void *);
149 static const Sfdisc_t eval_disc = {NULL, NULL, NULL, eval_exceptf, NULL};
150 static Sfdisc_t tee_disc = {NULL, tee_write, NULL, NULL, NULL};
151 static_fn Sfio_t *subopen(Shell_t *, Sfio_t *, off_t, long);
152 static const Sfdisc_t sub_disc = {subread, 0, 0, subexcept, 0};
153 
154 struct subfile {
155     Sfdisc_t disc;
156     Sfio_t *oldsp;
157     off_t offset;
158     long size;
159     long left;
160     char *io_buffer;
161 };
162 
163 struct Eof {
164     Namfun_t namfun;
165     int fd;
166 };
167 
nget_cur_eof(Namval_t * np,Namfun_t * fp)168 static_fn Sfdouble_t nget_cur_eof(Namval_t *np, Namfun_t *fp) {
169     struct Eof *ep = (struct Eof *)fp;
170     Sfoff_t end, cur = lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
171 
172     if (*np->nvname == 'C') return (Sfdouble_t)cur;
173     if (cur < 0) return (Sfdouble_t)-1;
174     end = lseek(ep->fd, (Sfoff_t)0, SEEK_END);
175     lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
176     return (Sfdouble_t)end;
177 }
178 
179 static const Namdisc_t EOF_disc = {.dsize = sizeof(struct Eof), .getnum = nget_cur_eof};
180 
181 static struct fdsave *filemap;
182 static short filemapsize;
183 
184 #define PSEUDOFD (SHRT_MAX)
185 
186 // ======== Input, output and file copying ========
187 
sh_iovalidfd(Shell_t * shp,int fd)188 bool sh_iovalidfd(Shell_t *shp, int fd) {
189     Sfio_t **sftable = shp->sftable;
190     int max, n, **fdptrs = shp->fdptrs;
191     unsigned int *fdstatus = shp->fdstatus;
192 
193     if (fd < 0) return false;
194     if (fd < shp->gd->lim.open_max) return true;
195 
196     max = sysconf(_SC_OPEN_MAX);
197     if (fd >= max) {
198         errno = EBADF;
199         return false;
200     }
201 
202     n = (fd + 16) & ~0xf;
203     if (n++ > max) n = max + 1;
204     max = shp->gd->lim.open_max;
205     shp->sftable = calloc((n + 1) * (sizeof(int *) + sizeof(Sfio_t *) + sizeof(*fdstatus)), 1);
206 
207     if (sftable) {
208         --sftable;
209         if (max) memcpy(shp->sftable, sftable, ++max * sizeof(Sfio_t *));
210     }
211 
212     shp->fdptrs = (int **)(&shp->sftable[n]);
213     if (max) memcpy(shp->fdptrs, --fdptrs, max * sizeof(int *));
214     shp->fdstatus = (unsigned int *)(&shp->fdptrs[n]);
215     if (max) memcpy(shp->fdstatus, --fdstatus, max);
216 
217     if (sftable) free(sftable);
218 
219     shp->sftable++;
220     shp->fdptrs++;
221     shp->fdstatus++;
222     shp->gd->lim.open_max = n - 1;
223     return true;
224 }
225 
sh_inuse(Shell_t * shp,int fd)226 bool sh_inuse(Shell_t *shp, int fd) { return fd < shp->gd->lim.open_max && shp->fdptrs[fd]; }
227 
sh_ioinit(Shell_t * shp)228 void sh_ioinit(Shell_t *shp) {
229     filemapsize = 8;
230     filemap = malloc(filemapsize * sizeof(struct fdsave));
231     if (!sh_iovalidfd(shp, 16)) abort();
232     shp->sftable[0] = sfstdin;
233     shp->sftable[1] = sfstdout;
234     shp->sftable[2] = sfstderr;
235     sfnotify(sftrack);
236     sh_iostream(shp, 0, 0);
237     sh_iostream(shp, 1, 1);
238     sh_iostream(shp, 2, 2);
239     // All write steams are in the same pool and share outbuff.
240     shp->outpool = sfopen(NULL, NULL, "sw");  // pool identifier
241     shp->outbuff = malloc(IOBSIZE + 4);
242     shp->errbuff = malloc(IOBSIZE / 4);
243     sfsetbuf(sfstderr, shp->errbuff, IOBSIZE / 4);
244     sfsetbuf(sfstdout, shp->outbuff, IOBSIZE);
245     sfpool(sfstdout, shp->outpool, SF_WRITE);
246     sfpool(sfstderr, shp->outpool, SF_WRITE);
247     sfset(sfstdout, SF_LINE, 0);
248     sfset(sfstderr, SF_LINE, 0);
249     sfset(sfstdin, SF_SHARE | SF_PUBLIC, 1);
250 }
251 
252 //
253 //  Handle output stream exceptions.
254 //
outexcept(Sfio_t * iop,int type,void * data,Sfdisc_t * handle)255 static_fn int outexcept(Sfio_t *iop, int type, void *data, Sfdisc_t *handle) {
256     Shell_t *shp = ((struct Iodisc *)handle)->sh;
257     static bool active = false;
258 
259     if (type == SF_DPOP || type == SF_FINAL) {
260         free(handle);
261     } else if (type == SF_WRITE && (*(ssize_t *)data) < 0 && sffileno(iop) != 2) {
262         switch (errno) {
263 #ifdef ECONNRESET
264             case ECONNRESET:
265 #endif
266 #ifdef ESHUTDOWN
267             case ESHUTDOWN:
268 #endif
269             case EINTR:
270             case EPIPE: {
271                 break;
272             }
273             default: {
274                 if (active) return -1;
275                 int save = errno;
276                 int mode = shp->jmplist->mode;
277                 active = true;
278                 shp->jmplist->mode = 0;
279                 sfpurge(iop);
280                 sfpool(iop, NULL, SF_WRITE);
281                 errno = save;
282                 errormsg(SH_DICT, ERROR_system(1), e_badwrite, sffileno(iop));
283                 active = false;
284                 shp->jmplist->mode = mode;
285                 sh_exit(shp, 1);
286             }
287         }
288     }
289 
290     return 0;
291 }
292 
293 //
294 // Create or initialize a stream corresponding to descriptor <fd>. A buffer
295 // with room for a sentinal is allocated for a read stream. A discipline is
296 // inserted when read stream is a tty or a pipe. For output streams, the buffer
297 // is set to sh.output and put into the sh.outpool synchronization pool.
298 //
sh_iostream(Shell_t * shp,int fd,int fn)299 Sfio_t *sh_iostream(Shell_t *shp, int fd, int fn) {
300     Sfio_t *iop;
301     int status = sh_iocheckfd(shp, fd, fn);
302     int flags = SF_WRITE;
303     char *bp;
304     struct Iodisc *dp;
305 
306     if (status == IOCLOSE) {
307         switch (fd) {
308             case 0: {
309                 return sfstdin;
310             }
311             case 1: {
312                 return sfstdout;
313             }
314             case 2: {
315                 return sfstderr;
316             }
317             default: { return NULL; }
318         }
319     }
320     if (status & IOREAD) {
321         if (shp->bltinfun && shp->bltinfun != b_read && shp->bltindata.bnode &&
322             !nv_isattr(shp->bltindata.bnode, BLT_SPC)) {
323             bp = NULL;
324         } else if (!(bp = malloc(IOBSIZE + 1))) {
325             return NULL;
326         }
327         if (bp) bp[IOBSIZE] = 0;
328         flags |= SF_READ;
329         if (!(status & IOWRITE)) flags &= ~SF_WRITE;
330     } else {
331         bp = shp->outbuff;
332     }
333     if (status & IODUP) flags |= SF_SHARE | SF_PUBLIC;
334     if ((iop = shp->sftable[fn]) && sffileno(iop) >= 0) {
335         if (status & IOTTY) sfset(iop, SF_LINE | SF_WCWIDTH, 1);
336         if (bp) sfsetbuf(iop, bp, IOBSIZE);
337     } else {
338         iop = sfnew((fd <= 2 ? iop : 0), bp, IOBSIZE, fd, flags);
339         if (!iop) return NULL;
340     }
341     dp = calloc(1, sizeof(struct Iodisc));
342     dp->sh = shp;
343     if (status & IOREAD) {
344         sfset(iop, SF_MALLOC, 1);
345         if (!(status & IOWRITE)) sfset(iop, SF_IOCHECK, 1);
346         dp->disc.exceptf = slowexcept;
347         if (status & IOTTY) {
348             dp->disc.readf = slowread;
349         } else if (status & IONOSEEK) {
350             dp->disc.readf = piperead;
351             sfset(iop, SF_IOINTR, 1);
352         } else {
353             dp->disc.readf = 0;
354         }
355         dp->disc.seekf = 0;
356         dp->disc.writef = 0;
357     } else {
358         if ((status & (IONOSEEK | IOTTY)) == IONOSEEK) {
359             dp->disc.exceptf = pipeexcept;
360         } else {
361             dp->disc.exceptf = outexcept;
362         }
363         sfpool(iop, shp->outpool, SF_WRITE);
364     }
365     sfdisc(iop, &dp->disc);
366     shp->sftable[fn] = iop;
367     return iop;
368 }
369 
370 //
371 // Preserve the file descriptor or stream by moving it.
372 //
io_preserve(Shell_t * shp,Sfio_t * sp,int f2)373 static_fn void io_preserve(Shell_t *shp, Sfio_t *sp, int f2) {
374     int fd;
375 
376     if (sp) {
377         fd = sfsetfd(sp, 10);
378     } else {
379         fd = sh_fcntl(f2, F_DUPFD_CLOEXEC, 10);
380     }
381     if (f2 == shp->infd) shp->infd = fd;
382     if (fd < 0) {
383         shp->toomany = 1;
384         shp->jmplist->mode = SH_JMPERREXIT;
385         errormsg(SH_DICT, ERROR_system(1), e_toomany);
386         __builtin_unreachable();
387     }
388     if (f2 >= shp->gd->lim.open_max && !sh_iovalidfd(shp, f2)) abort();
389     shp->fdptrs[fd] = shp->fdptrs[f2];
390     if (shp->fdptrs[fd]) {
391         if (f2 == job.fd) job.fd = fd;
392         *shp->fdptrs[fd] = fd;
393         shp->fdptrs[f2] = 0;
394     }
395     shp->sftable[fd] = sp;
396     shp->fdstatus[fd] = shp->fdstatus[f2];
397     if (fcntl(f2, F_GETFD, 0) & 1) {
398         (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
399         shp->fdstatus[fd] |= IOCLEX;
400     }
401     shp->sftable[f2] = 0;
402 }
403 
404 //
405 // Given a file descriptor <f1>, move it to a file descriptor number <f2>.
406 // If <f2> is needed move it, otherwise it is closed first.
407 // The original stream <f1> is closed.
408 // The new file descriptor <f2> is returned;
409 //
sh_iorenumber(Shell_t * shp,int f1,int f2)410 int sh_iorenumber(Shell_t *shp, int f1, int f2) {
411     Sfio_t *sp = shp->sftable[f2];
412 
413     if (!sh_iovalidfd(shp, f1)) abort();
414     if (!sh_iovalidfd(shp, f2)) abort();
415     if (f1 != f2) {
416         // See whether file descriptor is in use.
417         if (sh_inuse(shp, f2) || (f2 > 2 && sp)) {
418             if (!(shp->inuse_bits & (1 << f2))) io_preserve(shp, sp, f2);
419             sp = NULL;
420         } else if (f2 == 0) {
421             shp->st.ioset = 1;
422         }
423         sh_close(f2);
424         if (f2 <= 2 && sp) {
425             Sfio_t *spnew = sh_iostream(shp, f1, f1);
426             shp->fdstatus[f2] = (shp->fdstatus[f1] & ~IOCLEX);
427             // It should be impossible for this call to fail; thus returning -1. But rather than
428             // simply add a (void) cast check the return value. That's because I'm uncomfortable
429             // trusting SFIO to behave as I expect. Coverity Scan CID #294189.
430             int n = sfsetfd(spnew, f2);
431             assert(n != -1);
432             if (sfswap(spnew, sp) != sp) abort();
433             sfset(sp, SF_SHARE | SF_PUBLIC, 1);
434         } else {
435             shp->fdstatus[f2] = (shp->fdstatus[f1] & ~IOCLEX);
436             if ((f2 = sh_fcntl(f1, F_DUPFD, f2)) < 0) {
437                 errormsg(SH_DICT, ERROR_system(1), e_file + 4);
438                 __builtin_unreachable();
439             } else if (f2 <= 2) {
440                 sh_iostream(shp, f2, f2);
441             }
442         }
443         if (sp) shp->sftable[f1] = 0;
444         if (shp->fdstatus[f1] != IOCLOSE) sh_close(f1);
445     } else if (sp) {
446         // What happens if this fails and returns -1? Coverity Scan #294189.
447         (void)sfsetfd(sp, f2);
448         if (f2 <= 2) sfset(sp, SF_SHARE | SF_PUBLIC, 1);
449     }
450     return f2;
451 }
452 
453 //
454 // Close a file descriptor and update stream table and attributes.
455 //
sh_close(int fd)456 int sh_close(int fd) {
457     Shell_t *shp = sh_getinterp();
458 
459     if (!sh_iovalidfd(shp, fd)) {
460         errno = EBADF;
461         return -1;
462     }
463 
464     Sfio_t *sp = shp->sftable[fd];
465     if (!sp || sffileno(sp) != fd || sfclose(sp) < 0) {
466         if (fdnotify) (*fdnotify)(fd, SH_FDCLOSE);
467         close(fd);
468     }
469 
470     if (fd > STDERR_FILENO) shp->sftable[fd] = 0;
471     int r = (shp->fdstatus[fd] >> 8);
472     if (r) close(r);
473     shp->fdstatus[fd] = IOCLOSE;
474     if (shp->fdptrs[fd]) *shp->fdptrs[fd] = -1;
475     shp->fdptrs[fd] = 0;
476     if (fd < 10) shp->inuse_bits &= ~(1 << fd);
477     return 0;
478 }
479 
480 //
481 // Return /dev/<protocol>/<host>/<service> fd.
482 // If called with flags==O_NONBLOCK return 1 if protocol is supported.
483 //
484 typedef int (*Inetintr_f)(struct addrinfo *, void *);
485 
inetopen(const char * path,int flags,Inetintr_f onintr,void * handle)486 static_fn int inetopen(const char *path, int flags, Inetintr_f onintr, void *handle) {
487     char *s;
488     int fd;
489     int oerrno;
490     struct addrinfo hint;
491     struct addrinfo *addr;
492     struct addrinfo *p;
493 
494     memset(&hint, 0, sizeof(hint));
495     hint.ai_family = PF_UNSPEC;
496     switch (path[0]) {
497 #ifdef IPPROTO_SCTP
498         case 's': {
499             if (path[1] != 'c' || path[2] != 't' || path[3] != 'p' || path[4] != '/') {
500                 errno = ENOTDIR;
501                 return -1;
502             }
503             hint.ai_socktype = SOCK_STREAM;
504             hint.ai_protocol = IPPROTO_SCTP;
505             path += 5;
506             break;
507         }
508 #endif
509         case 't': {
510             if (path[1] != 'c' || path[2] != 'p' || path[3] != '/') {
511                 errno = ENOTDIR;
512                 return -1;
513             }
514             hint.ai_socktype = SOCK_STREAM;
515             path += 4;
516             break;
517         }
518         case 'u': {
519             if (path[1] != 'd' || path[2] != 'p' || path[3] != '/') {
520                 errno = ENOTDIR;
521                 return -1;
522             }
523             hint.ai_socktype = SOCK_DGRAM;
524             path += 4;
525             break;
526         }
527         default: {
528             errno = ENOTDIR;
529             return -1;
530         }
531     }
532 
533     if (flags == O_NONBLOCK) return 1;
534 
535     char *slash = strchr(path, '/');
536     if (!slash) return -1;
537 
538     s = strdup(path);
539     s[slash - path] = 0;
540     if (!strcmp(s, "local")) {
541         free(s);
542         s = strdup("localhost");
543     }
544 
545     int status = getaddrinfo(s, slash + 1, &hint, &addr);
546     free(s);
547     if (status) {
548         if (status != EAI_SYSTEM) errno = ENOTDIR;
549         return -1;
550     }
551 
552     oerrno = errno;
553     errno = 0;
554     fd = -1;
555     for (p = addr; p; p = p->ai_next) {
556         //
557         // Some api's don't take the hint.
558         //
559         if (!p->ai_protocol) p->ai_protocol = hint.ai_protocol;
560         if (!p->ai_socktype) p->ai_socktype = hint.ai_socktype;
561         while ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) >= 0) {
562             if (connect(fd, p->ai_addr, p->ai_addrlen) == 0) goto done;
563             close(fd);
564             fd = -1;
565             if (errno != EINTR || !onintr) break;
566             if ((*onintr)(addr, handle)) goto done;
567         }
568     }
569 
570 done:
571     freeaddrinfo(addr);
572     if (fd >= 0) errno = oerrno;
573     return fd;
574 }
575 
onintr(struct addrinfo * addr,void * handle)576 static_fn int onintr(struct addrinfo *addr, void *handle) {
577     Shell_t *sh = handle;
578 
579     if (sh->trapnote & SH_SIGSET) {
580         Shell_t *shp = sh_getinterp();
581         freeaddrinfo(addr);
582         sh_exit(shp, SH_EXITSIG);
583         return -1;
584     }
585     if (sh->trapnote) sh_chktrap(sh);
586     return 0;
587 }
588 
589 //
590 // Mimic open(2) with checks for pseudo /dev files and keep track of fd/sfio descriptors.
591 //
sh_open(const char * path,int flags,...)592 int sh_open(const char *path, int flags, ...) {
593     Shell_t *shp = sh_getinterp();
594     Sfio_t *sp;
595     int fd = -1;
596     mode_t mode;
597     char *e;
598     va_list ap;
599 
600     va_start(ap, flags);
601     mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
602     va_end(ap);
603 
604     if (!path) {
605         errno = EFAULT;
606         return -1;
607     }
608     if (*path == 0) {
609         errno = ENOENT;
610         return -1;
611     }
612 
613     if (strncmp(path, "/dev/", sizeof("/dev/") - 1) == 0) {
614         if (strncmp(path, "/dev/fd/", sizeof("/dev/fd/") - 1) == 0) {
615             if (flags == O_NONBLOCK) return 1;
616             fd = (int)strtol(path + sizeof("/dev/fd/") - 1, &e, 10);
617             if (*e) fd = -1;
618         } else if (strcmp(path, "/dev/stdin") == 0) {
619             fd = 0;
620         } else if (strcmp(path, "/dev/stdout") == 0) {
621             fd = 1;
622         } else if (strcmp(path, "/dev/stderr") == 0) {
623             fd = 2;
624         }
625 
626         if (fd < 0) {
627             if ((fd = inetopen(path + 5, flags, onintr, shp)) < 0 && errno != ENOTDIR) return -1;
628             if (flags == O_NONBLOCK) return fd >= 0;
629             if (fd >= 0) goto ok;
630         }
631         if (flags == O_NONBLOCK) return 0;
632     }
633 
634     if (fd >= 0) {
635         int nfd = -1;
636         if (flags & O_CREAT) {
637             struct stat st;
638             if (sh_stat(path, &st) >= 0) nfd = open(path, flags, st.st_mode);
639         } else {
640             nfd = open(path, flags);
641         }
642         if (nfd >= 0) {
643             fd = nfd;
644             goto ok;
645         }
646         if ((mode = sh_iocheckfd(shp, fd, fd)) == IOCLOSE) return -1;
647         flags &= O_ACCMODE;
648         if (!(mode & IOWRITE) && ((flags == O_WRONLY) || (flags == O_RDWR))) return -1;
649         if (!(mode & IOREAD) && ((flags == O_RDONLY) || (flags == O_RDWR))) return -1;
650         if ((fd = dup(fd)) < 0) return -1;
651     } else {
652         while ((fd = open(path, flags, mode)) < 0) {
653             if (errno != EINTR || shp->trapnote) return -1;
654         }
655     }
656 ok:
657     flags &= O_ACCMODE;
658     if (flags == O_WRONLY) {
659         mode = IOWRITE;
660     } else if (flags == O_RDWR) {
661         mode = (IOREAD | IOWRITE);
662     } else {
663         mode = IOREAD;
664     }
665     if (fd >= shp->gd->lim.open_max && !sh_iovalidfd(shp, fd)) abort();
666     if ((sp = shp->sftable[fd]) && (sfset(sp, 0, 0) & SF_STRING)) {
667         int n;
668         if ((n = sh_fcntl(fd, F_DUPFD_CLOEXEC, 10)) >= 10) {
669             close(fd);
670             fd = n;
671             mode |= IOCLEX;
672         }
673     }
674     if (flags & O_CLOEXEC) mode |= IOCLEX;
675     shp->fdstatus[fd] = mode;
676     return fd;
677 }
678 
679 //
680 // Open a file for reading. On failure, print message.
681 //
sh_chkopen(const char * name)682 int sh_chkopen(const char *name) {
683     int fd = sh_open(name, O_RDONLY | O_CLOEXEC, 0);
684 
685     if (fd >= 0) return fd;
686     errormsg(SH_DICT, ERROR_system(1), e_open, name);
687     __builtin_unreachable();
688 }
689 
690 //
691 // Move open file descriptor to a number > 9.
692 //
sh_iomovefd(Shell_t * shp,int fdold)693 int sh_iomovefd(Shell_t *shp, int fdold) {
694     int fdnew;
695     if (!sh_iovalidfd(shp, fdold)) abort();
696     if (fdold < 0 || fdold > 9) return fdold;
697 
698     fdnew = sh_iomovefd(shp, sh_fcntl(fdold, F_DUPFD_CLOEXEC, 10));
699     if (!sh_iovalidfd(shp, fdnew)) abort();
700     shp->fdstatus[fdnew] = (shp->fdstatus[fdold] | IOCLEX);
701     close(fdold);
702     shp->fdstatus[fdold] = IOCLOSE;
703     return fdnew;
704 }
705 
706 //
707 // Create a pipe and print message on failure. File descriptors will be >2 and close-on-exec. This
708 // may create a pipe using _io_socketpair() if a usable socketpair() is provided by the platform.
709 //
sh_pipe(int pv[])710 int sh_pipe(int pv[]) {
711     Shell_t *shp = sh_getinterp();
712     int fd[2];
713 
714     if (pipe(fd) < 0 || (pv[0] = fd[0]) < 0 || (pv[1] = fd[1]) < 0) {
715         errormsg(SH_DICT, ERROR_system(1), e_pipe);
716         __builtin_unreachable();
717     }
718     if (!sh_iovalidfd(shp, fd[0])) abort();
719     if (!sh_iovalidfd(shp, fd[1])) abort();
720     if (pv[0] > 2) (void)fcntl(pv[0], F_SETFD, FD_CLOEXEC);
721     if (pv[1] > 2) (void)fcntl(pv[1], F_SETFD, FD_CLOEXEC);
722     if (pv[0] <= 2) pv[0] = sh_iomovefd(shp, pv[0]);
723     if (pv[1] <= 2) pv[1] = sh_iomovefd(shp, pv[1]);
724     shp->fdstatus[pv[0]] = IONOSEEK | IOREAD | IOCLEX;
725     shp->fdstatus[pv[1]] = IONOSEEK | IOWRITE | IOCLEX;
726     sh_subsavefd(pv[0]);
727     sh_subsavefd(pv[1]);
728     return 0;
729 }
730 
731 #ifndef pipe2
732 #undef pipe
733 #if !_lib_pipe2
734 #define pipe2(a, b) pipe(a)
735 #endif
736 #endif
737 //
738 // Create a real pipe when pipe() is socketpair.
739 //
sh_rpipe(int pv[])740 void sh_rpipe(int pv[]) {
741     Shell_t *shp = sh_getinterp();
742     int fd[2];
743 
744     if (pipe2(fd, O_CLOEXEC) < 0 || (pv[0] = fd[0]) < 0 || (pv[1] = fd[1]) < 0) {
745         errormsg(SH_DICT, ERROR_system(1), e_pipe);
746         __builtin_unreachable();
747     }
748     shp->fdstatus[pv[0]] = IONOSEEK | IOREAD | IOCLEX;
749     shp->fdstatus[pv[1]] = IONOSEEK | IOWRITE | IOCLEX;
750 #if !_lib_pipe2
751     if (pv[0] > 2) (void)fcntl(pv[0], F_SETFD, FD_CLOEXEC);
752     if (pv[1] > 2) (void)fcntl(pv[1], F_SETFD, FD_CLOEXEC);
753 #endif
754     if (pv[0] <= 2) pv[0] = sh_iomovefd(shp, pv[0]);
755     if (pv[1] <= 2) pv[1] = sh_iomovefd(shp, pv[1]);
756     sh_subsavefd(pv[0]);
757     sh_subsavefd(pv[1]);
758 }
759 
pat_seek(void * handle,const char * str,size_t sz)760 static_fn int pat_seek(void *handle, const char *str, size_t sz) {
761     UNUSED(sz);
762     char **bp = (char **)handle;
763     *bp = (char *)str;
764     return -1;
765 }
766 
pat_line(const regex_t * rp,const char * buff,size_t n)767 static_fn int pat_line(const regex_t *rp, const char *buff, size_t n) {
768     const char *cp = buff, *sp;
769     while (n > 0) {
770         for (sp = cp; n-- > 0 && *cp++ != '\n';) {
771             ;  // empty loop
772         }
773         if (regnexec(rp, sp, cp - sp, 0, NULL, 0) == 0) return sp - buff;
774     }
775     return cp - buff;
776 }
777 
io_patseek(Shell_t * shp,regex_t * rp,Sfio_t * sp,int flags)778 static_fn int io_patseek(Shell_t *shp, regex_t *rp, Sfio_t *sp, int flags) {
779     char *cp, *match;
780     int r, fd, close_exec, was_share, s;
781     size_t n, m;
782 
783 #if PIPE_BUF > SF_BUFSIZE
784     s = SF_BUFSIZE;
785 #else
786     s = PIPE_BUF;
787 #endif
788 
789     fd = sffileno(sp);
790     if (!sh_iovalidfd(shp, fd)) abort();
791     close_exec = shp->fdstatus[fd] & IOCLEX;
792 
793     shp->fdstatus[sffileno(sp)] |= IOCLEX;
794     if (fd == 0) was_share = sfset(sp, SF_SHARE, 1);
795     while ((cp = sfreserve(sp, -s, SF_LOCKR)) || (cp = sfreserve(sp, SF_UNBOUND, SF_LOCKR))) {
796         m = n = sfvalue(sp);
797         while (n > 0 && cp[n - 1] != '\n') n--;
798         if (n) m = n;
799         r = regrexec(rp, cp, m, 0, NULL, 0, '\n', &match, pat_seek);
800         if (r < 0) {
801             m = match - cp;
802         } else if (r == 2) {
803             m = pat_line(rp, cp, m);
804             if (m < n) r = -1;
805         }
806         if (m && (flags & IOCOPY)) sfwrite(sfstdout, cp, m);
807         sfread(sp, cp, m);
808         if (r < 0) break;
809     }
810     if (!close_exec) shp->fdstatus[sffileno(sp)] &= ~IOCLEX;
811     if (fd == 0 && !(was_share & SF_SHARE)) sfset(sp, SF_SHARE, 0);
812     return 0;
813 }
814 
file_offset(Shell_t * shp,int fd,char * fname)815 static_fn Sfoff_t file_offset(Shell_t *shp, int fd, char *fname) {
816     Sfio_t *sp;
817     char *cp;
818     Sfoff_t off;
819     struct Eof endf;
820     Namval_t *mp = nv_open("EOF", shp->var_tree, 0);
821     Namval_t *pp = nv_open("CUR", shp->var_tree, 0);
822 
823     if (!sh_iovalidfd(shp, fd)) abort();
824     sp = shp->sftable[fd];
825 
826     memset(&endf, 0, sizeof(struct Eof));
827     endf.fd = fd;
828     endf.namfun.disc = &EOF_disc;
829     endf.namfun.nofree = 1;
830     if (mp) nv_stack(mp, &endf.namfun);
831     if (pp) nv_stack(pp, &endf.namfun);
832     if (sp) sfsync(sp);
833     off = sh_strnum(shp, fname, &cp, 0);
834     if (mp) nv_stack(mp, NULL);
835     if (pp) nv_stack(pp, NULL);
836     return *cp ? (Sfoff_t)-1 : off;
837 }
838 
839 //
840 // Close a pipe.
841 //
sh_pclose(int pv[])842 void sh_pclose(int pv[]) {
843     if (pv[0] >= 2) sh_close(pv[0]);
844     if (pv[1] >= 2) sh_close(pv[1]);
845     pv[0] = pv[1] = -1;
846 }
847 
io_usename(Shell_t * shp,char * name,int * perm,int fno,int mode)848 static_fn char *io_usename(Shell_t *shp, char *name, int *perm, int fno, int mode) {
849     struct stat statb;
850     char *tname, *sp, *ep, path[PATH_MAX + 1];
851     int fd, r;
852     size_t n;
853 
854     if (mode == 0) {
855         if ((fd = sh_open(name, O_RDONLY, 0)) >= 0) {
856             r = fstat(fd, &statb);
857             sh_close(fd);
858             if (r) return 0;
859             if (!S_ISREG(statb.st_mode)) return 0;
860             if (!(statb.st_mode & (S_IWUSR | S_IWOTH))) {
861                 if (!(statb.st_mode & S_IWGRP) && sh_access(name, W_OK)) {
862                     errno = EPERM;
863                     return 0;
864                 }
865             }
866             *perm = statb.st_mode & (RW_ALL | (S_IXUSR | S_IXGRP | S_IXOTH));
867         } else if (fd < 0 && errno != ENOENT) {
868             return 0;
869         }
870     }
871     while ((fd = readlink(name, path, PATH_MAX)) > 0) {
872         name = path;
873         name[fd] = 0;
874     }
875     stkseek(shp->stk, 1);
876     sfputr(shp->stk, name, 0);
877     n = stktell(shp->stk);
878     pathcanon(stkptr(shp->stk, 1), n - 1, PATH_PHYSICAL);
879     sp = stkptr(shp->stk, 1);
880     ep = strrchr(sp, '/');
881     if (ep) {
882         memmove(stkptr(shp->stk, 0), sp, ++ep - sp);
883         stkseek(shp->stk, ep - sp);
884     } else {
885         stkseek(shp->stk, 0);
886     }
887     sfputc(shp->stk, '.');
888     sfprintf(stkstd, "%<#d_%d{;.tmp", getpid(), fno);
889     tname = stkfreeze(shp->stk, 1);
890     switch (mode) {
891         case 1: {
892             rename(tname, name);
893             break;
894         }
895         default: {
896             unlink(tname);
897             break;
898         }
899     }
900     return tname;
901 }
902 
903 #if USE_SPAWN
904 //
905 // Restore sfstderr and close file descriptors.
906 //
sh_vexrestore(Shell_t * shp,int n)907 void sh_vexrestore(Shell_t *shp, int n) {
908     Spawnvex_t *vp = shp->vexp;
909 
910     if (vp->cur > n) {
911         spawnvex_apply(vp, n, n);
912         vp = shp->vex;
913         if (vp && vp->cur) spawnvex_apply(vp, 0, SPAWN_FRAME | SPAWN_RESET);
914     }
915 }
916 
917 //
918 // Set up standard stream in the child.
919 //
iovex_child(void * context,uint64_t fd1,uint64_t fd2)920 static_fn int iovex_child(void *context, uint64_t fd1, uint64_t fd2) {
921     Shell_t *shp = context;
922     Sfio_t *sp = shp->sftable[fd2];
923 #if 1
924     char buff[256];
925     int n = sfsprintf(buff, sizeof(buff), "%p: fd1=%d fd2=%d \n", sp, fd1, fd2);
926     write(-1, buff, n);
927 #else
928     if (sp) {
929         spnew = sh_iostream(shp, fd1, fd1);
930         shp->fdstatus[fd2] = (shp->fdstatus[fd1] & ~IOCLEX);
931         if (sfswap(spnew, sp) != sp) abort();
932         sp->file = fd2;
933         sfset(sp, SF_SHARE | SF_PUBLIC, 1);
934     }
935 #endif
936     return 0;
937 }
938 
iovex_stdstream(Shell_t * shp,int fn)939 static_fn void iovex_stdstream(Shell_t *shp, int fn) {
940     if (fn > 2) return;
941     if (fn == 0) {
942         sfstdin = shp->sftable[0];
943         shp->st.ioset = 1;
944     } else if (fn == 1) {
945         if (sfstdout != &_Sfstdout) sfset(sfstdout, SF_STATIC, 0);
946         sfstdout = shp->sftable[1];
947         if (sfstdout != &_Sfstdout) sfset(sfstdout, SF_STATIC, SF_STATIC);
948     } else if (fn == 2) {
949         sfstderr = shp->sftable[2];
950         if (sfstderr) {
951             error_info.fd = sffileno(sfstderr);
952         } else {
953             error_info.fd = -1;
954         }
955     }
956     sfset(shp->sftable[fn], SF_SHARE | SF_PUBLIC, 1);
957 }
958 
959 //
960 // Restore stream in parent.
961 //
iovex_stream(void * context,uint64_t origfd,uint64_t fd2)962 static_fn int iovex_stream(void *context, uint64_t origfd, uint64_t fd2) {
963     UNUSED(fd2);
964     Shell_t *shp = context;
965     Sfio_t *sp, *sporig = shp->sftable[origfd];
966 
967     if (sporig) {
968         int status = shp->fdstatus[origfd];
969         int fd = sffileno(sporig);
970         if (fd < 0) {
971             fd = -(fd + 1);
972             status = IOCLOSE;
973         }
974         sp = shp->sftable[fd];
975         if (sp) {
976             sfsetfd(sp, -1);
977             sfclose(sp);
978         } else {
979             int flag = (status & IOCLEX) ? F_DUPFD_CLOEXEC : F_DUPFD;
980             sh_fcntl(origfd, flag, fd);
981         }
982         shp->sftable[fd] = sporig;
983 
984         if (shp->readscript) {
985             sfsetfd(sporig, -1);
986             sfclose(sporig);
987             sfnew(sporig, NULL, -1, fd,
988                   (fd < 3 ? SF_SHARE | SF_PUBLIC : 0) | (status & (IOREAD | IOWRITE)));
989             sh_iostream(shp, fd, fd);
990         } else {
991             shp->fdstatus[fd] = status;
992         }
993         shp->fdstatus[origfd] = IOCLOSE;
994         shp->sftable[origfd] = 0;
995         iovex_stdstream(shp, fd);
996     }
997     return 0;
998 }
999 
iovex_trunc(void * context,uint64_t origfd,uint64_t fd2)1000 static_fn int iovex_trunc(void *context, uint64_t origfd, uint64_t fd2) {
1001     Shell_t *shp = context;
1002     int r = 0;
1003     errno = 0;
1004 
1005     if (shp->exitval == 0) {
1006         Sfio_t *sp = shp->sftable[origfd];
1007         shp->sftable[origfd] = 0;
1008         ftruncate(origfd, lseek(origfd, 0, SEEK_CUR));
1009         shp->sftable[origfd] = sp;
1010         r = errno;
1011     }
1012     if (shp->sftable[origfd]) iovex_stream(context, origfd, fd2);
1013     return r;
1014 }
1015 
iovex_rename(void * context,uint64_t origfd,uint64_t fd2)1016 static_fn int iovex_rename(void *context, uint64_t origfd, uint64_t fd2) {
1017     Shell_t *shp = *(Shell_t **)context;
1018     char *fname = (char *)((char *)context + sizeof(void *));
1019 
1020     io_usename(shp, fname, NULL, origfd, shp->exitval ? 2 : 1);
1021     free(context);
1022     if (shp->sftable[origfd]) iovex_stream(shp, origfd, fd2);
1023     return 0;
1024 }
1025 #endif
1026 
1027 //
1028 // I/O redirection.
1029 //
1030 // flag = 0 if files are to be restored
1031 // flag = 2 if files are to be closed on exec
1032 // flag = 3 when called from $( < ...), just open file and return
1033 // flag = SH_SHOWME for trace only
1034 //
1035 // If (flag&IOHERESTRING), here documents can be string files.
1036 //
sh_redirect(Shell_t * shp,struct ionod * iop,int flag)1037 int sh_redirect(Shell_t *shp, struct ionod *iop, int flag) {
1038     Sfoff_t off;
1039     char *fname;
1040     int fd, iof;
1041     const char *message = e_open;
1042     int o_mode;            // mode flag for open
1043     static char io_op[7];  // used for -x trace info
1044     int trunc = 0, clexec = 0, fn, traceon;
1045     int r, indx = shp->topfd, perm = -1;
1046     char *tname = NULL;
1047     char *after = "";
1048     char *trace = shp->st.trap[SH_DEBUGTRAP];
1049     Namval_t *np = NULL;
1050     int isstring = shp->subshell ? (sfset(sfstdout, 0, 0) & SF_STRING) : 0;
1051     int herestring = (flag & IOHERESTRING);
1052     int vex = (flag & IOUSEVEX);
1053 #if USE_SPAWN
1054     Spawnvex_t *vp = shp->vexp;
1055     Spawnvex_t *vc = shp->vex;
1056 #endif
1057     Sfio_t *sp;
1058 
1059     flag &= ~(IOHERESTRING | IOUSEVEX);
1060     if (flag == 2) clexec = 1;
1061     if (iop) traceon = sh_trace(shp, NULL, 0);
1062 
1063 #if USE_SPAWN
1064     if (vex) indx = vp->cur;
1065 #endif
1066 
1067     for (; iop; iop = iop->ionxt) {
1068         iof = iop->iofile;
1069         fn = (iof & IOUFD);
1070         if (fn == 1 && shp->subshell && !shp->subshare && (flag == 2 || isstring)) sh_subfork();
1071         if (shp->redir0 && fn == 0 && !(iof & IOMOV)) shp->redir0 = 2;
1072         io_op[0] = '0' + (iof & IOUFD);
1073         if (iof & IOPUT) {
1074             io_op[1] = '>';
1075             o_mode = O_WRONLY | O_CREAT;
1076         } else {
1077             io_op[1] = '<';
1078             o_mode = O_RDONLY | O_NONBLOCK;
1079         }
1080         io_op[2] = 0;
1081         io_op[3] = 0;
1082         io_op[4] = 0;
1083         fname = iop->ioname;
1084         if (!(iof & IORAW)) {
1085             if (iof & IOLSEEK) {
1086                 struct argnod *ap = stkalloc(shp->stk, ARGVAL + strlen(iop->ioname));
1087                 memset(ap, 0, ARGVAL);
1088                 ap->argflag = ARG_MAC;
1089                 strcpy(ap->argval, iop->ioname);
1090                 fname = sh_macpat(shp, ap, (iof & IOARITH) ? ARG_ARITH : ARG_EXP);
1091             } else if (iof & IOPROCSUB) {
1092                 struct argnod *ap = stkalloc(shp->stk, ARGVAL + strlen(iop->ioname));
1093                 memset(ap, 0, ARGVAL);
1094                 if (iof & IOPUT) {
1095                     ap->argflag = ARG_RAW;
1096                 } else if (shp->subshell) {
1097                     sh_subtmpfile(shp);
1098                 }
1099                 ap->argchn.ap = (struct argnod *)fname;
1100                 ap = sh_argprocsub(shp, ap);
1101                 fname = ap->argval;
1102             } else {
1103                 fname = sh_mactrim(
1104                     shp, fname,
1105                     (!sh_isoption(shp, SH_NOGLOB) && sh_isoption(shp, SH_INTERACTIVE)) ? 2 : 0);
1106             }
1107         }
1108         errno = 0;
1109         np = NULL;
1110         if (iop->iovname) {
1111             np = nv_open(iop->iovname, shp->var_tree, NV_VARNAME);
1112             if (nv_isattr(np, NV_RDONLY)) {
1113                 errormsg(SH_DICT, ERROR_exit(1), e_readonly, nv_name(np));
1114                 __builtin_unreachable();
1115             }
1116             io_op[0] = '}';
1117             if ((iof & IOLSEEK) || ((iof & IOMOV) && *fname == '-')) fn = nv_getnum(np);
1118         }
1119         if (fn >= shp->gd->lim.open_max && !sh_iovalidfd(shp, fn)) {
1120             errormsg(SH_DICT, ERROR_system(1), e_file + 4);
1121             __builtin_unreachable();
1122         }
1123         if (iof & IOLSEEK) {
1124             io_op[2] = '#';
1125             if (iof & IOARITH) {
1126                 strcpy(&io_op[3], " ((");
1127                 after = "))";
1128             } else if (iof & IOCOPY) {
1129                 io_op[3] = '#';
1130             }
1131             goto traceit;
1132         }
1133         if (*fname || (iof & (IODOC | IOSTRG)) == (IODOC | IOSTRG)) {
1134             if (iof & IODOC) {
1135                 if (traceon) sfputr(sfstderr, io_op, '<');
1136                 fd = io_heredoc(shp, iop, fname, traceon | herestring);
1137                 if (traceon && (flag == SH_SHOWME)) sh_close(fd);
1138                 fname = 0;
1139             } else if (iof & IOMOV) {
1140                 int dupfd, toclose = -1;
1141                 io_op[2] = '&';
1142                 if ((fd = fname[0]) >= '0' && (fd == '{' || fd <= '9')) {
1143                     char *number = fname;
1144                     int f;
1145                     if (fd == '{') {
1146                         np = NULL;
1147                         number = strchr(fname, '}');
1148                         if (number) {
1149                             *number = 0;
1150                             np = nv_open(fname + 1, shp->var_tree, NV_VARNAME | NV_NOFAIL);
1151                             *number++ = '}';
1152                         }
1153                         if (!np) {
1154                             message = e_file;
1155                             goto fail;
1156                         }
1157                         dupfd = nv_getnum(np);
1158                         np = NULL;
1159                     } else {
1160                         dupfd = strtol(fname, &number, 10);
1161                     }
1162 #if USE_SPAWN
1163                     if (vex && (f = spawnvex_get(vc, dupfd, 0)) >= 0) dupfd = f;
1164 #endif
1165                     if (*number == '-') {
1166                         toclose = dupfd;
1167                         number++;
1168                     }
1169                     if (*number) {
1170                         message = e_file;
1171                         goto fail;
1172                     }
1173                     if (!sh_iovalidfd(shp, dupfd)) {
1174                         message = e_file;
1175                         goto fail;
1176                     }
1177                     if (shp->subshell && dupfd == 1) {
1178                         if (sfset(sfstdout, 0, 0) & SF_STRING) sh_subtmpfile(shp);
1179                         if (shp->comsub == 1) shp->subdup |= 1 << fn;
1180                         dupfd = sffileno(sfstdout);
1181                     } else if ((sp = shp->sftable[dupfd])) {
1182                         char *tmpname;
1183                         if (sfset(sp, 0, 0) & SF_STRING) {
1184                             tmpname = ast_temp_file(NULL, "sf", &f, 0);
1185                             if (tmpname) {
1186                                 Sfoff_t last = sfseek(sp, 0, SEEK_END);
1187                                 unlink(tmpname);
1188                                 free(tmpname);
1189                                 write(f, sp->data, (size_t)last);
1190                                 lseek(f, 0, SEEK_SET);
1191                                 // Associate the stream with the temp file descriptor. We don't
1192                                 // close then reopen the stream because the stream pointed to by
1193                                 // `sp` is used after we return. See
1194                                 // https://github.com/att/ast/issues/398.
1195                                 close(sffileno(sp));
1196                                 (void)sfnew(sp, NULL, -1, f, SF_READ);
1197                             }
1198                         }
1199                         sfsync(shp->sftable[dupfd]);
1200                     }
1201                     if (dupfd != 1 && fn < 10) shp->subdup &= ~(1 << fn);
1202                 } else if (fd == '-' && fname[1] == 0) {
1203                     fd = -1;
1204                     goto traceit;
1205                 } else if (fd == 'p' && fname[1] == 0) {
1206                     if (iof & IOPUT) {
1207                         dupfd = shp->coutpipe;
1208                     } else {
1209                         dupfd = shp->cpipe[0];
1210                     }
1211                     if (flag) toclose = dupfd;
1212                 } else {
1213                     message = e_file;
1214                     goto fail;
1215                 }
1216                 if (flag == SH_SHOWME) goto traceit;
1217                 if ((sp = shp->sftable[dupfd]) && sfset(sp, 0, 0) & SF_STRING) {
1218                     char *cp;
1219                     Sfoff_t off = sftell(sp);
1220                     sfset(sp, SF_MALLOC, 0);
1221                     cp = sfgetbuf(sp);
1222                     sfset(sp, SF_MALLOC, 1);
1223                     r = (int)(sfseek(sp, (Sfoff_t)0, SEEK_END) - off);
1224                     sfseek(sp, off, SEEK_SET);
1225                     fd = shp->gd->lim.open_max - 1;
1226                     shp->sftable[fd] = sfnew(NULL, cp, r, -1, SF_READ | SF_STRING);
1227                     shp->fdstatus[fd] = shp->fdstatus[dupfd];
1228                 } else if (vex && toclose >= 0) {
1229 #if USE_SPAWN
1230                     indx = spawnvex_add(vp, dupfd, -1, 0, 0);
1231                     spawnvex_add(vc, dupfd, -1, 0, 0);
1232 #endif
1233                     fd = dupfd;
1234                 } else if ((fd = sh_fcntl(dupfd, F_DUPFD_CLOEXEC, 3)) < 0) {
1235                     goto fail;
1236                 }
1237                 if (!sh_iovalidfd(shp, fd)) abort();
1238                 if (!shp->sftable[dupfd]) sh_iocheckfd(shp, dupfd, dupfd);
1239                 shp->fdstatus[fd] = (shp->fdstatus[dupfd] & ~IOCLEX);
1240                 if (toclose < 0 && shp->fdstatus[fd] & IOREAD) {
1241                     shp->fdstatus[fd] |= IODUP;
1242                 } else if (dupfd == shp->cpipe[0]) {
1243                     sh_pclose(shp->cpipe);
1244                 } else if (!vex && toclose >= 0) {
1245                     if (flag == 0) {
1246                         sh_iosave(shp, toclose, indx, NULL); /* save file descriptor */
1247                     }
1248                     sh_close(toclose);
1249                 }
1250             } else if (iof & IORDW) {
1251                 if (sh_isoption(shp, SH_RESTRICTED)) {
1252                     errormsg(SH_DICT, ERROR_exit(1), e_restricted, fname);
1253                     __builtin_unreachable();
1254                 }
1255                 io_op[2] = '>';
1256                 o_mode = O_RDWR | O_CREAT;
1257                 if (iof & IOREWRITE) trunc = io_op[2] = ';';
1258                 goto openit;
1259             } else if (!(iof & IOPUT)) {
1260                 if (flag == SH_SHOWME) goto traceit;
1261                 fd = sh_chkopen(fname);
1262                 fd = sh_iomovefd(shp, fd);
1263             } else if (sh_isoption(shp, SH_RESTRICTED)) {
1264                 errormsg(SH_DICT, ERROR_exit(1), e_restricted, fname);
1265                 __builtin_unreachable();
1266             } else {
1267                 if (iof & IOAPP) {
1268                     io_op[2] = '>';
1269                     o_mode |= O_APPEND;
1270                 } else if ((iof & IOREWRITE) && (flag == 0 || flag == 1 || sh_subsavefd(fn))) {
1271                     io_op[2] = ';';
1272                     o_mode |= O_TRUNC;
1273                     tname = io_usename(shp, fname, &perm, fn, 0);
1274                     if (tname) o_mode |= O_EXCL;
1275                 } else {
1276                     o_mode |= O_TRUNC;
1277                     if (iof & IOCLOB) {
1278                         io_op[2] = '|';
1279                     } else if (sh_isoption(shp, SH_NOCLOBBER)) {
1280                         struct stat sb;
1281                         if (sh_stat(fname, &sb) >= 0) {
1282                             if (S_ISREG(sb.st_mode)) {
1283                                 errno = EEXIST;
1284                                 errormsg(SH_DICT, ERROR_system(1), e_exists, fname);
1285                                 __builtin_unreachable();
1286                             }
1287                         } else {
1288                             o_mode |= O_EXCL;
1289                         }
1290                     }
1291                 }
1292             openit:
1293                 if (flag != SH_SHOWME) {
1294                     fd = sh_open(tname ? tname : fname, o_mode, RW_ALL);
1295                     if (fd < 0) {
1296                         errormsg(SH_DICT, ERROR_system(1), ((o_mode & O_CREAT) ? e_create : e_open),
1297                                  tname ? tname : fname);
1298                         __builtin_unreachable();
1299                     }
1300                     if (perm > 0) {
1301                         fchmod(fd, perm);
1302                     }
1303                 }
1304             }
1305         traceit:
1306             if (traceon && fname) {
1307                 if (np) sfprintf(sfstderr, "{%s", nv_name(np));
1308                 sfprintf(sfstderr, "%s %s%s%c", io_op, fname, after, iop->ionxt ? ' ' : '\n');
1309             }
1310             if (flag == SH_SHOWME) return indx;
1311             if (trace && fname) {
1312                 char *argv[7], **av = argv;
1313                 av[3] = io_op;
1314                 av[4] = fname;
1315                 av[5] = 0;
1316                 av[6] = 0;
1317                 if (iof & IOARITH) av[5] = after;
1318                 if (np) {
1319                     av[0] = "{";
1320                     av[1] = nv_name(np);
1321                     av[2] = "}";
1322                 } else {
1323                     av += 3;
1324                 }
1325                 sh_debug(shp, trace, NULL, NULL, av, ARG_NOGLOB);
1326             }
1327             if (iof & IOLSEEK) {
1328                 sp = shp->sftable[fn];
1329                 r = shp->fdstatus[fn];
1330                 if (!(r & (IOSEEK | IONOSEEK))) r = sh_iocheckfd(shp, fn, fn);
1331                 sfsprintf(io_op, sizeof(io_op), "%d\0", fn);
1332                 if (r == IOCLOSE) {
1333                     fname = io_op;
1334                     message = e_file;
1335                     goto fail;
1336                 }
1337                 if (iof & IOARITH) {
1338                     if (r & IONOSEEK) {
1339                         fname = io_op;
1340                         message = e_notseek;
1341                         goto fail;
1342                     }
1343                     message = e_badseek;
1344                     if ((off = file_offset(shp, fn, fname)) < 0) goto fail;
1345                     if (sp) {
1346                         off = sfseek(sp, off, SEEK_SET);
1347                         sfsync(sp);
1348                     } else {
1349                         off = lseek(fn, off, SEEK_SET);
1350                     }
1351                     if (off < 0) r = -1;
1352                 } else {
1353                     regex_t *rp;
1354                     if (!(r & IOREAD)) {
1355                         message = e_noread;
1356                         goto fail;
1357                     }
1358                     if (!(rp = regcache(fname,
1359                                         REG_SHELL | REG_NOSUB | REG_NEWLINE | REG_AUGMENTED |
1360                                             REG_FIRST | REG_LEFT | REG_RIGHT,
1361                                         &r))) {
1362                         message = e_badpattern;
1363                         goto fail;
1364                     }
1365                     if (!sp) sp = sh_iostream(shp, fn, fn);
1366                     // Note that `sp` has to be non-NULL at this juncture.
1367                     // See https://github.com/att/ast/issues/1140
1368                     r = io_patseek(shp, rp, sp, iof);
1369                     if (flag == 3) {
1370                         // Close stream but not fn.
1371                         sfsetfd(sp, -1);
1372                         sfclose(sp);
1373                     }
1374                 }
1375                 if (r < 0) goto fail;
1376                 if (flag == 3) return fn;
1377                 continue;
1378             }
1379             if (!np) {
1380                 if (!vex && (flag == 0 || tname ||
1381                              (flag == 1 && fn == 1 && (shp->fdstatus[fn] & IONOSEEK) &&
1382                               shp->outpipepid && shp->outpipepid == getpid()))) {
1383                     if (fd == fn) {
1384                         if ((r = sh_fcntl(fd, F_DUPFD, 10)) > 0) {
1385                             fd = r;
1386                             sh_close(fn);
1387                         }
1388                         // fd points to valid file descriptor.
1389                         sh_iosave(shp, fd, indx, tname ? fname : (trunc ? Empty : 0));
1390                     } else {
1391                         sh_iosave(shp, fn, indx, tname ? fname : (trunc ? Empty : 0));
1392                     }
1393                 } else if (!vex && flag != 3 && sh_subsavefd(fn)) {
1394                     // TODO: Truncation flag is not passed here. Is there a bug here ?
1395                     sh_iosave(shp, fn, indx | IOSUBSHELL, tname ? fname : 0);
1396                 }
1397             }
1398             if (fd < 0) {
1399                 if (vex) {
1400                     // This used to be as follows but AFAICT `flag` can never be negative based on a
1401                     // review of all the callers of this function. Leaving this comment in case
1402                     // someone debugging a problem in the future finds it helpful.
1403                     //
1404                     //   if (flag < 2) {
1405                     // #if USE_SPAWN
1406                     //     sh_vexsave(shp, fn, (iof & IODOC) ? -1 : -2, 0, 0);
1407                     // #endif
1408                     //   } else if (!(iof & IODOC)) {
1409                     if (!(iof & IODOC)) {
1410                         sh_close(fn);
1411                     } else {
1412                         fd = sh_fcntl(fn, F_DUPFD_CLOEXEC, 10);
1413                         shp->sftable[fn] = shp->sftable[-1];
1414                         shp->fdstatus[fn] = shp->fdstatus[-1];
1415                         shp->fdstatus[fn] |= (fd << 8);
1416                         fd = -1;
1417                     }
1418                 } else if (sh_inuse(shp, fn) || (fn && fn == shp->infd)) {
1419                     if (fn > 9 || !(shp->inuse_bits & (1 << fn))) {
1420                         io_preserve(shp, shp->sftable[fn], fn);
1421                     }
1422                 }
1423                 if (!vex || !(iof & IODOC)) sh_close(fn);
1424             }
1425             if (flag == 3) return fd;
1426             if (fd >= 0) {
1427                 if (np) {
1428                     int32_t v;
1429                     fn = fd;
1430                     if (fd < 10) {
1431                         if ((fn = fcntl(fd, F_DUPFD, 10)) < 0) goto fail;
1432                         if (fn >= shp->gd->lim.open_max && !sh_iovalidfd(shp, fn)) goto fail;
1433                         shp->fdstatus[fn] = shp->fdstatus[fd];
1434                         sh_close(fd);
1435                         fd = fn;
1436                     }
1437 
1438                     if (flag != 2 || shp->subshell) {
1439                         // TODO: Shall we replace 0x10000 with IOPICKFD ?
1440                         sh_iosave(shp, fn, indx | 0x10000, tname ? fname : (trunc ? Empty : 0));
1441                     }
1442 
1443                     _nv_unset(np, 0);
1444                     nv_onattr(np, NV_INT32);
1445                     v = fn;
1446                     nv_putval(np, (char *)&v, NV_INT32);
1447                     sh_iocheckfd(shp, fd, fd);
1448                 } else if (vex && flag == 2) {
1449                     Sfio_t *spold, *sp = shp->sftable[fn];
1450                     int status = IOCLOSE, fx = fd;
1451                     if (sp) {
1452                         fx = sffileno(sp);
1453                         spold = shp->sftable[fx];
1454                         status = shp->fdstatus[fx];
1455                         sfclose(sp);
1456                         fd = sh_fcntl(fd, fn < 3 ? F_DUPFD : F_DUPFD_CLOEXEC, fx);
1457                         if (fd < 0) goto fail;
1458                         shp->sftable[fn] = sh_iostream(shp, fd, fd);
1459                         shp->sftable[fx] = spold;
1460                     } else {
1461                         shp->sftable[fn] = sh_iostream(shp, fd, fn);
1462                         if (fd != fn) shp->fdstatus[fd] = IOCLOSE;
1463                     }
1464                     if (fx != fd) shp->fdstatus[fx] = status;
1465 #if USE_SPAWN
1466                     if (fn <= 2) iovex_stdstream(shp, fn);
1467 #endif
1468                 } else if (vex) {
1469                     void *arg = shp;
1470                     if (fn == fd) {
1471                         fd = sh_fcntl(fn, F_DUPFD_CLOEXEC, fn);
1472                         close(fn);
1473                     }
1474 
1475 #if USE_SPAWN
1476                     Spawnvex_f fun = NULL;
1477                     if (trunc) {
1478                         fun = iovex_trunc;
1479                     } else if (tname) {
1480                         arg = malloc(sizeof(void *) + strlen(fname) + 1);
1481                         *(Shell_t **)arg = shp;
1482                         strcpy((char *)arg + sizeof(void *), fname);
1483                         fun = iovex_rename;
1484                     } else if (shp->sftable[fn]) {
1485                         fun = iovex_stream;
1486                     }
1487                     sh_vexsave(shp, fn, fd, fun, arg);
1488 #else
1489                     if (tname) {
1490                         arg = malloc(sizeof(void *) + strlen(fname) + 1);
1491                         *(Shell_t **)arg = shp;
1492                         strcpy((char *)arg + sizeof(void *), fname);
1493                     }
1494 #endif
1495                 } else {
1496                     fd = sh_iorenumber(shp, sh_iomovefd(shp, fd), fn);
1497                     if (fn > 2 && fn < 10) shp->inuse_bits |= (1 << fn);
1498                 }
1499             } else if ((iof & IODOC) && !vex) {
1500                 Sfio_t *sp = &_Sfstderr;
1501                 if (fn == 1) {
1502                     sp = &_Sfstdout;
1503                 } else if (fn == 0) {
1504                     sp = &_Sfstdin;
1505                 }
1506                 shp->sftable[fn] = shp->sftable[-1];
1507                 shp->fdstatus[fn] = shp->fdstatus[-1];
1508                 if (fn <= 2) {
1509                     if (sfswap(shp->sftable[fn], sp) != sp) abort();
1510                     shp->sftable[fn] = sp;
1511                 }
1512                 shp->fdptrs[fn] = 0;
1513                 shp->sftable[-1] = 0;
1514             }
1515             if (fd > 2 && clexec && !(shp->fdstatus[fd] & IOCLEX)) {
1516                 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
1517                 shp->fdstatus[fd] |= IOCLEX;
1518             }
1519         } else {
1520             goto fail;
1521         }
1522     }
1523     return indx;
1524 
1525 fail:
1526     errormsg(SH_DICT, ERROR_system(1), message, fname);
1527     __builtin_unreachable();
1528 }
1529 
1530 //
1531 // Create a tmp file for the here-document.
1532 //
io_heredoc(Shell_t * shp,struct ionod * iop,const char * name,int traceon)1533 static_fn int io_heredoc(Shell_t *shp, struct ionod *iop, const char *name, int traceon) {
1534     Sfio_t *infile = NULL;
1535     Sfio_t *outfile, *tmp;
1536     int fd;
1537     Sfoff_t off;
1538 
1539     if (!(iop->iofile & IOSTRG) && (!shp->heredocs || iop->iosize == 0)) {
1540         return sh_open("/dev/null", O_RDONLY);
1541     }
1542     // Create an unnamed temporary file.
1543     outfile = sftmp((traceon & IOHERESTRING) ? PIPE_BUF : 0);
1544     if (!outfile) {
1545         errormsg(SH_DICT, ERROR_system(1), e_tmpcreate);
1546         __builtin_unreachable();
1547     }
1548     traceon &= ~IOHERESTRING;
1549     if (iop->iofile & IOSTRG) {
1550         if (traceon) sfprintf(sfstderr, "< %s\n", name);
1551         sfputr(outfile, name, '\n');
1552         sfputc(outfile, 0);
1553         outfile->next--;
1554     } else {
1555         // The locking is only needed in case & blocks process here-docs so
1556         // this can be eliminted in some cases.
1557         struct flock lock;
1558         int fno = sffileno(shp->heredocs);
1559         if (fno >= 0) {
1560             memset(&lock, 0, sizeof(lock));
1561             lock.l_type = F_WRLCK;
1562             lock.l_whence = SEEK_SET;
1563             fcntl(fno, F_SETLKW, &lock);
1564             lock.l_type = F_UNLCK;
1565         }
1566         off = sftell(shp->heredocs);
1567         infile = subopen(shp, shp->heredocs, iop->iooffset, iop->iosize);
1568         if (traceon) {
1569             char *cp = sh_fmtq(iop->iodelim);
1570             fd = (*cp == '$' || *cp == '\'') ? ' ' : '\\';
1571             sfprintf(sfstderr, " %c%s\n", fd, cp);
1572             sfdisc(outfile, &tee_disc);
1573         }
1574         tmp = outfile;
1575         if (fno >= 0 && !(iop->iofile & IOQUOTE)) {
1576             tmp = sftmp(iop->iosize < IOBSIZE ? iop->iosize : 0);
1577         }
1578         if (fno >= 0 || (iop->iofile & IOQUOTE)) {
1579             // This is a quoted here-document, not expansion.
1580             sfmove(infile, tmp, SF_UNBOUND, -1);
1581             sfclose(infile);
1582             if (sffileno(tmp) > 0) {
1583                 sfsetbuf(tmp, malloc(IOBSIZE + 1), IOBSIZE);
1584                 sfset(tmp, SF_MALLOC, 1);
1585             }
1586             sfseek(shp->heredocs, off, SEEK_SET);
1587             if (fno >= 0) fcntl(fno, F_SETLK, &lock);
1588             sfseek(tmp, (off_t)0, SEEK_SET);
1589             infile = tmp;
1590         }
1591         if (!(iop->iofile & IOQUOTE)) {
1592             char *lastpath = shp->lastpath;
1593             sh_machere(shp, infile, outfile, iop->ioname);
1594             shp->lastpath = lastpath;
1595             if (infile) sfclose(infile);
1596         }
1597     }
1598     if (traceon && !(iop->iofile & IOSTRG)) sfputr(sfstderr, iop->ioname, '\n');
1599     // Close stream outfile, but save file descriptor.
1600     if (sfset(outfile, 0, 0) & SF_STRING) {
1601         sfseek(outfile, (Sfoff_t)0, SEEK_SET);
1602         sfset(outfile, SF_READ | SF_WRITE, SF_READ);
1603         shp->sftable[-1] = outfile;
1604         shp->fdstatus[-1] = IOREAD | IOSEEK;
1605         shp->fdptrs[-1] = 0;
1606         return -1;
1607     }
1608     fd = sffileno(outfile);
1609     sfsetfd(outfile, -1);
1610     sfclose(outfile);
1611     lseek(fd, (off_t)0, SEEK_SET);
1612     shp->fdstatus[fd] = IOREAD;
1613     return fd;
1614 }
1615 
1616 //
1617 // This write discipline also writes the output on standard error. This is used
1618 // when tracing here-documents.
1619 //
tee_write(Sfio_t * iop,const void * buff,size_t n,Sfdisc_t * unused)1620 static_fn ssize_t tee_write(Sfio_t *iop, const void *buff, size_t n, Sfdisc_t *unused) {
1621     UNUSED(unused);
1622 
1623     sfwrite(sfstderr, buff, n);
1624     return write(sffileno(iop), buff, n);
1625 }
1626 
1627 //
1628 // Copy file <origfd> into a save place. The saved file is set close-on-exec.
1629 // If <origfd> < 0, then -origfd is saved, but not duped so that it will be
1630 // closed with sh_iorestore.
1631 //
sh_iosave(Shell_t * shp,int origfd,int oldtop,char * name)1632 void sh_iosave(Shell_t *shp, int origfd, int oldtop, char *name) {
1633     int savefd;
1634     Sfio_t *sp;
1635     int flag = (oldtop & (IOSUBSHELL | IOPICKFD));
1636     int savestr = 0;
1637 
1638     oldtop &= ~(IOSUBSHELL | IOPICKFD);
1639     // See if already saved, only save once.
1640     for (savefd = shp->topfd; --savefd >= oldtop;) {
1641         if (filemap[savefd].orig_fd == origfd) return;
1642     }
1643     // Make sure table is large enough.
1644     if (shp->topfd >= filemapsize) {
1645         char *cp, *oldptr = (char *)filemap;
1646         char *oldend = (char *)&filemap[filemapsize];
1647         long moved;
1648         filemapsize += 8;
1649         filemap = realloc(filemap, filemapsize * sizeof(struct fdsave));
1650         moved = (char *)filemap - oldptr;
1651         if (moved) {
1652             for (savefd = shp->gd->lim.open_max; --savefd >= 0;) {
1653                 cp = (char *)shp->fdptrs[savefd];
1654                 if (cp >= oldptr && cp < oldend) shp->fdptrs[savefd] = (int *)(cp + moved);
1655             }
1656         }
1657     }
1658 #if has_dev_fd
1659     if (origfd < 0) {
1660         savefd = origfd;
1661         origfd = -origfd;
1662     } else
1663 #endif  // has_dev_fd
1664         if (flag & IOPICKFD) {
1665         savefd = -1;
1666     } else {
1667         if ((savefd = sh_fcntl(origfd, F_DUPFD_CLOEXEC, 10)) < 0 && errno != EBADF) {
1668             shp->toomany = 1;
1669             shp->jmplist->mode = SH_JMPERREXIT;
1670             errormsg(SH_DICT, ERROR_system(1), e_toomany);
1671             __builtin_unreachable();
1672         }
1673         if (savefd < 0 && (sp = shp->sftable[origfd]) && (sfset(sp, 0, 0) & SF_STRING)) {
1674             savestr = 1;
1675             int fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
1676 
1677             if (fd == -1) {
1678                 errormsg(SH_DICT, ERROR_system(1), e_open, "/dev/null");
1679                 __builtin_unreachable();
1680             }
1681 
1682             if (fd < 10) {
1683                 savefd = sh_fcntl(fd, F_DUPFD_CLOEXEC, 10);
1684                 close(fd);
1685             } else {
1686                 savefd = fd;
1687             }
1688         }
1689     }
1690 
1691     filemap[shp->topfd].tname = name;
1692     filemap[shp->topfd].subshell = (flag & IOSUBSHELL);
1693     filemap[shp->topfd].orig_fd = origfd;
1694     filemap[shp->topfd].save_fd = savefd;
1695     if (savestr) filemap[shp->topfd].save_fd |= IOSAVESTRING;
1696     shp->topfd++;
1697     if (savefd >= 0) {
1698         sp = shp->sftable[origfd];
1699         // Make saved file close-on-exec.
1700         if (origfd == job.fd) job.fd = savefd;
1701         shp->fdstatus[savefd] = shp->fdstatus[origfd];
1702         shp->fdptrs[savefd] = &filemap[shp->topfd - 1].save_fd;
1703         if (!(shp->sftable[savefd] = sp)) return;
1704         if (!savestr) sfsync(sp);
1705         if (origfd <= 2) {
1706             // Copy standard stream to new stream.
1707             sp = sfswap(sp, NULL);
1708             shp->sftable[savefd] = sp;
1709         } else {
1710             shp->sftable[origfd] = 0;
1711         }
1712     }
1713 }
1714 
1715 #if USE_SPAWN
sh_vexsave(Shell_t * shp,int fn,int fd,Spawnvex_f vexfun,void * arg)1716 void sh_vexsave(Shell_t *shp, int fn, int fd, Spawnvex_f vexfun, void *arg) {
1717     Spawnvex_t *vp = shp->vexp;
1718     Spawnvex_t *vc = shp->vex;
1719     Sfio_t *sp = NULL;
1720     int status, infd = fd, close = (fd == -2);
1721     if (!vexfun && shp->sftable[fn]) vexfun = iovex_stream;
1722     if (!arg) arg = shp;
1723     if (fd < 0) {
1724         fd = sh_fcntl(fn, F_DUPFD_CLOEXEC, 10);
1725         if (fd >= shp->gd->lim.open_max) {
1726             if (!sh_iovalidfd(shp, fd)) abort();
1727         }
1728     } else {
1729         sp = shp->sftable[fd];
1730     }
1731     spawnvex_add(vc, fd, close ? -1 : fn, !close ? iovex_child : 0, arg);
1732     spawnvex_add(vp, fd, -1, vexfun, arg);
1733     if (close) {
1734         shp->sftable[fd] = shp->sftable[fn];
1735         shp->fdstatus[fd] = shp->fdstatus[fn];
1736         shp->sftable[fn] = 0;
1737         sh_close(fn);
1738     } else if (shp->sftable[fn]) {
1739         if (!sp) {
1740             if (infd == -1) {
1741                 sp = shp->sftable[infd];
1742             } else {
1743                 sp = sh_iostream(shp, fd, fd);
1744             }
1745         }
1746         status = shp->fdstatus[infd];
1747         shp->sftable[fd] = shp->sftable[fn];
1748         shp->fdstatus[fd] = shp->fdstatus[fn];
1749         shp->sftable[fn] = sp;
1750         shp->fdstatus[fn] = status;
1751         iovex_stdstream(shp, fn);
1752     }
1753 }
1754 #endif
1755 
1756 // Return the lowest numbered fd that is equal to or greater than the requested
1757 // `min_fd` and which is not currently in use.
sh_get_unused_fd(Shell_t * shp,int min_fd)1758 int sh_get_unused_fd(Shell_t *shp, int min_fd) {
1759     int fd;
1760 
1761     while (true) {
1762         if (fcntl(min_fd, F_GETFD) == -1) {
1763             for (fd = 0; fd < shp->topfd; fd++) {
1764                 if (filemap[fd].save_fd == min_fd || filemap[fd].orig_fd == min_fd) break;
1765             }
1766             if (fd == shp->topfd) break;
1767         }
1768         min_fd++;
1769     }
1770 
1771     return min_fd;
1772 }
1773 
1774 //
1775 // Close all saved file descriptors.
1776 //
sh_iounsave(Shell_t * shp)1777 void sh_iounsave(Shell_t *shp) {
1778     int fd, savefd, newfd;
1779 
1780     for (newfd = fd = 0; fd < shp->topfd; fd++) {
1781         if ((savefd = filemap[fd].save_fd) < 0) {
1782             filemap[newfd++] = filemap[fd];
1783         } else {
1784             shp->sftable[savefd] = 0;
1785             sh_close(savefd);
1786         }
1787     }
1788     shp->topfd = newfd;
1789 }
1790 
1791 //
1792 // Restore saved file descriptors from <last> on.
1793 //
sh_iorestore(Shell_t * shp,int last,int jmpval)1794 void sh_iorestore(Shell_t *shp, int last, int jmpval) {
1795     int origfd, savefd, fd;
1796     int savestr, flag = (last & IOSUBSHELL);
1797 
1798     last &= ~IOSUBSHELL;
1799 
1800     // There was an issue with truncating files (See `ftruncate` below) that was caused by
1801     // out of sync streams. So to be safe, sync all streams before restoring file descriptors.
1802     sfsync(NULL);
1803 
1804     for (fd = shp->topfd - 1; fd >= last; fd--) {
1805         if (!flag && filemap[fd].subshell) continue;
1806         savestr = filemap[fd].save_fd & IOSAVESTRING;
1807         filemap[fd].save_fd &= ~IOSAVESTRING;
1808         if (jmpval == SH_JMPSCRIPT) {
1809             if ((savefd = filemap[fd].save_fd) >= 0) {
1810                 shp->sftable[savefd] = 0;
1811                 sh_close(savefd);
1812             }
1813             continue;
1814         }
1815         origfd = filemap[fd].orig_fd;
1816         if (origfd < 0) {
1817             // This should never happen.
1818             savefd = filemap[fd].save_fd;
1819             shp->sftable[savefd] = 0;
1820             sh_close(savefd);
1821             return;
1822         }
1823         if (filemap[fd].tname == Empty && shp->exitval == 0) {
1824             off_t offset = lseek(origfd, 0, SEEK_CUR);
1825             if (offset >= 0) ftruncate(origfd, offset);
1826         } else if (filemap[fd].tname) {
1827             io_usename(shp, filemap[fd].tname, NULL, origfd, shp->exitval ? 2 : 1);
1828         }
1829         sh_close(origfd);
1830         if ((savefd = filemap[fd].save_fd) >= 0) {
1831             int dupflag = (shp->fdstatus[origfd] & IOCLEX) ? F_DUPFD_CLOEXEC : F_DUPFD;
1832             if (!savestr) sh_fcntl(savefd, dupflag, origfd);
1833             if (savefd == job.fd) job.fd = origfd;
1834             shp->fdstatus[origfd] = shp->fdstatus[savefd];
1835             // Turn off close-on-exec if flag if necessary.
1836             if (origfd <= 2) {
1837                 // It is unclear what conditions will cause us to attempt to swap entries when the
1838                 // `savefd` entry is NULL but it happens a lot. When it does  `sfswap()` returns
1839                 // NULL to indicate failure.
1840                 if (shp->sftable[savefd]) {
1841                     Sfio_t *sfio_orig = shp->sftable[origfd];
1842                     if (sfswap(shp->sftable[savefd], sfio_orig) != sfio_orig) abort();
1843                 }
1844                 if (origfd == 0) shp->st.ioset = 0;
1845             } else {
1846                 shp->sftable[origfd] = shp->sftable[savefd];
1847             }
1848             shp->sftable[savefd] = 0;
1849             sh_close(savefd);
1850         } else {
1851             shp->fdstatus[origfd] = IOCLOSE;
1852         }
1853     }
1854     if (!flag) {
1855         // Keep file descriptors for subshell restore.
1856         for (fd = last; fd < shp->topfd; fd++) {
1857             if (filemap[fd].subshell) filemap[last++] = filemap[fd];
1858         }
1859     }
1860     if (last < shp->topfd) shp->topfd = last;
1861 }
1862 
1863 //
1864 // Returns access information on open file <fd>.
1865 // Returns -1 for failure, 0 for success.
1866 // <mode> is the same as for access().
1867 //
sh_ioaccess(int fd,int mode)1868 int sh_ioaccess(int fd, int mode) {
1869     Shell_t *shp = sh_getinterp();
1870     int flags;
1871 
1872     if (mode == X_OK) return -1;
1873     if ((flags = sh_iocheckfd(shp, fd, fd)) != IOCLOSE) {
1874         if (mode == F_OK) return 0;
1875         if (mode == R_OK && (flags & IOREAD)) return 0;
1876         if (mode == W_OK && (flags & IOWRITE)) return 0;
1877     }
1878     return -1;
1879 }
1880 
1881 //
1882 // Handle interrupts for slow streams.
1883 //
slowexcept(Sfio_t * iop,int type,void * data,Sfdisc_t * handle)1884 static_fn int slowexcept(Sfio_t *iop, int type, void *data, Sfdisc_t *handle) {
1885     UNUSED(data);
1886     Shell_t *shp = ((struct Iodisc *)handle)->sh;
1887     int n, fno;
1888     UNUSED(handle);
1889 
1890     if (type == SF_DPOP || type == SF_FINAL) free(handle);
1891     if (type == SF_WRITE && ERROR_PIPE(errno)) {
1892         sfpurge(iop);
1893         return -1;
1894     }
1895     if (type != SF_READ) return 0;
1896     if ((shp->trapnote & (SH_SIGSET | SH_SIGTRAP)) && errno != EIO && errno != ENXIO) errno = EINTR;
1897     fno = sffileno(iop);
1898     if ((n = sfvalue(iop)) <= 0) {
1899 #ifndef FNDELAY
1900 #ifdef O_NDELAY
1901         if (errno == 0 && (n = fcntl(fno, F_GETFL, 0)) & O_NDELAY) {
1902             n &= ~O_NDELAY;
1903             fcntl(fno, F_SETFL, n);
1904             return 1;
1905         }
1906 #endif /* O_NDELAY */
1907 #endif /* !FNDELAY */
1908 #ifdef O_NONBLOCK
1909         if (errno == EAGAIN) {
1910             n = fcntl(fno, F_GETFL, 0);
1911             n &= ~O_NONBLOCK;
1912             fcntl(fno, F_SETFL, n);
1913             return 1;
1914         }
1915 #endif /* O_NONBLOCK */
1916         if (errno != EINTR) {
1917             return 0;
1918         } else if (shp->bltinfun && (shp->trapnote & SH_SIGTRAP) && shp->lastsig) {
1919             return -1;
1920         }
1921         n = 1;
1922         sh_onstate(shp, SH_TTYWAIT);
1923     } else {
1924         n = 0;
1925     }
1926     if (shp->bltinfun && shp->bltindata.sigset) return -1;
1927     errno = 0;
1928     if (shp->trapnote & SH_SIGSET) {
1929         if (isatty(fno)) sfputc(sfstderr, '\n');
1930         sh_exit(shp, SH_EXITSIG);
1931     }
1932     if (shp->trapnote & SH_SIGTRAP) sh_chktrap(shp);
1933     return n;
1934 }
1935 
1936 //
1937 // Called when slowread times out.
1938 //
time_grace(void * handle)1939 static_fn void time_grace(void *handle) {
1940     Shell_t *shp = handle;
1941     timeout = NULL;
1942 
1943     if (sh_isstate(shp, SH_GRACE)) {
1944         sh_offstate(shp, SH_GRACE);
1945         if (!sh_isstate(shp, SH_INTERACTIVE)) return;
1946         shp->jmplist->mode = SH_JMPEXIT;
1947         errormsg(SH_DICT, 2, e_timeout);
1948         shp->trapnote |= SH_SIGSET;
1949         return;
1950     }
1951     errormsg(SH_DICT, 0, e_timewarn);
1952     sh_onstate(shp, SH_GRACE);
1953     sh_sigaction(SIGALRM, SIG_UNBLOCK);
1954     shp->trapnote |= SH_SIGTRAP;
1955 }
1956 
piperead(Sfio_t * iop,void * buff,size_t size,Sfdisc_t * handle)1957 static_fn ssize_t piperead(Sfio_t *iop, void *buff, size_t size, Sfdisc_t *handle) {
1958     Shell_t *shp = ((struct Iodisc *)handle)->sh;
1959     int fd = sffileno(iop);
1960 
1961     if (job.waitsafe && job.savesig) {
1962         job_lock();
1963         job_unlock();
1964     }
1965     if (shp->trapnote) {
1966         errno = EINTR;
1967         return -1;
1968     }
1969     if (sh_isstate(shp, SH_INTERACTIVE) && sffileno(iop) == 0 &&
1970         io_prompt(shp, iop, shp->nextprompt) < 0 && errno == EIO) {
1971         return 0;
1972     }
1973     sh_onstate(shp, SH_TTYWAIT);
1974     if (!(shp->fdstatus[fd] & IOCLEX) && (sfset(iop, 0, 0) & SF_SHARE)) {
1975         size = ed_read(shgd->ed_context, fd, (char *)buff, size, 0);
1976     } else {
1977         size = sfrd(iop, buff, size, handle);
1978     }
1979     sh_offstate(shp, SH_TTYWAIT);
1980     return size;
1981 }
1982 
1983 //
1984 // This is the read discipline that is applied to slow devices. This routine
1985 // takes care of prompting for input.
1986 //
slowread(Sfio_t * iop,void * buff,size_t size,Sfdisc_t * handle)1987 static_fn ssize_t slowread(Sfio_t *iop, void *buff, size_t size, Sfdisc_t *handle) {
1988     Shell_t *shp = ((struct Iodisc *)handle)->sh;
1989     int (*readf)(void *, int, char *, int, int);
1990     int reedit = 0;
1991     ssize_t rsize;
1992     char *xp = NULL;
1993 
1994     if (sh_isoption(shp, SH_EMACS) || sh_isoption(shp, SH_GMACS)) {
1995         readf = ed_emacsread;
1996     } else if (sh_isoption(shp, SH_VI) || mbwide()) {
1997         readf = ed_viread;
1998     } else {
1999         readf = ed_read;
2000     }
2001     if (shp->trapnote) {
2002         errno = EINTR;
2003         return -1;
2004     }
2005 
2006     while (1) {
2007         if (io_prompt(shp, iop, shp->nextprompt) < 0 && errno == EIO) return 0;
2008         if (shp->timeout) {
2009             timeout = sh_timeradd(sh_isstate(shp, SH_GRACE) ? 1000L * TGRACE : 1000L * shp->timeout,
2010                                   0, time_grace, shp);
2011         }
2012         rsize = (*readf)(shgd->ed_context, sffileno(iop), (char *)buff, size, reedit);
2013         if (timeout) {
2014             timerdel(timeout);
2015             timeout = NULL;
2016         }
2017 
2018         if (rsize == -1) return -1;
2019 
2020         if (!(rsize && *(char *)buff != '\n' && shp->nextprompt == 1 &&
2021               sh_isoption(shp, SH_HISTEXPAND))) {
2022             break;
2023         }
2024 
2025         ((char *)buff)[rsize] = '\0';
2026         if (xp) {
2027             free(xp);
2028             xp = NULL;
2029         }
2030 
2031         int r = hist_expand(shp, buff, &xp);
2032         if ((r & (HIST_EVENT | HIST_PRINT)) && !(r & HIST_ERROR) && xp) {
2033             strlcpy(buff, xp, size);
2034             rsize = strlen(buff);
2035             if (!sh_isoption(shp, SH_HISTVERIFY) || readf == ed_read) {
2036                 sfputr(sfstderr, xp, -1);
2037                 break;
2038             }
2039             reedit = rsize - 1;
2040         } else if ((r & HIST_ERROR) && sh_isoption(shp, SH_HISTREEDIT)) {
2041             reedit = rsize - 1;
2042         } else {
2043             if (r & (HIST_ERROR | HIST_PRINT)) {
2044                 *(char *)buff = '\n';
2045                 rsize = 1;
2046             }
2047             break;
2048         }
2049     }
2050 
2051     return rsize;
2052 }
2053 
2054 //
2055 // Check and return the attributes for a file descriptor.
2056 //
sh_iocheckfd(Shell_t * shp,int fd,int fn)2057 int sh_iocheckfd(Shell_t *shp, int fd, int fn) {
2058     int flags, n;
2059 
2060     if ((n = shp->fdstatus[fd]) & IOCLOSE) return n;
2061     if (!(n & (IOREAD | IOWRITE))) {
2062 #ifdef F_GETFL
2063         if ((flags = fcntl(fd, F_GETFL, 0)) < 0) {
2064             shp->fdstatus[fd] = IOCLOSE;
2065             return IOCLOSE;
2066         }
2067         if ((flags & O_ACCMODE) != O_WRONLY) n |= IOREAD;
2068         if ((flags & O_ACCMODE) != O_RDONLY) n |= IOWRITE;
2069 #else
2070         struct stat statb;
2071         if ((flags = fstat(fd, &statb)) < 0) {
2072             shp->fdstatus[fd] = IOCLOSE;
2073             return IOCLOSE;
2074         }
2075         n |= (IOREAD | IOWRITE);
2076         if (read(fd, "", 0) < 0) n &= ~IOREAD;
2077 #endif /* F_GETFL */
2078     }
2079     if (!(n & (IOSEEK | IONOSEEK))) {
2080         struct stat statb;
2081         Sfio_t *sp = shp->sftable[fd];
2082         // /dev/null check is a workaround for select bug.
2083         static ino_t null_ino;
2084         static dev_t null_dev;
2085         shp->sftable[fd] = 0;
2086         if (null_ino == 0 && sh_stat("/dev/null", &statb) >= 0) {
2087             null_ino = statb.st_ino;
2088             null_dev = statb.st_dev;
2089         }
2090         if (tty_check(fd)) n |= IOTTY;
2091         if (lseek(fd, 0, SEEK_CUR) < 0) {
2092             n |= IONOSEEK;
2093 #ifdef S_ISSOCK
2094             if ((fstat(fd, &statb) >= 0) && S_ISSOCK(statb.st_mode)) {
2095                 n |= IOREAD | IOWRITE;
2096 #if _socketpair_shutdown_mode
2097                 if (!(statb.st_mode & S_IRUSR)) {
2098                     n &= ~IOREAD;
2099                 } else if (!(statb.st_mode & S_IWUSR)) {
2100                     n &= ~IOWRITE;
2101                 }
2102 #endif
2103             }
2104 #endif /* S_ISSOCK */
2105         } else if ((fstat(fd, &statb) >= 0) &&
2106                    (S_ISFIFO(statb.st_mode) ||
2107 #ifdef S_ISSOCK
2108                     S_ISSOCK(statb.st_mode) ||
2109 #endif /* S_ISSOCK */
2110                     /* The following is for sockets on the sgi */
2111                     (statb.st_ino == 0 &&
2112                      (statb.st_mode & ~(S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH |
2113                                         S_IXUSR | S_IXGRP | S_IXOTH | S_ISUID | S_ISGID)) == 0) ||
2114                     (S_ISCHR(statb.st_mode) &&
2115                      (statb.st_ino != null_ino || statb.st_dev != null_dev)))) {
2116             n |= IONOSEEK;
2117         } else {
2118             n |= IOSEEK;
2119         }
2120         shp->sftable[fd] = sp;
2121     }
2122     if (fd == 0) {
2123         n &= ~IOWRITE;
2124     } else if (fd == 1) {
2125         n &= ~IOREAD;
2126     }
2127     shp->fdstatus[fn] = n;
2128     return n;
2129 }
2130 
2131 //
2132 // Display prompt PS<flag> on standard error.
2133 //
io_prompt(Shell_t * shp,Sfio_t * iop,int flag)2134 static_fn int io_prompt(Shell_t *shp, Sfio_t *iop, int flag) {
2135     char *cp;
2136     char buff;
2137     char *endprompt;
2138     static short cmdno;
2139     int sfflags;
2140 
2141     if (flag < 3 && !sh_isstate(shp, SH_INTERACTIVE)) flag = 0;
2142     if (flag == 2 && sfpkrd(sffileno(iop), &buff, 1, '\n', 0, 1) >= 0) flag = 0;
2143     if (flag == 0) return sfsync(sfstderr);
2144     sfflags = sfset(sfstderr, SF_SHARE | SF_PUBLIC | SF_READ, 0);
2145     if (!(shp->prompt = (char *)sfreserve(sfstderr, 0, 0))) shp->prompt = "";
2146     sh_onstate(shp, SH_IOPROMPT);
2147     switch (flag) {
2148         case 1: {
2149             int c;
2150 #if defined(TIOCLBIC) && defined(LFLUSHO)
2151             if (!sh_isoption(shp, SH_VI) && !sh_isoption(shp, SH_EMACS) &&
2152                 !sh_isoption(shp, SH_GMACS)) {
2153                 // Re-enable output in case the user has disabled it.  Not needed with edit mode.
2154                 int mode = LFLUSHO;
2155                 ioctl(sffileno(sfstderr), TIOCLBIC, &mode);
2156             }
2157 #endif /* TIOCLBIC */
2158             cp = sh_mactry(shp, nv_getval(sh_scoped(shp, VAR_PS1)));
2159             shp->exitval = 0;
2160             for (int escape_index = 0; (c = *cp); cp++) {
2161                 if ((escape_index == 0 && c == ESC) ||
2162                     /* Track escape sequences, and don't expand ! if it appears at 2nd position */
2163                     (escape_index == 1 && (c == '[' || c == ']' || c == '('))) {
2164                     escape_index++;
2165                 } else if (c == HIST_CHAR && escape_index == 0) {
2166                     c = *++cp;             // look at next character
2167                     if (c != HIST_CHAR) {  // print out line number if not !!
2168                         sfprintf(sfstderr, "%d",
2169                                  shp->gd->hist_ptr ? (int)shp->gd->hist_ptr->histind : ++cmdno);
2170                     }
2171                     if (c == 0) goto done;
2172                 } else {
2173                     escape_index = 0;
2174                 }
2175                 sfputc(sfstderr, c);
2176             }
2177             goto done;
2178         }
2179         case 2: {
2180             cp = nv_getval(sh_scoped(shp, VAR_PS2));
2181             break;
2182         }
2183         case 3: {
2184             cp = nv_getval(sh_scoped(shp, VAR_PS3));
2185             break;
2186         }
2187         default: { goto done; }
2188     }
2189     if (cp) sfputr(sfstderr, cp, -1);
2190 
2191 done:
2192     sh_offstate(shp, SH_IOPROMPT);
2193     if (*shp->prompt && (endprompt = (char *)sfreserve(sfstderr, 0, 0))) *endprompt = 0;
2194     sfset(sfstderr, (sfflags & SF_READ) | SF_SHARE | SF_PUBLIC, 1);
2195     return sfsync(sfstderr);
2196 }
2197 
2198 //
2199 // This discipline is inserted on write pipes to prevent SIGPIPE from causing
2200 // an infinite loop.
2201 //
pipeexcept(Sfio_t * iop,int mode,void * data,Sfdisc_t * handle)2202 static_fn int pipeexcept(Sfio_t *iop, int mode, void *data, Sfdisc_t *handle) {
2203     UNUSED(data);
2204     if (mode == SF_DPOP || mode == SF_FINAL) {
2205         free(handle);
2206     } else if (mode == SF_WRITE && ERROR_PIPE(errno)) {
2207         sfpurge(iop);
2208         return -1;
2209     }
2210     return 0;
2211 }
2212 
2213 //
2214 // Keep track of each stream that is opened and closed.
2215 //
sftrack(Sfio_t * sp,int flag,void * data)2216 static_fn void sftrack(Sfio_t *sp, int flag, void *data) {
2217     Shell_t *shp = sh_getinterp();
2218     int fd = sffileno(sp);
2219     checkpt_t *pp;
2220     int mode;
2221     int newfd = (uintptr_t)data;
2222 
2223     if (flag == SF_SETFD || flag == SF_CLOSING) {
2224         if (newfd < 0) flag = SF_CLOSING;
2225         if (fdnotify) (*fdnotify)(sffileno(sp), flag == SF_CLOSING ? -1 : newfd);
2226     }
2227 #ifdef DEBUG
2228     if (flag == SF_READ || flag == SF_WRITE) {
2229         char *z = fmtbase(getpid(), 0, 0);
2230         write(STDERR_FILENO, z, strlen(z));
2231         write(STDERR_FILENO, ": ", 2);
2232         write(STDERR_FILENO, "attempt to ", 11);
2233         if (flag == SF_READ) {
2234             write(STDERR_FILENO, "read from", 9);
2235         } else {
2236             write(STDERR_FILENO, "write to", 8);
2237         }
2238         write(STDERR_FILENO, " locked stream\n", 15);
2239         return;
2240     }
2241 #endif
2242     if (fd < 0 || fd == PSEUDOFD || !sh_iovalidfd(shp, fd)) return;
2243     if (sh_isstate(shp, SH_NOTRACK)) return;
2244 
2245     mode = sfset(sp, 0, 0);
2246     if (sp == shp->heredocs && fd < 10 && flag == SF_SETFD) {
2247         fd = sfsetfd(sp, 10);
2248         (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
2249     }
2250     if (fd < 3) return;
2251     if (flag == SF_NEW) {
2252         if (!shp->sftable[fd] && shp->fdstatus[fd] == IOCLOSE) {
2253             shp->sftable[fd] = sp;
2254             flag = (mode & SF_WRITE) ? IOWRITE : 0;
2255             if (mode & SF_READ) flag |= IOREAD;
2256             shp->fdstatus[fd] = flag;
2257             sh_iostream(shp, fd, fd);
2258         }
2259         pp = shp->jmplist;
2260         if (pp && pp->mode == SH_JMPCMD) {
2261             struct openlist *item;
2262             // Record open file descriptors so they can be closed in case a
2263             // longjmp prevents built-ins from cleanup.
2264             item = calloc(1, sizeof(struct openlist));
2265             item->strm = sp;
2266             item->next = pp->olist;
2267             pp->olist = item;
2268         }
2269         if (fdnotify) (*fdnotify)(-1, sffileno(sp));
2270     } else if (flag == SF_CLOSING || (flag == SF_SETFD && newfd <= 2)) {
2271         shp->sftable[fd] = 0;
2272         shp->fdstatus[fd] = IOCLOSE;
2273         pp = shp->jmplist;
2274         if (pp) {
2275             struct openlist *item;
2276             for (item = pp->olist; item; item = item->next) {
2277                 if (item->strm == sp) {
2278                     item->strm = NULL;
2279                     break;
2280                 }
2281             }
2282         }
2283     }
2284 }
2285 
2286 struct eval {
2287     Sfdisc_t disc;
2288     const char **argv;
2289     size_t slen;
2290     char addspace;
2291 };
2292 
2293 //
2294 // Create a stream consisting of a space separated argv[] list.
2295 //
sh_sfeval(const char * argv[])2296 Sfio_t *sh_sfeval(const char *argv[]) {
2297     Sfio_t *iop;
2298     const char *cp;
2299 
2300     if (argv[1]) {
2301         cp = "";
2302     } else {
2303         cp = argv[0];
2304     }
2305     iop = sfopen(NULL, (char *)cp, "s");
2306     if (argv[1]) {
2307         struct eval *ep;
2308         ep = calloc(1, sizeof(struct eval));
2309         ep->disc = eval_disc;
2310         ep->argv = argv;
2311         ep->slen = -1;
2312         ep->addspace = 0;
2313         sfdisc(iop, &ep->disc);
2314     }
2315     return iop;
2316 }
2317 
2318 //
2319 // This code gets called whenever an end of string is found with eval.
2320 //
eval_exceptf(Sfio_t * iop,int type,void * data,Sfdisc_t * handle)2321 static_fn int eval_exceptf(Sfio_t *iop, int type, void *data, Sfdisc_t *handle) {
2322     UNUSED(data);
2323     struct eval *ep = (struct eval *)handle;
2324     const char *cp;
2325     size_t len;
2326 
2327     // No more to do.
2328     if (type != SF_READ || !(cp = ep->argv[0])) {
2329         if (type == SF_CLOSING) {
2330             sfdisc(iop, SF_POPDISC);
2331         } else if (type == SF_DPOP || type == SF_FINAL) {
2332             free(ep);
2333         }
2334         return 0;
2335     }
2336 
2337     if (!ep->addspace) {
2338         ep->slen = len = strlen(cp);  // get the length of this string
2339         ep->argv++;                   // move to next string
2340     } else {                          // insert space between arguments
2341         len = 1;
2342         cp = " ";
2343     }
2344     // Insert the new string.
2345     sfsetbuf(iop, cp, len);
2346     ep->addspace = !ep->addspace;
2347     return 1;
2348 }
2349 
2350 //
2351 // This routine returns a stream pointer to a segment of length <size> from the
2352 // stream <sp> starting at offset <offset>. The stream can be read with the
2353 // normal stream operations.
2354 //
subopen(Shell_t * shp,Sfio_t * sp,off_t offset,long size)2355 static_fn Sfio_t *subopen(Shell_t *shp, Sfio_t *sp, off_t offset, long size) {
2356     UNUSED(shp);
2357     struct subfile *disp;
2358 
2359     if (sfseek(sp, offset, SEEK_SET) < 0) return NULL;
2360     disp = malloc(sizeof(struct subfile));
2361     disp->io_buffer = malloc(IOBSIZE);
2362     disp->disc = sub_disc;
2363     disp->oldsp = sp;
2364     disp->offset = offset;
2365     disp->size = disp->left = size;
2366     sp = sfnew(NULL, disp->io_buffer, IOBSIZE, PSEUDOFD, SF_READ);
2367     sfdisc(sp, &disp->disc);
2368     return sp;
2369 }
2370 
2371 //
2372 // Read function for subfile discipline.
2373 //
subread(Sfio_t * sp,void * buff,size_t size,Sfdisc_t * handle)2374 static_fn ssize_t subread(Sfio_t *sp, void *buff, size_t size, Sfdisc_t *handle) {
2375     UNUSED(sp);
2376     struct subfile *disp = (struct subfile *)handle;
2377     ssize_t n;
2378 
2379     sfseek(disp->oldsp, disp->offset, SEEK_SET);
2380     if (disp->left == 0) return 0;
2381     if (size > disp->left) size = disp->left;
2382     disp->left -= size;
2383     n = sfread(disp->oldsp, buff, size);
2384     if (size > 0) disp->offset += size;
2385     return n;
2386 }
2387 
2388 //
2389 // Exception handler for subfile discipline.
2390 //
subexcept(Sfio_t * sp,int mode,void * data,Sfdisc_t * handle)2391 static_fn int subexcept(Sfio_t *sp, int mode, void *data, Sfdisc_t *handle) {
2392     UNUSED(data);
2393     struct subfile *disp = (struct subfile *)handle;
2394 
2395     if (mode == SF_CLOSING) {
2396         sfdisc(sp, SF_POPDISC);
2397         sfsetfd(sp, -1);
2398         return 0;
2399     } else if (disp && (mode == SF_DPOP || mode == SF_FINAL)) {
2400         free(disp->io_buffer);
2401         free(disp);
2402         return 0;
2403     } else if (mode == SF_ATEXIT) {
2404         sfdisc(sp, SF_POPDISC);
2405         return 0;
2406     } else if (mode == SF_READ) {
2407         return 0;
2408     }
2409     return -1;
2410 }
2411 
2412 #define NROW 15  /* number of rows before going to multi-columns */
2413 #define LBLSIZ 3 /* size of label field and interfield spacing */
2414 
2415 //
2416 // Print a list of arguments in columns.
2417 //
sh_menu(Shell_t * shp,Sfio_t * outfile,int argn,char * argv[])2418 void sh_menu(Shell_t *shp, Sfio_t *outfile, int argn, char *argv[]) {
2419     int i, j;
2420     char **arg;
2421     int nrow, ncol = 1, ndigits = 1;
2422     int fldsize, wsize = ed_window();
2423     char *cp = nv_getval(sh_scoped(shp, VAR_LINES));
2424     nrow = (cp ? 1 + 2 * ((int)strtol(cp, NULL, 10) / 3) : NROW);
2425     for (i = argn; i >= 10; i /= 10) ndigits++;
2426     if (argn < nrow) {
2427         nrow = argn;
2428         goto skip;
2429     }
2430     i = 0;
2431     for (arg = argv; *arg; arg++) {
2432         if ((j = strlen(*arg)) > i) i = j;
2433     }
2434     i += (ndigits + LBLSIZ);
2435     if (i < wsize) ncol = wsize / i;
2436     if (argn > nrow * ncol) {
2437         nrow = 1 + (argn - 1) / ncol;
2438     } else {
2439         ncol = 1 + (argn - 1) / nrow;
2440         nrow = 1 + (argn - 1) / ncol;
2441     }
2442 
2443 skip:
2444     fldsize = (wsize / ncol) - (ndigits + LBLSIZ);
2445     for (i = 0; i < nrow; i++) {
2446         if (shp->trapnote & SH_SIGSET) return;
2447         j = i;
2448         while (1) {
2449             arg = argv + j;
2450             sfprintf(outfile, "%*d) %s", ndigits, j + 1, *arg);
2451             j += nrow;
2452             if (j >= argn) break;
2453             sfnputc(outfile, ' ', fldsize - strlen(*arg ? *arg : ""));
2454         }
2455         sfputc(outfile, '\n');
2456     }
2457 }
2458 
2459 #undef read
2460 //
2461 // Shell version of read() for user added builtins.
2462 //
sh_read(int fd,void * buff,size_t n)2463 ssize_t sh_read(int fd, void *buff, size_t n) {
2464     int r, err = errno;
2465     Shell_t *shp = sh_getinterp();
2466     Sfio_t *sp;
2467 
2468     sp = shp->sftable[fd];
2469     if (sp) return sfread(sp, buff, n);
2470     while ((r = read(fd, buff, n)) < 0 && errno == EINTR) errno = err;
2471     return r;
2472 }
2473 
2474 #undef write
2475 //
2476 // Shell version of write() for user added builtins.
2477 //
sh_write(int fd,const void * buff,size_t n)2478 ssize_t sh_write(int fd, const void *buff, size_t n) {
2479     int r, err = errno;
2480     Shell_t *shp = sh_getinterp();
2481     Sfio_t *sp;
2482 
2483     if (!sh_iovalidfd(shp, fd)) abort();
2484 
2485     sp = shp->sftable[fd];
2486     if (sp) return sfwrite(sp, buff, n);
2487     while ((r = write(fd, buff, n)) < 0 && errno == EINTR) errno = err;
2488     return r;
2489 }
2490 
2491 //
2492 // Shell version of lseek() for user added builtins.
2493 //
sh_seek(int fd,off_t offset,int whence)2494 off_t sh_seek(int fd, off_t offset, int whence) {
2495     Shell_t *shp = sh_getinterp();
2496     Sfio_t *sp;
2497     if (!sh_iovalidfd(shp, fd)) abort();
2498     if ((sp = shp->sftable[fd]) && (sfset(sp, 0, 0) & (SF_READ | SF_WRITE))) {
2499         return sfseek(sp, offset, whence);
2500     }
2501     return lseek(fd, offset, whence);
2502 }
2503 
sh_dup(int old)2504 int sh_dup(int old) {
2505     Shell_t *shp = sh_getinterp();
2506     int fd = dup(old);
2507     if (!sh_iovalidfd(shp, fd)) abort();
2508     if (fd >= 0) {
2509         if (shp->fdstatus[old] == IOCLOSE) shp->fdstatus[old] = 0;
2510         shp->fdstatus[fd] = (shp->fdstatus[old] & ~IOCLEX);
2511         if (fdnotify) (*fdnotify)(old, fd);
2512     }
2513     return fd;
2514 }
2515 
sh_fcntl(int fd,int op,...)2516 int sh_fcntl(int fd, int op, ...) {
2517     Shell_t *shp = sh_getinterp();
2518     int newfd, arg;
2519     va_list ap;
2520 
2521     va_start(ap, op);
2522     arg = va_arg(ap, int);
2523     va_end(ap);
2524     newfd = fcntl(fd, op, arg);
2525     if (newfd < 0) return newfd;
2526 
2527     switch (op) {
2528         case F_DUPFD:
2529         case F_DUPFD_CLOEXEC: {
2530             if (shp->fdstatus[fd] == IOCLOSE) shp->fdstatus[fd] = 0;
2531             if (newfd >= shp->gd->lim.open_max && !sh_iovalidfd(shp, newfd)) abort();
2532             if (op == F_DUPFD) {
2533                 shp->fdstatus[newfd] = (shp->fdstatus[fd] & ~IOCLEX);
2534             } else {
2535                 shp->fdstatus[newfd] = (shp->fdstatus[fd] | IOCLEX);
2536             }
2537             if (fdnotify) (*fdnotify)(fd, newfd);
2538             break;
2539         }
2540         case F_SETFD: {
2541             if (shp->fdstatus[fd] == IOCLOSE) shp->fdstatus[fd] = 0;
2542             if (arg & FD_CLOEXEC) {
2543                 shp->fdstatus[fd] |= IOCLEX;
2544             } else {
2545                 shp->fdstatus[fd] &= ~IOCLEX;
2546             }
2547         }
2548         default: { break; }
2549     }
2550 
2551     return newfd;
2552 }
2553 
sh_umask(mode_t m)2554 mode_t sh_umask(mode_t m) {
2555     Shell_t *shp = sh_getinterp();
2556     shp->mask = m;
2557     return umask(m);
2558 }
2559 
2560 //
2561 // Give file descriptor <fd> and <mode>, return an iostream pointer.
2562 // <mode> must be SF_READ or SF_WRITE.
2563 // <fd> must be a non-negative number ofr SH_IOCOPROCESS or SH_IOHISTFILE.
2564 // Returns NULL on failure and may set errno.
2565 //
sh_iogetiop(int fd,int mode)2566 Sfio_t *sh_iogetiop(int fd, int mode) {
2567     Shell_t *shp = sh_getinterp();
2568     if (!sh_iovalidfd(shp, fd)) abort();
2569     int n;
2570     Sfio_t *iop = NULL;
2571 
2572     if (mode != SF_READ && mode != SF_WRITE) {
2573         errno = EINVAL;
2574         return iop;
2575     }
2576     switch (fd) {
2577         case SH_IOHISTFILE: {
2578             if (!sh_histinit(shp)) return iop;
2579             fd = sffileno(shp->gd->hist_ptr->histfp);
2580             break;
2581         }
2582         case SH_IOCOPROCESS: {
2583             if (mode == SF_WRITE) {
2584                 fd = shp->coutpipe;
2585             } else {
2586                 fd = shp->cpipe[0];
2587             }
2588             break;
2589         }
2590         default: {
2591             if (fd < 0 || !sh_iovalidfd(shp, fd)) fd = -1;
2592         }
2593     }
2594     if (fd < 0) {
2595         errno = EBADF;
2596         return iop;
2597     }
2598     if (!(n = shp->fdstatus[fd])) n = sh_iocheckfd(shp, fd, fd);
2599     if (mode == SF_WRITE && !(n & IOWRITE)) return iop;
2600     if (mode == SF_READ && !(n & IOREAD)) return iop;
2601     iop = shp->sftable[fd];
2602     if (!iop) iop = sh_iostream(shp, fd, fd);
2603     return iop;
2604 }
2605 
2606 typedef int (*Notify_f)(int, int);
2607 
sh_fdnotify(Notify_f notify)2608 Notify_f sh_fdnotify(Notify_f notify) {
2609     Notify_f old;
2610     old = fdnotify;
2611     fdnotify = notify;
2612     return old;
2613 }
2614 
2615 // This function is commented out because it is currently unused but might be useful in the future.
2616 // It's original use was by the `mkservice` and `poll` builtins added for the ksh93v- build that
2617 // have since been removed.
2618 #if 0
2619 Sfio_t *sh_fd2sfio(Shell_t *shp, int fd) {
2620     int status;
2621     Sfio_t *sp = shp->sftable[fd];
2622 
2623     if (!sp && (status = sh_iocheckfd(shp, fd, fd)) != IOCLOSE) {
2624         int flags = 0;
2625         if (status & IOREAD) flags |= SF_READ;
2626         if (status & IOWRITE) flags |= SF_WRITE;
2627         sp = sfnew(NULL, NULL, -1, fd, flags);
2628         shp->sftable[fd] = sp;
2629     }
2630     return sp;
2631 }
2632 #endif
2633 
sh_pathopen(Shell_t * shp,const char * cp)2634 Sfio_t *sh_pathopen(Shell_t *shp, const char *cp) {
2635     int n;
2636 #ifdef PATH_BFPATH
2637     if ((n = path_open(shp, cp, path_get(shp, cp))) < 0) n = path_open(shp, cp, NULL);
2638 #else
2639     if ((n = path_open(shp, cp, path_get(cp))) < 0) n = path_open(shp, cp, "");
2640 #endif
2641     if (n < 0) {
2642         errormsg(SH_DICT, ERROR_system(1), e_open, cp);
2643         __builtin_unreachable();
2644     }
2645     return sh_iostream(shp, n, n);
2646 }
2647 
sh_isdevfd(const char * fd)2648 bool sh_isdevfd(const char *fd) {
2649     if (!fd || strncmp(fd, "/dev/fd/", 8) || fd[8] == 0) return false;
2650     for (fd = &fd[8]; *fd != '\0'; fd++) {
2651         if (*fd < '0' || *fd > '9') return false;
2652     }
2653     return true;
2654 }
2655 
2656 #undef fchdir
sh_fchdir(int fd)2657 int sh_fchdir(int fd) {
2658     int r, err = errno;
2659 
2660     while ((r = fchdir(fd)) < 0 && errno == EINTR) errno = err;
2661     return r;
2662 }
2663 
2664 #undef chdir
sh_chdir(const char * dir)2665 int sh_chdir(const char *dir) {
2666     int r, err = errno;
2667 
2668     while ((r = chdir(dir)) < 0 && errno == EINTR) errno = err;
2669     return r;
2670 }
2671 
2672 #undef stat
sh_stat(const char * path,struct stat * statb)2673 int sh_stat(const char *path, struct stat *statb) {
2674     int r, err = errno;
2675 
2676     while ((r = stat(path, statb)) < 0 && errno == EINTR) errno = err;
2677     return r;
2678 }
2679