[Bug 241559] cat(1) endless loop when writing to special device file

bugzilla-noreply at freebsd.org bugzilla-noreply at freebsd.org
Tue Oct 29 01:43:11 UTC 2019


https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=241559

            Bug ID: 241559
           Summary: cat(1) endless loop when writing to special device
                    file
           Product: Base System
           Version: 12.1-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: bin
          Assignee: bugs at FreeBSD.org
          Reporter: sigsys at gmail.com

Using cat to write to a disk directly loops forever when it reaches the end of
the disk and there's still data to write (like when using /dev/zero or
/dev/random for example).  write() returns 0 (without setting errno) when that
happens (one of the very rare cases where that can happen it seems) and cat
handles this by retrying the write forever.  It would be better to error out in
this case AFAIK.  There must be tons of programs that react very poorly when
making them write to a device file directly like that, but one might expect
that cat always work (more or less).

$ mdconfig -s 1m -u 10
$ cat /dev/zero > /dev/md10 # loops forever

cp seems to handle it better:

$ cp /dev/zero /dev/md10
cp: /dev/md10: No error: 0

Which isn't a very good error message but still better since it doesn't loop
forever.

With this change:

Index: bin/cat/cat.c
===================================================================
--- bin/cat/cat.c       (revision 354128)
+++ bin/cat/cat.c       (working copy)
@@ -327,7 +327,7 @@
        }
        while ((nr = read(rfd, buf, bsize)) > 0)
                for (off = 0; nr; nr -= nw, off += nw)
-                       if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
+                       if ((nw = write(wfd, buf + off, (size_t)nr)) <= 0)
                                err(1, "stdout");
        if (nr < 0) {
                warn("%s", filename);

It errors out like cp instead:

$ cat /dev/zero > /dev/md10
cat: stdout: No error: 0



That's when cat is in "raw mode".  In "cooked mode", it already errors out, but
it picks up a bogus errno for it:

$ cat -v /dev/zero > /dev/md10
cat: stdout: Inappropriate ioctl for device

Which comes from an isatty() call in stdio.  errno should be saved at some
point, dunno if it should be done by cat or stdio (before its call to isatty()
in __smakebuf()).  Not very important though I guess.

-- 
You are receiving this mail because:
You are the assignee for the bug.


More information about the freebsd-bugs mailing list