On 23/06/16 08:13, Paul Eggert wrote:
> Incidentally, 'yes' has a different bug: it mishandles the case where 
> 'write' succeeds but returns a value less than the buffer size. I'll try 
> to look into that too. Simplest would be to use stdio (the comments 
> indicate this has performance issues but I don't know what they are, 
> anyway correctness trumps performance).

Good spot on the yes(1) write(2) bug.
Shouldn't impact too often due to smallish BUFSIZ,
and subsequent writes catching ENOSPC,
but definitely could cause issues.

The attached should fix that up, and keep the same
performance characteristics.

cheers,
Pádraig

>From f410acd5fb0e9aa71809123b7f28b4f5565a2cf9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]>
Date: Thu, 23 Jun 2016 14:15:59 +0100
Subject: [PATCH] yes: handle short writes

* src/yes.c (main): Loop over the write buffer to
handle the case where write may write less than requested.
* NEWS: Mention the bug fix.
Reported by Paul Eggert.
---
 NEWS      |  3 +++
 src/yes.c | 14 +++++++++++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index 71b5c24..daf4367 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,9 @@ GNU coreutils NEWS                                    -*- outline -*-
    seq now immediately exits upon write errors.
    [This bug was present in "the beginning".]
 
+   yes now handles short writes, rather than assuming a single write succeeds.
+   [bug introduced in coreutils-8.24]
+
 ** Changes in behavior
 
    seq no longer accepts 0 value as increment, and now also rejects NaN
diff --git a/src/yes.c b/src/yes.c
index 1d2c612..fd96b07 100644
--- a/src/yes.c
+++ b/src/yes.c
@@ -106,10 +106,18 @@ main (int argc, char **argv)
   /* The normal case is to continuously output the local buffer.  */
   while (i == argc)
     {
-      if (write (STDOUT_FILENO, buf, pbuf - buf) == -1)
+      const char* pwrite = buf;
+      size_t to_write = pbuf - buf;
+      while (to_write)
         {
-          error (0, errno, _("standard output"));
-          return EXIT_FAILURE;
+          ssize_t written = write (STDOUT_FILENO, pwrite, to_write);
+          if (written < 0)
+            {
+              error (0, errno, _("standard output"));
+              return EXIT_FAILURE;
+            }
+          to_write -= written;
+          pwrite += written;
         }
     }
 
-- 
2.5.5

Reply via email to