aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2017-03-20 21:15:03 +0200
committerArnold D. Robbins <arnold@skeeve.com>2017-03-20 21:15:03 +0200
commit7ec5068a7419cc4dddcf7e060077a1287217c5cd (patch)
tree9369b5591ddb5f0a48421b1b82abd4b02674195b
parentde684770acc545bf14f85655d44fe91e9afa0ba3 (diff)
downloadegawk-7ec5068a7419cc4dddcf7e060077a1287217c5cd.tar.gz
egawk-7ec5068a7419cc4dddcf7e060077a1287217c5cd.tar.bz2
egawk-7ec5068a7419cc4dddcf7e060077a1287217c5cd.zip
Improve handling of EPIPE and fflush.
-rw-r--r--ChangeLog20
-rw-r--r--awk.h12
-rw-r--r--builtin.c21
-rw-r--r--io.c69
-rw-r--r--main.c5
5 files changed, 89 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index a0f26b26..c430cd48 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2017-03-20 Arnold D. Robbins <arnold@skeeve.com>
+
+ Improve handling of EPIPE. Problems reported by
+ Alexandre Ferrieux <alexandre.ferrieux@orange.com>
+ and David Kerns <david.t.kerns@gmail.com>.
+
+ * awk.h (ignore_sigpipe, set_sigpipe_to_default,
+ non_fatal_flush_std): Declare new functions.
+ (ignore_sigpipe, set_sigpipe_to_default,
+ non_fatal_flush_std): New macros.
+ * builtin.c (do_fflush): When nonfatal not in force, flush
+ of stdout/stderr and EPIPE exits, simulating SIGPIPE, as
+ in nawk/mawk. Flush of other redirections with EPIPE now
+ also fatals.
+ (do_system): Use ignore_sipipe and set_sigpipe_to_default
+ instead of uglier inline ifdefed code.
+ * main.c (main): Ditto.
+ * io.c (redirect_string, two_way_open, gawk_popen): Ditto.
+ (flush_io): Use non_fatal_flush_std for stdout and stderr.
+
2017-03-16 Arnold D. Robbins <arnold@skeeve.com>
* configure.ac: Some cleanups.
diff --git a/awk.h b/awk.h
index aae5e7ec..163ad362 100644
--- a/awk.h
+++ b/awk.h
@@ -1584,6 +1584,10 @@ extern bool inrec(IOBUF *iop, int *errcode);
extern int nextfile(IOBUF **curfile, bool skipping);
extern bool is_non_fatal_std(FILE *fp);
extern bool is_non_fatal_redirect(const char *str, size_t len);
+extern void ignore_sigpipe(void);
+extern void set_sigpipe_to_default(void);
+extern bool non_fatal_flush_std_file(FILE *fp);
+
/* main.c */
extern int arg_assign(char *arg, bool initing);
extern int is_std_var(const char *var);
@@ -1958,3 +1962,11 @@ erealloc_real(void *ptr, size_t count, const char *where, const char *var, const
return ret;
}
+
+#ifdef SIGPIPE
+#define ignore_sigpipe() signal(SIGPIPE, SIG_IGN)
+#define set_sigpipe_to_default() signal(SIGPIPE, SIG_DFL)
+#else
+#define ignore_sigpipe()
+#define set_sigpipe_to_default()
+#endif
diff --git a/builtin.c b/builtin.c
index 2acd9928..b92eb19d 100644
--- a/builtin.c
+++ b/builtin.c
@@ -133,7 +133,6 @@ wrerror:
if (fp == stdout && errno == EPIPE)
gawk_exit(EXIT_FATAL);
-
/* otherwise die verbosely */
if ((rp != NULL) ? is_non_fatal_redirect(rp->value, strlen(rp->value)) : is_non_fatal_std(fp))
update_ERRNO_int(errno);
@@ -245,13 +244,19 @@ do_fflush(int nargs)
return make_number((AWKNUM) status);
}
fp = rp->output.fp;
- if (fp != NULL)
+ if (fp != NULL) {
status = rp->output.gawk_fflush(fp, rp->output.opaque);
- else if ((rp->flag & RED_TWOWAY) != 0)
+
+ if (status != 0) {
+ if (! is_non_fatal_redirect(tmp->stptr, tmp->stlen))
+ fatal(_("fflush: cannot flush file `%.*s': %s"),
+ len, file, strerror(errno));
+ }
+ } else if ((rp->flag & RED_TWOWAY) != 0)
warning(_("fflush: cannot flush: two-way pipe `%.*s' has closed write end"),
len, file);
} else if ((fp = stdfile(tmp->stptr, tmp->stlen)) != NULL) {
- status = fflush(fp);
+ status = (non_fatal_flush_std_file(fp) == false);
} else {
status = -1;
warning(_("fflush: `%.*s' is not an open file, pipe or co-process"), len, file);
@@ -2148,9 +2153,7 @@ do_system(int nargs)
cmd[tmp->stlen] = '\0';
os_restore_mode(fileno(stdin));
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_DFL);
-#endif
+ set_sigpipe_to_default();
status = system(cmd);
/*
@@ -2176,9 +2179,7 @@ do_system(int nargs)
if ((BINMODE & BINMODE_INPUT) != 0)
os_setbinmode(fileno(stdin), O_BINARY);
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_IGN);
-#endif
+ ignore_sigpipe();
cmd[tmp->stlen] = save;
}
diff --git a/io.c b/io.c
index cced126e..0da27575 100644
--- a/io.c
+++ b/io.c
@@ -899,9 +899,7 @@ redirect_string(const char *str, size_t explen, bool not_string,
(void) flush_io();
os_restore_mode(fileno(stdin));
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_DFL);
-#endif
+ set_sigpipe_to_default();
/*
* Don't check failure_fatal; see input pipe below.
* Note that the failure happens upon failure to fork,
@@ -911,9 +909,7 @@ redirect_string(const char *str, size_t explen, bool not_string,
if ((rp->output.fp = popen(str, binmode("w"))) == NULL)
fatal(_("can't open pipe `%s' for output (%s)"),
str, strerror(errno));
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_IGN);
-#endif
+ ignore_sigpipe();
/* set close-on-exec */
os_close_on_exec(fileno(rp->output.fp), str, "pipe", "to");
@@ -1392,6 +1388,36 @@ checkwarn:
return status;
}
+/* non_fatal_flush_std_file --- flush a standard output file allowing for nonfatal setting */
+
+bool
+non_fatal_flush_std_file(FILE *fp)
+{
+ int status = fflush(fp);
+
+ if (status != 0) {
+ bool is_fatal = ! is_non_fatal_std(fp);
+
+ if (is_fatal) {
+ if (errno == EPIPE)
+ exit(EXIT_SUCCESS); // simulate SIGPIPE
+ else
+ fatal(fp == stdout
+ ? _("fflush: cannot flush standard output: %s")
+ : _("fflush: cannot flush standard error: %s"),
+ strerror(errno));
+ } else {
+ warning(fp == stdout
+ ? _("error writing standard output (%s)")
+ : _("error writing standard error (%s)"),
+ strerror(errno));
+ }
+ return false;
+ }
+
+ return true;
+}
+
/* flush_io --- flush all open output files */
int
@@ -1401,21 +1427,18 @@ flush_io()
int status = 0;
errno = 0;
- /* we don't warn about stdout/stderr if EPIPE, but we do error exit */
- if (fflush(stdout)) {
- if (errno != EPIPE)
- warning(_("error writing standard output (%s)"), strerror(errno));
+ if (! non_fatal_flush_std_file(stdout))
status++;
- }
- if (fflush(stderr)) {
- if (errno != EPIPE)
- warning(_("error writing standard error (%s)"), strerror(errno));
+
+ errno = 0;
+ if (! non_fatal_flush_std_file(stderr))
status++;
- }
+
+ // now for all open redirections
for (rp = red_head; rp != NULL; rp = rp->next) {
/* flush both files and pipes, what the heck */
if ((rp->flag & RED_WRITE) != 0 && rp->output.fp != NULL) {
- if (rp->output.gawk_fflush(rp->output.fp, rp->output.opaque)) {
+ if (rp->output.gawk_fflush(rp->output.fp, rp->output.opaque) != 0) {
if ((rp->flag & RED_PIPE) != 0)
warning(_("pipe flush of `%s' failed (%s)."),
rp->value, strerror(errno));
@@ -2076,7 +2099,7 @@ two_way_open(const char *str, struct redirect *rp, int extfd)
/* stderr does NOT get dup'ed onto child's stdout */
- signal(SIGPIPE, SIG_DFL);
+ set_sigpipe_to_default();
execl("/bin/sh", "sh", "-c", str, NULL);
_exit(errno == ENOENT ? 127 : 126);
@@ -2253,7 +2276,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);
+ set_sigpipe_to_default();
execl("/bin/sh", "sh", "-c", str, NULL);
_exit(errno == ENOENT ? 127 : 126);
}
@@ -2490,7 +2513,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);
+ set_sigpipe_to_default();
execl("/bin/sh", "sh", "-c", cmd, NULL);
_exit(errno == ENOENT ? 127 : 126);
}
@@ -2555,17 +2578,13 @@ gawk_popen(const char *cmd, struct redirect *rp)
FILE *current;
os_restore_mode(fileno(stdin));
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_DFL);
-#endif
+ set_sigpipe_to_default();
current = popen(cmd, binmode("r"));
if ((BINMODE & BINMODE_INPUT) != 0)
os_setbinmode(fileno(stdin), O_BINARY);
-#ifdef SIGPIPE
- signal(SIGPIPE, SIG_IGN);
-#endif
+ ignore_sigpipe();
if (current == NULL)
return NULL;
diff --git a/main.c b/main.c
index 56482f51..4f578d3e 100644
--- a/main.c
+++ b/main.c
@@ -255,7 +255,7 @@ main(int argc, char **argv)
#ifdef SIGBUS
(void) signal(SIGBUS, catchsig);
#endif
-#ifdef SIGPIPE
+
/*
* Ignore SIGPIPE so that writes to pipes that fail don't
* kill the process but instead return -1 and set errno.
@@ -269,8 +269,7 @@ main(int argc, char **argv)
* should not give us "broken pipe" messages --- mainly because
* it did not do so in the past and people would complain.
*/
- signal(SIGPIPE, SIG_IGN);
-#endif
+ ignore_sigpipe();
(void) sigsegv_install_handler(catchsegv);
#define STACK_SIZE (16*1024)