From 9953f4cee02f2781ee5da2e42bcb837c1a849cb0 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Thu, 12 Dec 2013 20:45:59 +0200 Subject: First round of VMS changes. --- io.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index 4f244532..ac1855ba 100644 --- a/io.c +++ b/io.c @@ -121,6 +121,11 @@ #endif #if defined(VMS) +#include +#ifndef SS$_EXBYTLM +#define SS$_EXBYTLM 0x2a14 /* VMS 8.4 seen */ +#endif +#include #define closemaybesocket(fd) close(fd) #endif @@ -462,6 +467,11 @@ nextfile(IOBUF **curfile, bool skipping) /* IOBUF management: */ errno = 0; fd = devopen(fname, binmode("r")); + if (fd == INVALID_HANDLE && errno == EMFILE) { + close_one(); + close_one(); + fd = devopen(fname, binmode("r")); + } errcode = errno; if (! do_traditional) update_ERRNO_int(errno); @@ -948,13 +958,13 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) if (errno == EMFILE || errno == ENFILE) close_one(); #ifdef VMS - /* Alpha/VMS V7.1's C RTL is returning this instead + /* Alpha/VMS V7.1+ C RTL is returning these instead of EMFILE (haven't tried other post-V6.2 systems) */ -#define SS$_EXQUOTA 0x001C -#define SS$_EXBYTLM 0x2a14 /* VMS 8.4 seen */ - else if (errno == EIO && + else if ((errno == EIO || errno == EVMSERR) && (vaxc$errno == SS$_EXQUOTA || - vaxc$errno == SS$_EXBYTLM)) + vaxc$errno == SS$_EXBYTLM || + vaxc$errno == RMS$_ACC || + vaxc$errno == RMS$_SYN)) close_one(); #endif else { -- cgit v1.2.3 From 664868f72b741ba448398d609e18a4cbb1ca20be Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Fri, 10 Jan 2014 12:28:09 +0200 Subject: Update some copyright years. --- io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'io.c') diff --git a/io.c b/io.c index ac1855ba..3e527da0 100644 --- a/io.c +++ b/io.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 1986, 1988, 1989, 1991-2013 the Free Software Foundation, Inc. + * Copyright (C) 1986, 1988, 1989, 1991-2014 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. -- cgit v1.2.3 From a76a789747458e3690e44ee81332099a3f80c156 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Wed, 5 Mar 2014 06:00:03 +0200 Subject: Continue to straighten out enum usage. --- io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'io.c') diff --git a/io.c b/io.c index 3e527da0..b0b60deb 100644 --- a/io.c +++ b/io.c @@ -3968,7 +3968,7 @@ init_output_wrapper(awk_output_buf_t *outbuf) outbuf->mode = NULL; outbuf->fp = NULL; outbuf->opaque = NULL; - outbuf->redirected = false; + outbuf->redirected = awk_false; outbuf->gawk_fwrite = gawk_fwrite; outbuf->gawk_fflush = gawk_fflush; outbuf->gawk_ferror = gawk_ferror; -- cgit v1.2.3 From 4525c29d221587c522c11ac6ec50122832729cd5 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Fri, 11 Apr 2014 07:35:29 +0300 Subject: Define closemaybesocket if it isn't otherwise. --- io.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'io.c') diff --git a/io.c b/io.c index b0b60deb..2a5c2e73 100644 --- a/io.c +++ b/io.c @@ -166,6 +166,12 @@ # define SOCKET int #endif +#else /* HAVE_SOCKETS */ + +#ifndef closemaybesocket +# define closemaybesocket(fd) close(fd) +#endif + #endif /* HAVE_SOCKETS */ #ifndef HAVE_SETSID -- cgit v1.2.3 From 6e5964a4f6dd7d2476af106387f40c7ae9ead0c5 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Sun, 20 Apr 2014 10:36:08 -0400 Subject: Improve socket name parsing to avoid false matches on names starting with /inet. --- io.c | 216 +++++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 113 insertions(+), 103 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index 2a5c2e73..a6e786f7 100644 --- a/io.c +++ b/io.c @@ -279,7 +279,23 @@ static RECVALUE (*matchrec)(IOBUF *iop, struct recmatch *recm, SCANSTATE *state) 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); + +struct inet_socket_info { + int family; /* AF_UNSPEC, AF_INET, or AF_INET6 */ + int protocol; /* SOCK_STREAM or SOCK_DGRAM */ + /* + * N.B. If we used 'char *' or 'const char *' pointers to the + * substrings, it would trigger compiler warnings about the casts + * in either inetfile() or devopen(). So we use offset/len to + * avoid that. + */ + struct { + int offset; + int len; + } localport, remotehost, remoteport; +}; + +static int inetfile(const char *str, struct inet_socket_info *isn); static NODE *in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx); static long get_read_timeout(IOBUF *iop); @@ -713,7 +729,9 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) int fd; const char *what = NULL; bool new_rp = false; - int len; /* used with /inet */ +#ifdef HAVE_SOCKETS + struct inet_socket_info isi; +#endif static struct redirect *save_rp = NULL; /* hold onto rp that should * be freed for reuse */ @@ -772,9 +790,9 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) * Use /inet4 to force IPv4, /inet6 to force IPv6, and plain * /inet will be whatever we get back from the system. */ - if (inetfile(str, & len, NULL)) { + if (inetfile(str, & isi)) { tflag |= RED_SOCKET; - if (strncmp(str + len, "tcp/", 4) == 0) + if (isi.protocol == SOCK_STREAM) tflag |= RED_TCP; /* use shutdown when closing */ } #endif /* HAVE_SOCKETS */ @@ -901,7 +919,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) direction = "to/from"; if (! two_way_open(str, rp)) { #ifdef HAVE_SOCKETS - if (inetfile(str, NULL, NULL)) { + if (inetfile(str, NULL)) { *errflg = errno; /* do not free rp, saving it for reuse (save_rp = rp) */ return NULL; @@ -1538,8 +1556,7 @@ devopen(const char *name, const char *mode) char *cp; char *ptr; int flag = 0; - int len; - int family; + struct inet_socket_info isi; if (strcmp(name, "-") == 0) return fileno(stdin); @@ -1576,74 +1593,14 @@ devopen(const char *name, const char *mode) /* do not set close-on-exec for inherited fd's */ if (openfd != INVALID_HANDLE) return openfd; - } else if (inetfile(name, & len, & family)) { + } else if (inetfile(name, & isi)) { #ifdef HAVE_SOCKETS - /* /inet/protocol/localport/hostname/remoteport */ - int protocol; - char *hostname; - char *hostnameslastcharp; - char *localpname; - char *localpnamelastcharp; - - cp = (char *) name + len; - /* which protocol? */ - if (strncmp(cp, "tcp/", 4) == 0) - protocol = SOCK_STREAM; - else if (strncmp(cp, "udp/", 4) == 0) - protocol = SOCK_DGRAM; - else { - protocol = SOCK_STREAM; /* shut up the compiler */ - fatal(_("no (known) protocol supplied in special filename `%s'"), - name); - } - cp += 4; - - /* which localport? */ - localpname = cp; - while (*cp != '/' && *cp != '\0') - cp++; - /* - * Require a port, let them explicitly put 0 if - * they don't care. - */ - if (*cp != '/' || cp == localpname) - fatal(_("special file name `%s' is incomplete"), name); + cp = (char *) name; - /* - * We change the special file name temporarily because we - * need a 0-terminated string here for conversion with atoi(). - * By using atoi() the use of decimal numbers is enforced. - */ - *cp = '\0'; - localpnamelastcharp = cp; - - /* which hostname? */ - cp++; - hostname = cp; - while (*cp != '/' && *cp != '\0') - cp++; - if (*cp != '/' || cp == hostname) { - *localpnamelastcharp = '/'; - fatal(_("must supply a remote hostname to `/inet'")); - } - *cp = '\0'; - hostnameslastcharp = cp; - - /* which remoteport? */ - cp++; - /* - * The remote port ends the special file name. - * This means there already is a '\0' at the end of the string. - * Therefore no need to patch any string ending. - * - * Here too, require a port, let them explicitly put 0 if - * they don't care. - */ - if (*cp == '\0') { - *localpnamelastcharp = '/'; - *hostnameslastcharp = '/'; - fatal(_("must supply a remote port to `/inet'")); - } + /* socketopen requires NUL-terminated strings */ + cp[isi.localport.offset+isi.localport.len] = '\0'; + cp[isi.remotehost.offset+isi.remotehost.len] = '\0'; + /* remoteport comes last, so already NUL-terminated */ { #define DEFAULT_RETRIES 20 @@ -1680,13 +1637,14 @@ devopen(const char *name, const char *mode) retries = def_retries; do { - openfd = socketopen(family, protocol, localpname, cp, hostname); + openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset, name+isi.remoteport.offset, name+isi.remotehost.offset); retries--; } while (openfd == INVALID_HANDLE && retries > 0 && usleep(msleep) == 0); } - *localpnamelastcharp = '/'; - *hostnameslastcharp = '/'; + /* restore original name string */ + cp[isi.localport.offset+isi.localport.len] = '/'; + cp[isi.remotehost.offset+isi.remotehost.len] = '/'; #else /* ! HAVE_SOCKETS */ fatal(_("TCP/IP communications are not supported")); #endif /* HAVE_SOCKETS */ @@ -1700,9 +1658,8 @@ strictopen: /* On OS/2 and Windows directory access via open() is not permitted. */ struct stat buf; - int l, f; - if (!inetfile(name, &l, &f) + if (!inetfile(name, NULL) && stat(name, & buf) == 0 && S_ISDIR(buf.st_mode)) errno = EISDIR; } @@ -1724,7 +1681,7 @@ two_way_open(const char *str, struct redirect *rp) #ifdef HAVE_SOCKETS /* case 1: socket */ - if (inetfile(str, NULL, NULL)) { + if (inetfile(str, NULL)) { int fd, newfd; fd = devopen(str, "rw"); @@ -3751,34 +3708,87 @@ free_rp(struct redirect *rp) /* inetfile --- return true for a /inet special file, set other values */ static int -inetfile(const char *str, int *length, int *family) +inetfile(const char *str, struct inet_socket_info *isi) { - bool ret = false; - - if (strncmp(str, "/inet/", 6) == 0) { - ret = true; - if (length != NULL) - *length = 6; - if (family != NULL) - *family = AF_UNSPEC; - } else if (strncmp(str, "/inet4/", 7) == 0) { - ret = true; - if (length != NULL) - *length = 7; - if (family != NULL) - *family = AF_INET; - } else if (strncmp(str, "/inet6/", 7) == 0) { - ret = true; - if (length != NULL) - *length = 7; - if (family != NULL) - *family = AF_INET6; + const char *cp = str; + struct inet_socket_info buf; + + /* syntax: /inet/protocol/localport/hostname/remoteport */ + if (strncmp(cp, "/inet", 5) != 0) + /* quick exit */ + return false; + if (! isi) + isi = & buf; + cp += 5; + switch (*cp) { + case '/': + isi->family = AF_UNSPEC; + break; + case '4': + if (*++cp != '/') + return false; + isi->family = AF_INET; + break; + case '6': + if (*++cp != '/') + return false; + isi->family = AF_INET6; + break; + default: + return false; + } + cp++; /* skip past '/' */ + + /* which protocol? */ + if (strncmp(cp, "tcp/", 4) == 0) + isi->protocol = SOCK_STREAM; + else if (strncmp(cp, "udp/", 4) == 0) + isi->protocol = SOCK_DGRAM; + else + return false; + cp += 4; + + /* which localport? */ + isi->localport.offset = cp-str; + while (*cp != '/' && *cp != '\0') + cp++; + /* + * Require a port, let them explicitly put 0 if + * they don't care. + */ + if (*cp != '/' || ((isi->localport.len = (cp-str)-isi->localport.offset) == 0)) + return false; + + /* which hostname? */ + cp++; + isi->remotehost.offset = cp-str; + while (*cp != '/' && *cp != '\0') + cp++; + if (*cp != '/' || ((isi->remotehost.len = (cp-str)-isi->remotehost.offset) == 0)) + return false; + + /* which remoteport? */ + cp++; + /* + * The remote port ends the special file name. + * This means there already is a '\0' at the end of the string. + * Therefore no need to patch any string ending. + * + * Here too, require a port, let them explicitly put 0 if + * they don't care. + */ + isi->remoteport.offset = cp-str; + while (*cp != '/' && *cp != '\0') + cp++; + if (*cp != '\0' || ((isi->remoteport.len = (cp-str)-isi->remoteport.offset) == 0)) + return false; + #ifndef HAVE_GETADDRINFO + /* final check for IPv6: */ + if (isi->family == AF_INET6) fatal(_("IPv6 communication is not supported")); #endif - } - - return ret; + return true; } /* -- cgit v1.2.3 From 19564e696aca506a14ceb4a08aa2b7c7988a2473 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Fri, 25 Apr 2014 13:21:43 +0300 Subject: In forked children, set SIGPIPE to SIG_DFL. --- io.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'io.c') diff --git a/io.c b/io.c index a6e786f7..2bb8f28a 100644 --- a/io.c +++ b/io.c @@ -2078,6 +2078,7 @@ use_pipes: || close(ctop[0]) == -1 || close(ctop[1]) == -1) fatal(_("close of pipe failed (%s)"), strerror(errno)); /* stderr does NOT get dup'ed onto child's stdout */ + signal(SIGPIPE, SIG_DFL); execl("/bin/sh", "sh", "-c", str, NULL); _exit(errno == ENOENT ? 127 : 126); } @@ -2271,6 +2272,7 @@ gawk_popen(const char *cmd, struct redirect *rp) fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno)); if (close(p[0]) == -1 || close(p[1]) == -1) fatal(_("close of pipe failed (%s)"), strerror(errno)); + signal(SIGPIPE, SIG_DFL); execl("/bin/sh", "sh", "-c", cmd, NULL); _exit(errno == ENOENT ? 127 : 126); } -- cgit v1.2.3 From 40694fc1c11bae6fac8e809a6a4c161c12cc37b7 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Fri, 9 May 2014 11:59:29 +0300 Subject: Fix in read_a_record for short file with RS=regex. --- io.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'io.c') diff --git a/io.c b/io.c index 2bb8f28a..b1c9fa18 100644 --- a/io.c +++ b/io.c @@ -206,6 +206,7 @@ typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type; #define at_eof(iop) (((iop)->flag & IOP_AT_EOF) != 0) #define has_no_data(iop) ((iop)->dataend == NULL) #define no_data_left(iop) ((iop)->off >= (iop)->dataend) +#define buffer_has_all_data(iop) ((iop)->dataend - (iop)->off == (iop)->public.sbuf.st_size) /* * The key point to the design is to split out the code that searches through @@ -3474,6 +3475,8 @@ get_a_record(char **out, /* pointer to pointer to data */ iop->flag &= ~IOP_AT_START; if (ret == REC_OK) break; + if (ret == TERMNEAREND && buffer_has_all_data(iop)) + break; /* need to add more data to buffer */ /* shift data down in buffer */ -- cgit v1.2.3 From 0ebae58196378b06e083109701875f15c60a7b9a Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Sat, 10 May 2014 22:53:29 +0300 Subject: Additional fix for TERMNEAREND. --- io.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index b1c9fa18..3d7b00ab 100644 --- a/io.c +++ b/io.c @@ -3473,8 +3473,15 @@ get_a_record(char **out, /* pointer to pointer to data */ ret = (*matchrec)(iop, & recm, & state); iop->flag &= ~IOP_AT_START; + /* found the record, we're done, break the loop */ if (ret == REC_OK) break; + + /* + * Likely found the record; if there's no more data + * to be had (like from a tiny regular file), break the + * loop. Otherwise, see if we can read more. + */ if (ret == TERMNEAREND && buffer_has_all_data(iop)) break; @@ -3527,10 +3534,14 @@ get_a_record(char **out, /* pointer to pointer to data */ break; } else if (iop->count == 0) { /* - * hit EOF before matching RS, so end - * the record and set RT to "" + * Hit EOF before being certain that we've matched + * the end of the record. If ret is TERMNEAREND, + * we need to pull out what we've got in the buffer. + * Eventually we'll come back here and see the EOF, + * end the record and set RT to "". */ - iop->flag |= IOP_AT_EOF; + if (ret != TERMNEAREND) + iop->flag |= IOP_AT_EOF; break; } else iop->dataend += iop->count; -- cgit v1.2.3 From c87f4150028ba1a144f8fa1f5e390b7cc129d7b9 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Mon, 26 May 2014 08:11:07 +0300 Subject: Compile fix in io.c for DJGPP. --- io.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index 3d7b00ab..57d4af22 100644 --- a/io.c +++ b/io.c @@ -296,7 +296,7 @@ struct inet_socket_info { } localport, remotehost, remoteport; }; -static int inetfile(const char *str, struct inet_socket_info *isn); +static bool inetfile(const char *str, struct inet_socket_info *isn); static NODE *in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx); static long get_read_timeout(IOBUF *iop); @@ -3723,9 +3723,12 @@ free_rp(struct redirect *rp) /* inetfile --- return true for a /inet special file, set other values */ -static int +static bool inetfile(const char *str, struct inet_socket_info *isi) { +#ifndef HAVE_SOCKETS + return false; +#else const char *cp = str; struct inet_socket_info buf; @@ -3805,6 +3808,7 @@ inetfile(const char *str, struct inet_socket_info *isi) fatal(_("IPv6 communication is not supported")); #endif return true; +#endif /* HAVE_SOCKETS */ } /* -- cgit v1.2.3