static int herein(struct ioword *iop, char **resbuf) { int fd = -1; struct shf *shf; struct temp *h; int i; /* ksh -c 'cat <<EOF' can cause this... */ if (iop->heredoc == NULL && !(iop->ioflag & IOHERESTR)) { warningf(true, "%s missing", "here document"); /* special to iosetup(): don't print error */ return (-2); } /* lexer substitution flags */ i = (iop->ioflag & IOEVAL) ? (ONEWORD | HEREDOC) : 0; /* skip all the fd setup if we just want the value */ if (resbuf != NULL) return (hereinval(iop, i, resbuf, NULL)); /* * Create temp file to hold content (done before newenv * so temp doesn't get removed too soon). */ h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps); if (!(shf = h->shf) || (fd = binopen3(h->tffn, O_RDONLY, 0)) < 0) { i = errno; warningf(true, "can't %s temporary file %s: %s", !shf ? "create" : "open", h->tffn, cstrerror(i)); if (shf) shf_close(shf); /* special to iosetup(): don't print error */ return (-2); } if (hereinval(iop, i, NULL, shf) == -2) { close(fd); /* special to iosetup(): don't print error */ return (-2); } if (shf_close(shf) == -1) { i = errno; close(fd); warningf(true, "can't %s temporary file %s: %s", "write", h->tffn, cstrerror(i)); /* special to iosetup(): don't print error */ return (-2); } return (fd); }
struct temp * maketemp(Area *ap, Temp_type type, struct temp **tlist) { char *cp; size_t len; int i, j; struct temp *tp; const char *dir; struct stat sb; dir = tmpdir ? tmpdir : MKSH_DEFAULT_TMPDIR; /* add "/shXXXXXX.tmp" plus NUL */ len = strlen(dir); checkoktoadd(len, offsetof(struct temp, tffn[0]) + 14); tp = alloc(offsetof(struct temp, tffn[0]) + 14 + len, ap); tp->shf = NULL; tp->pid = procpid; tp->type = type; if (stat(dir, &sb) || !S_ISDIR(sb.st_mode)) { tp->tffn[0] = '\0'; goto maketemp_out; } cp = (void *)tp; cp += offsetof(struct temp, tffn[0]); memcpy(cp, dir, len); cp += len; memcpy(cp, "/shXXXXXX.tmp", 14); /* point to the first of six Xes */ cp += 3; /* cyclically attempt to open a temporary file */ do { /* generate random part of filename */ len = 0; do { cp[len++] = digits_lc[rndget() % 36]; } while (len < 6); /* check if this one works */ if ((i = binopen3(tp->tffn, O_CREAT | O_EXCL | O_RDWR, 0600)) < 0 && errno != EEXIST) goto maketemp_out; } while (i < 0); if (type == TT_FUNSUB) { /* map us high and mark as close-on-exec */ if ((j = savefd(i)) != i) { close(i); i = j; } /* operation mode for the shf */ j = SHF_RD; } else j = SHF_WR; /* shf_fdopen cannot fail, so no fd leak */ tp->shf = shf_fdopen(i, j, NULL); maketemp_out: tp->next = *tlist; *tlist = tp; return (tp); }
/* * set up redirection, saving old fds in e->savefd */ static int iosetup(struct ioword *iop, struct tbl *tp) { int u = -1; char *cp = iop->ioname; int iotype = iop->ioflag & IOTYPE; bool do_open = true, do_close = false; int flags = 0; struct ioword iotmp; struct stat statb; if (iotype != IOHERE) cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0)); /* Used for tracing and error messages to print expanded cp */ iotmp = *iop; iotmp.ioname = (iotype == IOHERE) ? NULL : cp; iotmp.ioflag |= IONAMEXP; if (Flag(FXTRACE)) { change_xtrace(2, false); fptreef(shl_xtrace, 0, "%R", &iotmp); change_xtrace(1, false); } switch (iotype) { case IOREAD: flags = O_RDONLY; break; case IOCAT: flags = O_WRONLY | O_APPEND | O_CREAT; break; case IOWRITE: flags = O_WRONLY | O_CREAT | O_TRUNC; /* * The stat() is here to allow redirections to * things like /dev/null without error. */ if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB) && (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode))) flags |= O_EXCL; break; case IORDWR: flags = O_RDWR | O_CREAT; break; case IOHERE: do_open = false; /* herein() returns -2 if error has been printed */ u = herein(iop, NULL); /* cp may have wrong name */ break; case IODUP: { const char *emsg; do_open = false; if (ksh_isdash(cp)) { /* prevent error return below */ u = 1009; do_close = true; } else if ((u = check_fd(cp, X_OK | ((iop->ioflag & IORDUP) ? R_OK : W_OK), &emsg)) < 0) { char *sp; warningf(true, "%s: %s", (sp = snptreef(NULL, 32, "%R", &iotmp)), emsg); afree(sp, ATEMP); return (-1); } if (u == (int)iop->unit) /* "dup from" == "dup to" */ return (0); break; } } if (do_open) { if (Flag(FRESTRICTED) && (flags & O_CREAT)) { warningf(true, "%s: %s", cp, "restricted"); return (-1); } u = binopen3(cp, flags, 0666); } if (u < 0) { /* herein() may already have printed message */ if (u == -1) { u = errno; warningf(true, "can't %s %s: %s", iotype == IODUP ? "dup" : (iotype == IOREAD || iotype == IOHERE) ? "open" : "create", cp, cstrerror(u)); } return (-1); } /* Do not save if it has already been redirected (i.e. "cat >x >y"). */ if (e->savefd[iop->unit] == 0) { /* If these are the same, it means unit was previously closed */ if (u == (int)iop->unit) e->savefd[iop->unit] = -1; else /* * c_exec() assumes e->savefd[fd] set for any * redirections. Ask savefd() not to close iop->unit; * this allows error messages to be seen if iop->unit * is 2; also means we can't lose the fd (eg, both * dup2 below and dup2 in restfd() failing). */ e->savefd[iop->unit] = savefd(iop->unit); } if (do_close) close(iop->unit); else if (u != (int)iop->unit) { if (ksh_dup2(u, iop->unit, true) < 0) { int eno; char *sp; eno = errno; warningf(true, "%s %s: %s", "can't finish (dup) redirection", (sp = snptreef(NULL, 32, "%R", &iotmp)), cstrerror(eno)); afree(sp, ATEMP); if (iotype != IODUP) close(u); return (-1); } if (iotype != IODUP) close(u); /* * Touching any co-process fd in an empty exec * causes the shell to close its copies */ else if (tp && tp->type == CSHELL && tp->val.f == c_exec) { if (iop->ioflag & IORDUP) /* possible exec <&p */ coproc_read_close(u); else /* possible exec >&p */ coproc_write_close(u); } } if (u == 2) /* Clear any write errors */ shf_reopen(2, SHF_WR, shl_out); return (0); }