[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH]: bad interaction between head(1) and pipes

From: ian . bruce . nospam
Subject: [PATCH]: bad interaction between head(1) and pipes
Date: Thu, 09 Aug 2001 01:58:06 -0700

I claim that the following two commands should produce the same
output. Unfortunately, as of textutils-2.0.14, they don't:

$ echo abcdefgh | head -c6                # expected behaviour

$ echo abcdefgh | (head -c3 ; head -c3)   # unexpected behaviour

This is a trivial example, but in some real applications this
behaviour matters. The issue is that head(1) reads data from its input
stream in 4K blocks, throwing away any data left over from the final
block. This works fine when reading from files, but when the input is
a pipe or a character device, it results in the loss of data which may
still be needed. I first noticed this while trying to read a few bytes
from the Linux /dev/random device in a shell script. Doing this a few
times exhausted the accumulated entropy pool, which is normally
several kilobytes large.

The solution is to limit the size of the final read request to what is
actually needed. All prior reads remain at 4K in size, so efficiency
is unaffected. This fixes the problem:

$ echo abcdefgh | (head -c3 ; head -c3)   # fixed behaviour

A patch against textutils-2.0 follows. Please copy me on any responses
to this message, as I'm not subscribed to the mailing list.

-- Ian Bruce  <ian dot bruce at myrealbox dot com>

--- textutils-2.0/src/head.c.orig       Wed Apr 21 22:25:03 1999
+++ textutils-2.0/src/head.c    Mon Aug  6 03:20:48 2001
@@ -117,25 +117,25 @@
 static int
 head_bytes (const char *filename, int fd, uintmax_t bytes_to_write)
   char buffer[BUFSIZE];
-  int bytes_read;
+  int bytes_read, bytes_to_read = BUFSIZE;
   /* Need BINARY I/O for the byte counts to be accurate.  */
   SET_BINARY2 (fd, fileno (stdout));
   while (bytes_to_write)
-      bytes_read = safe_read (fd, buffer, BUFSIZE);
+      if (bytes_to_read > bytes_to_write)
+       bytes_to_read = bytes_to_write;
+      bytes_read = safe_read (fd, buffer, bytes_to_read);
       if (bytes_read < 0)
          error (0, errno, "%s", filename);
          return 1;
       if (bytes_read == 0)
-      if (bytes_read > bytes_to_write)
-       bytes_read = bytes_to_write;
       if (fwrite (buffer, 1, bytes_read, stdout) == 0)
        error (EXIT_FAILURE, errno, _("write error"));
       bytes_to_write -= bytes_read;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]