Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 Oct 2019 01:43:10 +0000
From:      bugzilla-noreply@freebsd.org
To:        bugs@FreeBSD.org
Subject:   [Bug 241559] cat(1) endless loop when writing to special device file
Message-ID:  <bug-241559-227@https.bugs.freebsd.org/bugzilla/>

next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D241559

            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@FreeBSD.org
          Reporter: sigsys@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 t=
hat
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 ou=
t 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
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- bin/cat/cat.c       (revision 354128)
+++ bin/cat/cat.c       (working copy)
@@ -327,7 +327,7 @@
        }
        while ((nr =3D read(rfd, buf, bsize)) > 0)
                for (off =3D 0; nr; nr -=3D nw, off +=3D nw)
-                       if ((nw =3D write(wfd, buf + off, (size_t)nr)) < 0)
+                       if ((nw =3D write(wfd, buf + off, (size_t)nr)) <=3D=
 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 isatt=
y()
in __smakebuf()).  Not very important though I guess.

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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-241559-227>