From dcaab6dd8a28be8885ccc508c49b962a61ab09fe Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Sat, 20 Dec 2014 19:56:44 +0200 Subject: Start at non-fatal output via PROCINFO. --- io.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index 1d15d887..b4688c89 100644 --- a/io.c +++ b/io.c @@ -718,6 +718,7 @@ redflags2str(int flags) { RED_PTY, "RED_PTY" }, { RED_SOCKET, "RED_SOCKET" }, { RED_TCP, "RED_TCP" }, + { RED_NON_FATAL, "RED_NON_FATAL" }, { 0, NULL } }; @@ -744,6 +745,8 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) static struct redirect *save_rp = NULL; /* hold onto rp that should * be freed for reuse */ + bool is_output = false; + bool is_non_fatal = false; if (do_sandbox) fatal(_("redirection not allowed in sandbox mode")); @@ -753,6 +756,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) tflag = RED_APPEND; /* FALL THROUGH */ case redirect_output: + is_output = true; outflag = (RED_FILE|RED_WRITE); tflag |= outflag; if (redirtype == redirect_output) @@ -761,6 +765,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) what = ">>"; break; case redirect_pipe: + is_output = true; tflag = (RED_PIPE|RED_WRITE); what = "|"; break; @@ -773,6 +778,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) what = "<"; break; case redirect_twoway: + is_output = true; tflag = (RED_READ|RED_WRITE|RED_TWOWAY); what = "|&"; break; @@ -794,6 +800,14 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) lintwarn(_("filename `%s' for `%s' redirection may be result of logical expression"), str, what); + /* input files/pipes are automatically nonfatal */ + if (is_output) { + is_non_fatal = (in_PROCINFO("nonfatal", NULL, NULL) != NULL + || in_PROCINFO(str, "nonfatal", NULL) != NULL); + if (is_non_fatal) + tflag |= RED_NON_FATAL; + } + #ifdef HAVE_SOCKETS /* * Use /inet4 to force IPv4, /inet6 to force IPv6, and plain @@ -892,6 +906,12 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) (void) flush_io(); os_restore_mode(fileno(stdin)); + /* + * Don't check is_non_fatal; see input pipe below. + * Note that the failure happens upon failure to fork, + * using a non-existant program will still succeed the + * popen(). + */ if ((rp->output.fp = popen(str, binmode("w"))) == NULL) fatal(_("can't open pipe `%s' for output (%s)"), str, strerror(errno)); @@ -932,6 +952,10 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) *errflg = errno; /* do not free rp, saving it for reuse (save_rp = rp) */ return NULL; + } else if (is_non_fatal) { + *errflg = errno; + /* do not free rp, saving it for reuse (save_rp = rp) */ + return NULL; } else #endif fatal(_("can't open two way pipe `%s' for input/output (%s)"), @@ -1009,11 +1033,14 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) * can return -1. For output to file, * complain. The shell will complain on * a bad command to a pipe. + * + * 12/2014: Take nonfatal settings in PROCINFO into account. */ if (errflg != NULL) *errflg = errno; - if ( redirtype == redirect_output - || redirtype == redirect_append) { + if (! is_non_fatal && + (redirtype == redirect_output + || redirtype == redirect_append)) { /* multiple messages make life easier for translators */ if (*direction == 'f') fatal(_("can't redirect from `%s' (%s)"), @@ -3799,12 +3826,21 @@ in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx) NODE *r, *sub = NULL; NODE *subsep = SUBSEP_node->var_value; + if (PROCINFO_node == NULL || (pidx1 == NULL && pidx2 == NULL)) + return NULL; + /* full_idx is in+out parameter */ if (full_idx) sub = *full_idx; - str_len = strlen(pidx1) + subsep->stlen + strlen(pidx2); + if (pidx1 != NULL && pidx2 == NULL) + str_len = strlen(pidx1); + else if (pidx1 == NULL && pidx2 != NULL) + str_len = strlen(pidx2); + else + 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); @@ -3818,8 +3854,14 @@ in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx) sub->stlen = str_len; } - sprintf(sub->stptr, "%s%.*s%s", pidx1, (int)subsep->stlen, - subsep->stptr, pidx2); + if (pidx1 != NULL && pidx2 == NULL) + strcpy(sub->stptr, pidx1); + else if (pidx1 == NULL && pidx2 != NULL) + strcpy(sub->stptr, pidx2); + else + sprintf(sub->stptr, "%s%.*s%s", pidx1, (int)subsep->stlen, + subsep->stptr, pidx2); + r = in_array(PROCINFO_node, sub); if (! full_idx) unref(sub); -- cgit v1.2.3 From 15a1d8d213380bd99b5dfe7f4cafcd6dedb8f0dc Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Sat, 27 Dec 2014 21:20:47 +0200 Subject: Make nonfatal work with stdout & stderr. Update doc more. --- io.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'io.c') diff --git a/io.c b/io.c index b4688c89..b3819c01 100644 --- a/io.c +++ b/io.c @@ -1085,6 +1085,25 @@ getredirect(const char *str, int len) return NULL; } +/* is_non_fatal_std --- return true if fp is stdout/stderr and nonfatal */ + +bool +is_non_fatal_std(FILE *fp) +{ + if (in_PROCINFO("nonfatal", NULL, NULL)) + return true; + + /* yucky logic. sigh. */ + if (fp == stdout) { + return ( in_PROCINFO("-", "nonfatal", NULL) != NULL + || in_PROCINFO("/dev/stdout", "nonfatal", NULL) != NULL); + } else if (fp == stderr) { + return (in_PROCINFO("/dev/stderr", "nonfatal", NULL) != NULL); + } + + return false; +} + /* close_one --- temporarily close an open file to re-use the fd */ static void -- cgit v1.2.3 From 2f9c84e82632cbce017a6d342acb3dede5e59e12 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Sun, 8 Feb 2015 19:45:44 +0200 Subject: Reset non-fatal-io to 31 December, add fixes from Andrew Schorr. --- io.c | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index b3819c01..db8a0a2b 100644 --- a/io.c +++ b/io.c @@ -261,7 +261,6 @@ struct recmatch { static int iop_close(IOBUF *iop); -struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg); static void close_one(void); static int close_redir(struct redirect *rp, bool exitwarn, two_way_close_type how); #ifndef PIPES_SIMULATED @@ -718,7 +717,6 @@ redflags2str(int flags) { RED_PTY, "RED_PTY" }, { RED_SOCKET, "RED_SOCKET" }, { RED_TCP, "RED_TCP" }, - { RED_NON_FATAL, "RED_NON_FATAL" }, { 0, NULL } }; @@ -728,7 +726,7 @@ redflags2str(int flags) /* redirect --- Redirection for printf and print commands */ struct redirect * -redirect(NODE *redir_exp, int redirtype, int *errflg) +redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal) { struct redirect *rp; char *str; @@ -745,8 +743,6 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) static struct redirect *save_rp = NULL; /* hold onto rp that should * be freed for reuse */ - bool is_output = false; - bool is_non_fatal = false; if (do_sandbox) fatal(_("redirection not allowed in sandbox mode")); @@ -756,7 +752,6 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) tflag = RED_APPEND; /* FALL THROUGH */ case redirect_output: - is_output = true; outflag = (RED_FILE|RED_WRITE); tflag |= outflag; if (redirtype == redirect_output) @@ -765,7 +760,6 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) what = ">>"; break; case redirect_pipe: - is_output = true; tflag = (RED_PIPE|RED_WRITE); what = "|"; break; @@ -778,7 +772,6 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) what = "<"; break; case redirect_twoway: - is_output = true; tflag = (RED_READ|RED_WRITE|RED_TWOWAY); what = "|&"; break; @@ -800,14 +793,6 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) lintwarn(_("filename `%s' for `%s' redirection may be result of logical expression"), str, what); - /* input files/pipes are automatically nonfatal */ - if (is_output) { - is_non_fatal = (in_PROCINFO("nonfatal", NULL, NULL) != NULL - || in_PROCINFO(str, "nonfatal", NULL) != NULL); - if (is_non_fatal) - tflag |= RED_NON_FATAL; - } - #ifdef HAVE_SOCKETS /* * Use /inet4 to force IPv4, /inet6 to force IPv6, and plain @@ -907,7 +892,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) os_restore_mode(fileno(stdin)); /* - * Don't check is_non_fatal; see input pipe below. + * Don't check failure_fatal; see input pipe below. * Note that the failure happens upon failure to fork, * using a non-existant program will still succeed the * popen(). @@ -947,17 +932,11 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) case redirect_twoway: direction = "to/from"; if (! two_way_open(str, rp)) { -#ifdef HAVE_SOCKETS - if (inetfile(str, NULL)) { - *errflg = errno; - /* do not free rp, saving it for reuse (save_rp = rp) */ - return NULL; - } else if (is_non_fatal) { + if (! failure_fatal || is_non_fatal_redirect(str)) { *errflg = errno; /* do not free rp, saving it for reuse (save_rp = rp) */ return NULL; } else -#endif fatal(_("can't open two way pipe `%s' for input/output (%s)"), str, strerror(errno)); } @@ -1038,7 +1017,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) */ if (errflg != NULL) *errflg = errno; - if (! is_non_fatal && + if (failure_fatal && ! is_non_fatal_redirect(str) && (redirtype == redirect_output || redirtype == redirect_append)) { /* multiple messages make life easier for translators */ @@ -1104,6 +1083,15 @@ is_non_fatal_std(FILE *fp) return false; } +/* is_non_fatal_redirect --- return true if redirected I/O should be nonfatal */ + +bool +is_non_fatal_redirect(const char *str) +{ + return in_PROCINFO("nonfatal", NULL, NULL) != NULL + || in_PROCINFO(str, "nonfatal", NULL) != NULL; +} + /* close_one --- temporarily close an open file to re-use the fd */ static void @@ -2467,7 +2455,7 @@ do_getline_redir(int into_variable, enum redirval redirtype) assert(redirtype != redirect_none); redir_exp = TOP(); - rp = redirect(redir_exp, redirtype, & redir_error); + rp = redirect(redir_exp, redirtype, & redir_error, false); DEREF(redir_exp); decr_sp(); if (rp == NULL) { -- cgit v1.2.3 From 7f9f66525d7d82816eba352efdf58497373a47bf Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Sun, 8 Feb 2015 20:01:32 +0200 Subject: Use "NONFATAL" for nonfatal I/O. --- io.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index db8a0a2b..f975353e 100644 --- a/io.c +++ b/io.c @@ -1069,15 +1069,17 @@ getredirect(const char *str, int len) bool is_non_fatal_std(FILE *fp) { - if (in_PROCINFO("nonfatal", NULL, NULL)) + static const char nonfatal[] = "NONFATAL"; + + if (in_PROCINFO(nonfatal, NULL, NULL)) return true; /* yucky logic. sigh. */ if (fp == stdout) { - return ( in_PROCINFO("-", "nonfatal", NULL) != NULL - || in_PROCINFO("/dev/stdout", "nonfatal", NULL) != NULL); + return ( in_PROCINFO("-", nonfatal, NULL) != NULL + || in_PROCINFO("/dev/stdout", nonfatal, NULL) != NULL); } else if (fp == stderr) { - return (in_PROCINFO("/dev/stderr", "nonfatal", NULL) != NULL); + return (in_PROCINFO("/dev/stderr", nonfatal, NULL) != NULL); } return false; @@ -1088,8 +1090,8 @@ is_non_fatal_std(FILE *fp) bool is_non_fatal_redirect(const char *str) { - return in_PROCINFO("nonfatal", NULL, NULL) != NULL - || in_PROCINFO(str, "nonfatal", NULL) != NULL; + return in_PROCINFO("NONFATAL", NULL, NULL) != NULL + || in_PROCINFO(str, "NONFATAL", NULL) != NULL; } /* close_one --- temporarily close an open file to re-use the fd */ -- cgit v1.2.3 From 1752d5ee472ce827ee66ea38c33085123575a033 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Fri, 27 Feb 2015 08:59:09 +0200 Subject: Make socket open not immediately fatal. --- io.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index f975353e..b00aa300 100644 --- a/io.c +++ b/io.c @@ -1466,7 +1466,7 @@ str2mode(const char *mode) static int socketopen(int family, int type, const char *localpname, - const char *remotepname, const char *remotehostname) + const char *remotepname, const char *remotehostname, bool *hard_error) { struct addrinfo *lres, *lres0; struct addrinfo lhints; @@ -1485,8 +1485,11 @@ socketopen(int family, int type, const char *localpname, lerror = getaddrinfo(NULL, localpname, & lhints, & lres); if (lerror) { - if (strcmp(localpname, "0") != 0) - fatal(_("local port %s invalid in `/inet'"), localpname); + if (strcmp(localpname, "0") != 0) { + warning(_("local port %s invalid in `/inet'"), localpname); + *hard_error = true; + return INVALID_HANDLE; + } lres0 = NULL; lres = & lhints; } else @@ -1504,7 +1507,9 @@ socketopen(int family, int type, const char *localpname, if (rerror) { if (lres0 != NULL) freeaddrinfo(lres0); - fatal(_("remote host and port information (%s, %s) invalid"), remotehostname, remotepname); + warning(_("remote host and port information (%s, %s) invalid"), remotehostname, remotepname); + *hard_error = true; + return INVALID_HANDLE; } rres0 = rres; socket_fd = INVALID_HANDLE; @@ -1668,6 +1673,7 @@ devopen(const char *name, const char *mode) static bool first_time = true; unsigned long retries = 0; static long msleep = 1000; + bool hard_error = false; if (first_time) { char *cp, *end; @@ -1697,9 +1703,9 @@ devopen(const char *name, const char *mode) retries = def_retries; do { - openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset, name+isi.remoteport.offset, name+isi.remotehost.offset); + openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset, name+isi.remoteport.offset, name+isi.remotehost.offset, & hard_error); retries--; - } while (openfd == INVALID_HANDLE && retries > 0 && usleep(msleep) == 0); + } while (openfd == INVALID_HANDLE && ! hard_error && retries > 0 && usleep(msleep) == 0); } /* restore original name string */ -- cgit v1.2.3 From 765d3a443f5121f148d47ec813069e1257212d5e Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Fri, 27 Feb 2015 09:06:01 +0200 Subject: For non-fatal sockets, get a better error message. --- io.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'io.c') diff --git a/io.c b/io.c index b00aa300..af963a80 100644 --- a/io.c +++ b/io.c @@ -1618,6 +1618,7 @@ devopen(const char *name, const char *mode) char *ptr; int flag = 0; struct inet_socket_info isi; + int save_errno = 0; if (strcmp(name, "-") == 0) return fileno(stdin); @@ -1702,10 +1703,12 @@ devopen(const char *name, const char *mode) } retries = def_retries; + errno = 0; do { openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset, name+isi.remoteport.offset, name+isi.remotehost.offset, & hard_error); retries--; } while (openfd == INVALID_HANDLE && ! hard_error && retries > 0 && usleep(msleep) == 0); + save_errno = errno; } /* restore original name string */ @@ -1717,8 +1720,11 @@ devopen(const char *name, const char *mode) } strictopen: - if (openfd == INVALID_HANDLE) + if (openfd == INVALID_HANDLE) { openfd = open(name, flag, 0666); + if (openfd == INVALID_HANDLE && save_errno) + errno = save_errno; + } #if defined(__EMX__) || defined(__MINGW32__) if (openfd == INVALID_HANDLE && errno == EACCES) { /* On OS/2 and Windows directory access via open() is -- cgit v1.2.3 From 9fa41fc2c183d5920d64e6f34f8a6bb325188443 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Sat, 28 Feb 2015 15:26:40 -0500 Subject: Improve testing for nonfatal socket connection attempts. --- io.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index af963a80..162fb4e8 100644 --- a/io.c +++ b/io.c @@ -3704,8 +3704,10 @@ pty_vs_pipe(const char *command) #ifdef HAVE_TERMIOS_H NODE *val; - if (PROCINFO_node == NULL) - return false; + /* + * N.B. No need to check for NULL PROCINFO_node, since the + * in_PROCINFO function now checks that for us. + */ val = in_PROCINFO(command, "pty", NULL); if (val) { if ((val->flags & MAYBE_NUM) != 0) -- cgit v1.2.3 From b108a3ba2ab12dd7274589c6fe09c882df02827c Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Sun, 8 Mar 2015 06:06:19 +0200 Subject: Make nonfatal override GAWK_SOCK_RETRIES. Document it. --- io.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index 162fb4e8..55c5d3a5 100644 --- a/io.c +++ b/io.c @@ -1661,20 +1661,20 @@ devopen(const char *name, const char *mode) goto strictopen; } else if (inetfile(name, & isi)) { #ifdef HAVE_SOCKETS - cp = (char *) name; - - /* 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 static unsigned long def_retries = DEFAULT_RETRIES; static bool first_time = true; unsigned long retries = 0; static long msleep = 1000; bool hard_error = false; + bool non_fatal = is_non_fatal_redirect(name); + + cp = (char *) name; + + /* 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 */ if (first_time) { char *cp, *end; @@ -1701,28 +1701,39 @@ devopen(const char *name, const char *mode) msleep *= 1000; } } - retries = def_retries; + /* + * PROCINFO["NONFATAL"] or PROCINFO[name, "NONFATAL"] overrrides + * GAWK_SOCK_RETRIES. The explicit code in the program carries + * a bigger stick than the environment variable does. + */ + retries = non_fatal ? 1 : def_retries; errno = 0; do { - openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset, name+isi.remoteport.offset, name+isi.remotehost.offset, & hard_error); + openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset, + name+isi.remoteport.offset, name+isi.remotehost.offset, + & hard_error); retries--; } while (openfd == INVALID_HANDLE && ! hard_error && retries > 0 && usleep(msleep) == 0); save_errno = errno; - } - /* restore original name string */ - cp[isi.localport.offset+isi.localport.len] = '/'; - cp[isi.remotehost.offset+isi.remotehost.len] = '/'; + /* 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")); + fatal(_("TCP/IP communications are not supported")); #endif /* HAVE_SOCKETS */ } strictopen: if (openfd == INVALID_HANDLE) { openfd = open(name, flag, 0666); - if (openfd == INVALID_HANDLE && save_errno) + /* + * ENOENT means there is no such name in the filesystem. + * Therefore it's ok to propagate up the error from + * getaddrinfo() that's in save_errno. + */ + if (openfd == INVALID_HANDLE && errno == ENOENT && save_errno) errno = save_errno; } #if defined(__EMX__) || defined(__MINGW32__) -- cgit v1.2.3