diff options
Diffstat (limited to 'io.c')
-rw-r--r-- | io.c | 271 |
1 files changed, 232 insertions, 39 deletions
@@ -206,12 +206,20 @@ static int get_a_record(char **out, IOBUF *iop, int *errcode); static void free_rp(struct redirect *rp); static int inetfile(const char *str, int *length, int *family); +static NODE *in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx); +static long get_read_timeout(IOBUF *iop); +static ssize_t read_with_timeout(int fd, char *buf, size_t size); + #if defined(HAVE_POPEN_H) #include "popen.h" #endif +static int read_can_timeout = FALSE; +static long read_timeout; +static long read_default_timeout; + static struct redirect *red_head = NULL; -static NODE *RS; +static NODE *RS = NULL; static Regexp *RS_re_yes_case; static Regexp *RS_re_no_case; static Regexp *RS_regexp; @@ -225,6 +233,33 @@ extern NODE *ARGIND_node; extern NODE *ERRNO_node; extern NODE **fields_arr; + +void +init_io() +{ + long tmout; + + /* + * N.B.: all these hacks are to minimize the effect + * on programs that do not care about timeout. + */ + + /* Parse the env. variable only once */ + tmout = getenv_long("GAWK_READ_TIMEOUT"); + if (tmout > 0) { + read_default_timeout = tmout; + read_can_timeout = TRUE; + } + + /* + * PROCINFO entries for timeout are dynamic; + * We can't be any more specific than this. + */ + if (PROCINFO_node != NULL) + read_can_timeout = TRUE; +} + + #if defined(__DJGPP__) || defined(__MINGW32__) || defined(__EMX__) || defined(__CYGWIN__) /* binmode --- convert BINMODE to string for fopen */ @@ -376,6 +411,7 @@ nextfile(IOBUF **curfile, int skipping) fname = "-"; iop = *curfile = iop_alloc(fileno(stdin), fname, &mybuf, FALSE); iop->flag |= IOP_NOFREE_OBJ; + if (iop->fd == INVALID_HANDLE) { errcode = errno; errno = 0; @@ -445,7 +481,7 @@ remap_std_file(int oldfd) int ret = -1; /* - * Give OS-specific routines in gawkmisc.c chance to interpret + * Give OS-specific routines in gawkmisc.c a chance to interpret * "/dev/null" as appropriate for their platforms. */ newfd = os_devopen("/dev/null", O_RDWR); @@ -611,7 +647,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) if (do_lint && (redir_exp->flags & STRCUR) == 0) lintwarn(_("expression in `%s' redirection only has numeric value"), what); - redir_exp = force_string(redir_exp); + redir_exp= force_string(redir_exp); str = redir_exp->stptr; if (str == NULL || *str == '\0') @@ -2340,6 +2376,30 @@ init_awkpath(char *path) #undef INC_PATH } +/* get_cwd -- get current working directory */ + +static char * +get_cwd () +{ +#define BSIZE 100 + char *buf; + size_t bsize = BSIZE; + + emalloc(buf, char *, bsize * sizeof(char), "get_cwd"); + while (TRUE) { + if (getcwd(buf, bsize) == buf) + return buf; + if (errno != ERANGE) { + efree(buf); + return NULL; + } + bsize *= 2; + erealloc(buf, char *, bsize * sizeof(char), "get_cwd"); + } +#undef BSIZE +} + + /* do_find_source --- search $AWKPATH for file, return NULL if not found */ static char * @@ -2361,10 +2421,16 @@ do_find_source(const char *src, struct stat *stb, int *errcode) return NULL; } - /* try current directory before path search */ + /* try current directory before $AWKPATH search */ if (stat(src, stb) == 0) { - emalloc(path, char *, strlen(src) + 1, "do_find_source"); - strcpy(path, src); + path = get_cwd(); + if (path == NULL) { + *errcode = errno; + return NULL; + } + erealloc(path, char *, strlen(path) + strlen(src) + 2, "do_find_source"); + strcat(path, "/"); + strcat(path, src); return path; } @@ -2374,6 +2440,7 @@ do_find_source(const char *src, struct stat *stb, int *errcode) emalloc(path, char *, max_pathlen + strlen(src) + 1, "do_find_source"); for (i = 0; awkpath[i] != NULL; i++) { if (strcmp(awkpath[i], "./") == 0 || strcmp(awkpath[i], ".") == 0) { + /* FIXME: already tried CWD above; Why do it again ? */ *path = '\0'; } else strcpy(path, awkpath[i]); @@ -2391,7 +2458,7 @@ do_find_source(const char *src, struct stat *stb, int *errcode) /* find_source --- find source file with default file extension handling */ char * -find_source(const char *src, struct stat *stb, int *errcode) +find_source(const char *src, struct stat *stb, int *errcode, int is_extlib) { char *path; @@ -2400,10 +2467,36 @@ find_source(const char *src, struct stat *stb, int *errcode) return NULL; path = do_find_source(src, stb, errcode); + if (path == NULL && is_extlib) { + char *file_ext; + int save_errno; + size_t src_len; + size_t suffix_len; + +#define EXTLIB_SUFFIX ".so" + src_len = strlen(src); + suffix_len = strlen(EXTLIB_SUFFIX); + + /* check if already has the SUFFIX */ + if (src_len >= suffix_len && strcmp(& src[src_len - suffix_len], EXTLIB_SUFFIX) == 0) + return NULL; + + /* append EXTLIB_SUFFIX and try again */ + save_errno = errno; + emalloc(file_ext, char *, src_len + suffix_len + 1, "find_source"); + sprintf(file_ext, "%s%s", src, EXTLIB_SUFFIX); + path = do_find_source(file_ext, stb, errcode); + efree(file_ext); + if (path == NULL) + errno = save_errno; + return path; +#undef EXTLIB_SUFFIX + } + #ifdef DEFAULT_FILETYPE if (! do_traditional && path == NULL) { char *file_awk; - int save = errno; + int save_errno = errno; #ifdef VMS int vms_save = vaxc$errno; #endif @@ -2415,7 +2508,7 @@ find_source(const char *src, struct stat *stb, int *errcode) path = do_find_source(file_awk, stb, errcode); efree(file_awk); if (path == NULL) { - errno = save; + errno = save_errno; #ifdef VMS vaxc$errno = vms_save; #endif @@ -2426,6 +2519,7 @@ find_source(const char *src, struct stat *stb, int *errcode) return path; } + /* srcopen --- open source file */ int @@ -2496,22 +2590,21 @@ iop_alloc(int fd, const char *name, IOBUF *iop, int do_openhooks) iop_malloced = TRUE; } memset(iop, '\0', sizeof(IOBUF)); - iop->flag = 0; iop->fd = fd; iop->name = name; + iop->read_func = ( ssize_t(*)() ) read; - if (do_openhooks) + if (do_openhooks) { find_open_hook(iop); - else if (iop->fd == INVALID_HANDLE) + /* tried to find open hook and could not */ + if (iop->fd == INVALID_HANDLE) { + if (iop_malloced) + efree(iop); + return NULL; + } + } else if (iop->fd == INVALID_HANDLE) return iop; - /* test reached if tried to find open hook and could not */ - if (iop->fd == INVALID_HANDLE) { - if (iop_malloced) - efree(iop); - return NULL; - } - if (os_isatty(iop->fd)) iop->flag |= IOP_IS_TTY; iop->readsize = iop->size = optimal_bufsize(iop->fd, & sbuf); @@ -2530,7 +2623,7 @@ iop_alloc(int fd, const char *name, IOBUF *iop, int do_openhooks) #define set_RT_to_null() \ (void)(! do_traditional && (unref(RT_node->var_value), \ - RT_node->var_value = Nnull_string)) + RT_node->var_value = dupnode(Nnull_string))) #define set_RT(str, len) \ (void)(! do_traditional && (unref(RT_node->var_value), \ @@ -2925,12 +3018,15 @@ get_a_record(char **out, /* pointer to pointer to data */ if (at_eof(iop) && no_data_left(iop)) return EOF; + if (read_can_timeout) + read_timeout = get_read_timeout(iop); + if (iop->get_record != NULL) return (*iop->get_record)(out, iop, errcode); /* <fill initial buffer>= */ if (has_no_data(iop) || no_data_left(iop)) { - iop->count = read(iop->fd, iop->buf, iop->readsize); + iop->count = iop->read_func(iop->fd, iop->buf, iop->readsize); if (iop->count == 0) { iop->flag |= IOP_AT_EOF; return EOF; @@ -2996,7 +3092,7 @@ get_a_record(char **out, /* pointer to pointer to data */ amt_to_read = min(amt_to_read, SSIZE_MAX); #endif - iop->count = read(iop->fd, iop->dataend, amt_to_read); + iop->count = iop->read_func(iop->fd, iop->dataend, amt_to_read); if (iop->count == -1) { *errcode = errno; iop->flag |= IOP_AT_EOF; @@ -3134,6 +3230,7 @@ set_FS: set_FS(); } + /* pty_vs_pipe --- return true if should use pty instead of pipes for `|&' */ /* @@ -3144,27 +3241,11 @@ static int pty_vs_pipe(const char *command) { #ifdef HAVE_TERMIOS_H - char *full_index; - size_t full_len; NODE *val; - NODE *sub; if (PROCINFO_node == NULL) return FALSE; - - full_len = strlen(command) - + SUBSEP_node->var_value->stlen - + 3 /* strlen("pty") */ - + 1; /* string terminator */ - emalloc(full_index, char *, full_len, "pty_vs_pipe"); - sprintf(full_index, "%s%.*spty", command, - (int) SUBSEP_node->var_value->stlen, SUBSEP_node->var_value->stptr); - - sub = make_string(full_index, strlen(full_index)); - val = in_array(PROCINFO_node, sub); - unref(sub); - efree(full_index); - + val = in_PROCINFO(command, "pty", NULL); if (val) { if (val->flags & MAYBE_NUM) (void) force_number(val); @@ -3235,3 +3316,115 @@ inetfile(const char *str, int *length, int *family) return ret; } + +/* + * in_PROCINFO --- return value for a PROCINFO element with + * SUBSEP seperated indices. + */ + +static NODE * +in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx) +{ + char *str; + size_t str_len; + NODE *r, *sub = NULL; + NODE *subsep = SUBSEP_node->var_value; + + /* full_idx is in+out parameter */ + + if (full_idx) + sub = *full_idx; + + str_len = strlen(pidx1) + subsep->stlen + strlen(pidx2); + if (sub == NULL) { + emalloc(str, char *, str_len + 1, "in_PROCINFO"); + sub = make_str_node(str, str_len, ALREADY_MALLOCED); + if (full_idx) + *full_idx = sub; + } else if (str_len != sub->stlen) { + /* *full_idx != NULL */ + + assert(sub->valref == 1); + erealloc(sub->stptr, char *, str_len + 1, "in_PROCINFO"); + sub->stlen = str_len; + } + + sprintf(sub->stptr, "%s%.*s%s", pidx1, (int)subsep->stlen, + subsep->stptr, pidx2); + r = in_array(PROCINFO_node, sub); + if (! full_idx) + unref(sub); + return r; +} + + +/* get_read_timeout --- get timeout in milliseconds for reading */ + +static long +get_read_timeout(IOBUF *iop) +{ + long tmout = 0; + + if (PROCINFO_node != NULL) { + const char *name = iop->name; + NODE *val = NULL; + static NODE *full_idx = NULL; + static const char *last_name = NULL; + + /* + * Do not re-construct the full index when last redirection + * string is the same as the current; "efficiency_hack++". + */ + if (full_idx == NULL || strcmp(name, last_name) != 0) { + val = in_PROCINFO(name, "READ_TIMEOUT", & full_idx); + if (last_name != NULL) + efree(last_name); + last_name = estrdup(name, strlen(name)); + } else /* use cached full index */ + val = in_array(PROCINFO_node, full_idx); + + if (val != NULL) + tmout = (long) force_number(val); + } else + tmout = read_default_timeout; /* initialized from env. variable in init_io() */ + + iop->read_func = tmout > 0 ? read_with_timeout : ( ssize_t(*)() ) read; + return tmout; +} + +/* + * read_with_timeout --- read with a timeout, return failure + * if no data is available within the timeout period. + */ + +static ssize_t +read_with_timeout(int fd, char *buf, size_t size) +{ + fd_set readfds; + struct timeval tv; + + tv.tv_sec = read_timeout / 1000; + tv.tv_usec = 1000 * (read_timeout - 1000 * tv.tv_sec); + + FD_ZERO(& readfds); + FD_SET(fd, & readfds); + + errno = 0; + if (select(fd + 1, & readfds, NULL, NULL, & tv) < 0) + return -1; + + if (FD_ISSET(fd, & readfds)) + return read(fd, buf, size); + /* else + timed out */ + + /* Set a meaningful errno */ +#ifdef ETIMEDOUT + errno = ETIMEDOUT; +#else + errno = EAGAIN; +#endif + return -1; +} + + |