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