/* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor. */ int check_fd(char *name, int mode, const char **emsgp) { int fd, fl; if (isdigit((unsigned char)name[0]) && !name[1]) { fd = name[0] - '0'; if ((fl = fcntl(fd, F_GETFL, 0)) < 0) { if (emsgp) *emsgp = "bad file descriptor"; return -1; } fl &= O_ACCMODE; /* X_OK is a kludge to disable this check for dups (x<&1): * historical shells never did this check (XXX don't know what * posix has to say). */ if (!(mode & X_OK) && fl != O_RDWR && (((mode & R_OK) && fl != O_RDONLY) || ((mode & W_OK) && fl != O_WRONLY))) { if (emsgp) *emsgp = (fl == O_WRONLY) ? "fd not open for reading" : "fd not open for writing"; return -1; } return fd; } else if (name[0] == 'p' && !name[1]) return coproc_getfd(mode, emsgp); if (emsgp) *emsgp = "illegal file descriptor name"; return -1; }
/* * Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor. */ int check_fd(const char *name, int mode, const char **emsgp) { int fd = 0, fl; if (name[0] == 'p' && !name[1]) return (coproc_getfd(mode, emsgp)); while (ksh_isdigit(*name)) { fd = (fd * 10) + *name - '0'; if (fd >= FDBASE) { if (emsgp) *emsgp = "file descriptor too large"; return (-1); } ++name; } if (*name) { if (emsgp) *emsgp = "illegal file descriptor name"; return (-1); } if ((fl = fcntl(fd, F_GETFL, 0)) < 0) { if (emsgp) *emsgp = "bad file descriptor"; return (-1); } fl &= O_ACCMODE; /* * X_OK is a kludge to disable this check for dups (x<&1): * historical shells never did this check (XXX don't know what * POSIX has to say). */ if (!(mode & X_OK) && fl != O_RDWR && ( ((mode & R_OK) && fl != O_RDONLY) || ((mode & W_OK) && fl != O_WRONLY))) { if (emsgp) *emsgp = (fl == O_WRONLY) ? "fd not open for reading" : "fd not open for writing"; return (-1); } return (fd); }
/* * Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor. */ int check_fd(const char *name, int mode, const char **emsgp) { int fd, fl; if (!name[0] || name[1]) goto illegal_fd_name; if (name[0] == 'p') return (coproc_getfd(mode, emsgp)); if (!ctype(name[0], C_DIGIT)) { illegal_fd_name: if (emsgp) *emsgp = "illegal file descriptor name"; return (-1); } if ((fl = fcntl((fd = ksh_numdig(name[0])), F_GETFL, 0)) < 0) { if (emsgp) *emsgp = "bad file descriptor"; return (-1); } fl &= O_ACCMODE; /* * X_OK is a kludge to disable this check for dups (x<&1): * historical shells never did this check (XXX don't know what * POSIX has to say). */ if (!(mode & X_OK) && fl != O_RDWR && ( ((mode & R_OK) && fl != O_RDONLY) || ((mode & W_OK) && fl != O_WRONLY))) { if (emsgp) *emsgp = (fl == O_WRONLY) ? "fd not open for reading" : "fd not open for writing"; return (-1); } return (fd); }
int c_read(char **wp) { int c = 0; int expand = 1, history = 0; int expanding; int ecode = 0; char *cp; int fd = 0; struct shf *shf; int optc; const char *emsg; XString cs, xs; struct tbl *vp; char *xp = NULL; while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != -1) switch (optc) { case 'p': if ((fd = coproc_getfd(R_OK, &emsg)) < 0) { bi_errorf("-p: %s", emsg); return 1; } break; case 'r': expand = 0; break; case 's': history = 1; break; case 'u': if (!*(cp = builtin_opt.optarg)) fd = 0; else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) { bi_errorf("-u: %s: %s", cp, emsg); return 1; } break; case '?': return 1; } wp += builtin_opt.optind; if (*wp == NULL) *--wp = "REPLY"; /* Since we can't necessarily seek backwards on non-regular files, * don't buffer them so we can't read too much. */ shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare); if ((cp = strchr(*wp, '?')) != NULL) { *cp = 0; if (isatty(fd)) { /* at&t ksh says it prints prompt on fd if it's open * for writing and is a tty, but it doesn't do it * (it also doesn't check the interactive flag, * as is indicated in the Kornshell book). */ shellf("%s", cp+1); } } /* If we are reading from the co-process for the first time, * make sure the other side of the pipe is closed first. This allows * the detection of eof. * * This is not compatible with at&t ksh... the fd is kept so another * coproc can be started with same output, however, this means eof * can't be detected... This is why it is closed here. * If this call is removed, remove the eof check below, too. * coproc_readw_close(fd); */ if (history) Xinit(xs, xp, 128, ATEMP); expanding = 0; Xinit(cs, cp, 128, ATEMP); for (; *wp != NULL; wp++) { for (cp = Xstring(cs, cp); ; ) { if (c == '\n' || c == EOF) break; while (1) { c = shf_getc(shf); if (c == '\0') continue; if (c == EOF && shf_error(shf) && shf_errno(shf) == EINTR) { /* Was the offending signal one that * would normally kill a process? * If so, pretend the read was killed. */ ecode = fatal_trap_check(); /* non fatal (eg, CHLD), carry on */ if (!ecode) { shf_clearerr(shf); continue; } } break; } if (history) { Xcheck(xs, xp); Xput(xs, xp, c); } Xcheck(cs, cp); if (expanding) { expanding = 0; if (c == '\n') { c = 0; if (Flag(FTALKING_I) && isatty(fd)) { /* set prompt in case this is * called from .profile or $ENV */ set_prompt(PS2, NULL); pprompt(prompt, 0); } } else if (c != EOF) Xput(cs, cp, c); continue; } if (expand && c == '\\') { expanding = 1; continue; } if (c == '\n' || c == EOF) break; if (ctype(c, C_IFS)) { if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS)) continue; if (wp[1]) break; } Xput(cs, cp, c); } /* strip trailing IFS white space from last variable */ if (!wp[1]) while (Xlength(cs, cp) && ctype(cp[-1], C_IFS) && ctype(cp[-1], C_IFSWS)) cp--; Xput(cs, cp, '\0'); vp = global(*wp); /* Must be done before setting export. */ if (vp->flag & RDONLY) { shf_flush(shf); bi_errorf("%s is read only", *wp); return 1; } if (Flag(FEXPORT)) typeset(*wp, EXPORT, 0, 0, 0); if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) { shf_flush(shf); return 1; } } shf_flush(shf); if (history) { Xput(xs, xp, '\0'); source->line++; histsave(source->line, Xstring(xs, xp), 1); Xfree(xs, xp); } /* if this is the co-process fd, close the file descriptor * (can get eof if and only if all processes are have died, ie, * coproc.njobs is 0 and the pipe is closed). */ if (c == EOF && !ecode) coproc_read_close(fd); return ecode ? ecode : c == EOF; }