Skip to content

Commit 0b2ff76

Browse files
committed
all: avoid repeated diagnostic upon write error
* cfg.mk (sc_some_programs_must_avoid_exit_failure): Adjust to avoid false positive. (sc_prohibit_exit_write_error): A new syntax check to prohibit open coding error(..., "write error"); instead directing to use... * src/system.h (write_error): ... a new function to clear stdout errors before we explicitly diagnose a write error and exit. * src/basenc.c: Use write_error() to ensure no repeated diagnostics. * src/cat.c: Likewise. * src/expand.c: Likewise. * src/factor.c: Likewise. * src/paste.c: Likewise. * src/seq.c: Likewise. * src/shuf.c: Likewise. * src/split.c: Likewise. * src/tail.c: Likewise. * src/tr.c: Likewise. * src/unexpand.c: Likewise. * tests/misc/write-errors.sh: Remove TODOs for the fixed utilities: expand, factor, paste, shuf, tr, unexpand.
1 parent ef47b92 commit 0b2ff76

File tree

14 files changed

+48
-53
lines changed

14 files changed

+48
-53
lines changed

cfg.mk

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,12 @@ sc_prohibit_man_see_also_period:
503503
{ echo '$(ME): do not end "SEE ALSO" section with a period' \
504504
1>&2; exit 1; } || :
505505

506+
sc_prohibit_exit_write_error:
507+
@prohibit='error.*EXIT_FAILURE.*write error' \
508+
in_vc_files='\.c$$' \
509+
halt='Use write_error() instead' \
510+
$(_sc_search_regexp)
511+
506512
# Don't use "indent-tabs-mode: nil" anymore. No longer needed.
507513
sc_prohibit_emacs__indent_tabs_mode__setting:
508514
@prohibit='^( *[*#] *)?indent-tabs-mode:' \
@@ -620,7 +626,8 @@ sc_prohibit_test_empty:
620626
sc_some_programs_must_avoid_exit_failure:
621627
@cd $(srcdir) \
622628
&& grep -nw EXIT_FAILURE \
623-
$$(git grep -El '[^T]_FAILURE|EXIT_CANCELED' $(srcdir)/src) \
629+
$$(git grep -El '[^T]_FAILURE|EXIT_CANCELED' src/) \
630+
| grep -v '^src/system\.h:' \
624631
| grep -vE '= EXIT_FAILURE|return .* \?' | grep . \
625632
&& { echo '$(ME): do not use EXIT_FAILURE in the above' \
626633
1>&2; exit 1; } || :

src/basenc.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ wrap_write (char const *buffer, idx_t len,
924924
{
925925
/* Simple write. */
926926
if (fwrite (buffer, 1, len, stdout) < len)
927-
error (EXIT_FAILURE, errno, _("write error"));
927+
write_error ();
928928
}
929929
else
930930
for (idx_t written = 0; written < len; )
@@ -934,13 +934,13 @@ wrap_write (char const *buffer, idx_t len,
934934
if (to_write == 0)
935935
{
936936
if (fputc ('\n', out) == EOF)
937-
error (EXIT_FAILURE, errno, _("write error"));
937+
write_error ();
938938
*current_column = 0;
939939
}
940940
else
941941
{
942942
if (fwrite (buffer + written, 1, to_write, stdout) < to_write)
943-
error (EXIT_FAILURE, errno, _("write error"));
943+
write_error ();
944944
*current_column += to_write;
945945
written += to_write;
946946
}
@@ -997,7 +997,7 @@ do_encode (FILE *in, char const *infile, FILE *out, idx_t wrap_column)
997997

998998
/* When wrapping, terminate last line. */
999999
if (wrap_column && current_column > 0 && fputc ('\n', out) == EOF)
1000-
error (EXIT_FAILURE, errno, _("write error"));
1000+
write_error ();
10011001

10021002
if (ferror (in))
10031003
error (EXIT_FAILURE, errno, _("read error"));
@@ -1060,7 +1060,7 @@ do_decode (FILE *in, char const *infile, FILE *out, bool ignore_garbage)
10601060
ok = base_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
10611061

10621062
if (fwrite (outbuf, 1, n, out) < n)
1063-
error (EXIT_FAILURE, errno, _("write error"));
1063+
write_error ();
10641064

10651065
if (!ok)
10661066
error (EXIT_FAILURE, 0, _("invalid input"));

src/cat.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ simple_cat (char *buf, idx_t bufsize)
178178
/* Write this block out. */
179179

180180
if (full_write (STDOUT_FILENO, buf, n_read) != n_read)
181-
error (EXIT_FAILURE, errno, _("write error"));
181+
write_error ();
182182
}
183183
}
184184

@@ -193,7 +193,7 @@ write_pending (char *outbuf, char **bpout)
193193
if (0 < n_write)
194194
{
195195
if (full_write (STDOUT_FILENO, outbuf, n_write) != n_write)
196-
error (EXIT_FAILURE, errno, _("write error"));
196+
write_error ();
197197
*bpout = outbuf;
198198
}
199199
}
@@ -257,7 +257,7 @@ cat (char *inbuf, idx_t insize, char *outbuf, idx_t outsize,
257257
do
258258
{
259259
if (full_write (STDOUT_FILENO, wp, outsize) != outsize)
260-
error (EXIT_FAILURE, errno, _("write error"));
260+
write_error ();
261261
wp += outsize;
262262
remaining_bytes = bpout - wp;
263263
}
@@ -794,7 +794,7 @@ main (int argc, char **argv)
794794
if (pending_cr)
795795
{
796796
if (full_write (STDOUT_FILENO, "\r", 1) != 1)
797-
error (EXIT_FAILURE, errno, _("write error"));
797+
write_error ();
798798
}
799799

800800
if (have_read_stdin && close (STDIN_FILENO) < 0)

src/expand.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ expand (void)
144144

145145
while (++column < next_tab_column)
146146
if (putchar (' ') < 0)
147-
error (EXIT_FAILURE, errno, _("write error"));
147+
write_error ();
148148

149149
c = ' ';
150150
}
@@ -169,7 +169,7 @@ expand (void)
169169
return;
170170

171171
if (putchar (c) < 0)
172-
error (EXIT_FAILURE, errno, _("write error"));
172+
write_error ();
173173
}
174174
while (c != '\n');
175175
}

src/factor.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2361,7 +2361,7 @@ lbuf_flush (void)
23612361
{
23622362
size_t size = lbuf.end - lbuf.buf;
23632363
if (full_write (STDOUT_FILENO, lbuf.buf, size) != size)
2364-
error (EXIT_FAILURE, errno, "%s", _("write error"));
2364+
write_error ();
23652365
lbuf.end = lbuf.buf;
23662366
}
23672367

src/paste.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,6 @@ collapse_escapes (char const *strptr)
152152
return backslash_at_end ? 1 : 0;
153153
}
154154

155-
/* Report a write error and exit. */
156-
157-
static void
158-
write_error (void)
159-
{
160-
error (EXIT_FAILURE, errno, _("write error"));
161-
}
162-
163155
/* Output a single byte, reporting any write errors. */
164156

165157
static inline void

src/seq.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,6 @@ long_double_format (char const *fmt, struct layout *layout)
285285
}
286286
}
287287

288-
static void
289-
io_error (void)
290-
{
291-
/* FIXME: consider option to silently ignore errno=EPIPE */
292-
clearerr (stdout);
293-
error (EXIT_FAILURE, errno, _("write error"));
294-
}
295-
296288
/* Actually print the sequence of numbers in the specified range, with the
297289
given or default stepping and format. */
298290

@@ -311,7 +303,7 @@ print_numbers (char const *fmt, struct layout layout,
311303
{
312304
long double x0 = x;
313305
if (printf (fmt, x) < 0)
314-
io_error ();
306+
write_error ();
315307
if (out_of_range)
316308
break;
317309
x = first + i * step;
@@ -358,11 +350,11 @@ print_numbers (char const *fmt, struct layout layout,
358350
}
359351

360352
if (fputs (separator, stdout) == EOF)
361-
io_error ();
353+
write_error ();
362354
}
363355

364356
if (fputs (terminator, stdout) == EOF)
365-
io_error ();
357+
write_error ();
366358
}
367359
}
368360

@@ -539,15 +531,15 @@ seq_fast (char const *a, char const *b, uintmax_t step)
539531
if (buf_end - (p_len + 1) < bufp)
540532
{
541533
if (fwrite (buf, bufp - buf, 1, stdout) != 1)
542-
io_error ();
534+
write_error ();
543535
bufp = buf;
544536
}
545537
}
546538

547539
/* Write any remaining buffered output, and the terminator. */
548540
*bufp++ = *terminator;
549541
if (fwrite (buf, bufp - buf, 1, stdout) != 1)
550-
io_error ();
542+
write_error ();
551543
}
552544

553545
if (ok)

src/shuf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ main (int argc, char **argv)
597597
}
598598

599599
if (i != 0)
600-
error (EXIT_FAILURE, errno, _("write error"));
600+
write_error ();
601601

602602
main_exit (EXIT_SUCCESS);
603603
}

src/split.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ lines_chunk_split (intmax_t k, intmax_t n, char *buf, idx_t bufsize,
957957
large chunks from an existing file, so it's more efficient
958958
to write out directly. */
959959
if (full_write (STDOUT_FILENO, bp, to_write) != to_write)
960-
error (EXIT_FAILURE, errno, "%s", _("write error"));
960+
write_error ();
961961
}
962962
else if (! k)
963963
cwrite (new_file_flag, bp, to_write);
@@ -1214,12 +1214,11 @@ lines_rr (intmax_t k, intmax_t n, char *buf, idx_t bufsize, of_t **filesp)
12141214
if (line_no == k && unbuffered)
12151215
{
12161216
if (full_write (STDOUT_FILENO, bp, to_write) != to_write)
1217-
error (EXIT_FAILURE, errno, "%s", _("write error"));
1217+
write_error ();
12181218
}
12191219
else if (line_no == k && fwrite (bp, to_write, 1, stdout) != 1)
12201220
{
1221-
clearerr (stdout); /* To silence close_stdout(). */
1222-
error (EXIT_FAILURE, errno, "%s", _("write error"));
1221+
write_error ();
12231222
}
12241223
if (next)
12251224
line_no = (line_no == n) ? 1 : line_no + 1;

src/system.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,17 @@ The following directory is part of the cycle:\n %s\n"), \
762762
} \
763763
while (0)
764764

765+
/* exit with a _single_ "write error" diagnostic. */
766+
767+
static inline void
768+
write_error (void)
769+
{
770+
int saved_errno = errno;
771+
fflush (stdout); /* Ensure nothing buffered that might induce an error. */
772+
clearerr (stdout); /* To avoid extraneous diagnostic from close_stdout. */
773+
error (EXIT_FAILURE, saved_errno, _("write error"));
774+
}
775+
765776
/* Like stpncpy, but do ensure that the result is NUL-terminated,
766777
and do not NUL-pad out to LEN. I.e., when strnlen (src, len) == len,
767778
this function writes a NUL byte into dest[len]. Thus, the length

0 commit comments

Comments
 (0)