Re: write.2: caveats: write(2) returns zero?

2017-09-21 Thread Ingo Schwarze
Hi Raul,

Raul Miller wrote on Wed, Sep 20, 2017 at 06:31:03PM -0400:

> What are the correct cases where write(2) writes 0 bytes and that is
> considered success (as opposed to being one of the documented error
> cases)?

Most importantly, nbytes == 0.

On OpenBSD, we are not aware of any other such cases.

Elsewhere, i already cited this from the POSIX RATIONALE:

  Also, some existing systems (for example, Eighth Edition) permit
  a write of zero bytes to mean that the reader should get an
  end-of-file indication; for those systems, a return value of zero
  from write() indicates a successful write of an end-of-file
  indication.

That behaviour seems very obsolete to me, though, and in violence
of the POSIX requirements.

Theoretically, there might be systems out there containing special
devices that may do successful partial writes of 0 bytes even when
given nbytes > 0, and which might write more on a later retry.  I'm
not aware of any specific examples, though.  If they exist, they
would be hard to use correctly because you would have to avoid
dangers both of expensive busy loops and of endless loops when
getting 0 and then repeating write attempts to them.

Note that the code example i added suggests to treat 0 as *failure*
for nbytes > 0, not as success.

Yours,
  Ingo



Re: write.2: caveats: write(2) returns zero?

2017-09-20 Thread Raul Miller
On Wed, Sep 20, 2017 at 5:52 PM, Marc Espie  wrote:
> On Wed, Sep 20, 2017 at 09:21:53PM +0200, Ingo Schwarze wrote:
>> So, apart from being safer for weird devices on weird implementations,
>> POSIX clearly recommends the idiom for symmetry with read(2) and
>> for compatibility with some historic implementations - even though
>> the importance of these reasons is likely to further decline, there
>> are so many different reasons that retaining the idiom seems the
>> safest bet.
>
> Symetry with read(2) is bull.
>
> write(2) is never used similarly to read(2). Either it's useful and correct
> or it's not.

What are the correct cases where write(2) writes 0 bytes and that is
considered success (as opposed to being one of the documented error
cases)?

Thanks,

-- 
Raul



Re: write.2: caveats: write(2) returns zero?

2017-09-20 Thread Marc Espie
On Wed, Sep 20, 2017 at 09:21:53PM +0200, Ingo Schwarze wrote:
> So, apart from being safer for weird devices on weird implementations,
> POSIX clearly recommends the idiom for symmetry with read(2) and
> for compatibility with some historic implementations - even though
> the importance of these reasons is likely to further decline, there
> are so many different reasons that retaining the idiom seems the
> safest bet.

Symetry with read(2) is bull.

write(2) is never used similarly to read(2). Either it's useful and correct
or it's not.



Re: write.2: caveats: write(2) returns zero?

2017-09-20 Thread Ingo Schwarze
Hi,

Todd C. Miller wrote on Mon, Sep 18, 2017 at 09:35:45AM -0600:
> On Mon, 18 Sep 2017 16:50:41 +0200, Ingo Schwarze wrote:

>> Indeed, the above code is nonsensical.
>> It will write the same bytes repeatedly in case of partial writes.

> OK millert@

Committed, thanks for checking.

> That does look much better, though I'm not convinced that write(2)
> will ever return 0 unless nbytes is also 0.  POSIX doesn't
> disallow this so I suppose we must assume it could happen.

I admit to a small amount of cargo cult:  Our very own cat(1)
implementation checks against 0, for example.

In addition to your argument that POSIX does not clearly prohibit
implementations from containing exotic devices performing 0-byte
partial writes, the RATIONALE in POSIX also says this:

  Where this volume of POSIX.1-2008 requires -1 to be returned and
  errno set to [EAGAIN], most historical implementations return
  zero (with the O_NDELAY flag set, which is the historical predecessor
  of O_NONBLOCK, but is not itself in this volume of POSIX.1-2008).
  The error indications in this volume of POSIX.1-2008 were chosen
  so that an application can distinguish these cases from end-of-file.
  While write() cannot receive an indication of end-of-file, read()
  can, and the two functions have similar return values. Also, some
  existing systems (for example, Eighth Edition) permit a write of
  zero bytes to mean that the reader should get an end-of-file
  indication; for those systems, a return value of zero from write()
  indicates a successful write of an end-of-file indication.

So, apart from being safer for weird devices on weird implementations,
POSIX clearly recommends the idiom for symmetry with read(2) and
for compatibility with some historic implementations - even though
the importance of these reasons is likely to further decline, there
are so many different reasons that retaining the idiom seems the
safest bet.

> However, if it did, in your example err() will use some an old errno
> value.  I don't think this is actually possible so it is not worth
> cluttering up the error reporting in the example.

Right.  Those arcane dangers are not a good reason for turning a
simple and frequently used three-line idiom into an unwieldy
seven-line monster.

Besides, i consider "cat: stdout: Undefined error: 0" to be a
totally appropriate error message, which clearly indicates that
something went really awry in a very unusual way.  Even if you
would ask me to add four more lines to cat.c to handle a 0 return
value with a different error message, i would be totally at a loss
what better to say.

And if another error happened before, chances are it might even be
related, so overriding the errno might sometimes even hide
information...

And finally, even a suboptimal error message would be much better
than embarking on an infinite loop.

Yours,
  Ingo



Re: write.2: caveats: write(2) returns zero?

2017-09-18 Thread Todd C. Miller
On Mon, 18 Sep 2017 16:50:41 +0200, Ingo Schwarze wrote:

> Indeed, the above code is nonsensical.
> It will write the same bytes repeatedly in case of partial writes.

OK millert@

That does look much better, though I'm not convinced that write(2)
will ever return 0 unless nbytes is also 0.  POSIX doesn't
disallow this so I suppose we must assume it could happen.

However, if it did, in your example err() will use some an old errno
value.  I don't think this is actually possible so it is not worth
cluttering up the error reporting in the example.

 - todd



Re: write.2: caveats: write(2) returns zero?

2017-09-18 Thread Marc Espie
On Mon, Sep 18, 2017 at 04:50:41PM +0200, Ingo Schwarze wrote:
> Hi Marc,
> 
> Marc Espie wrote on Sun, Sep 17, 2017 at 11:53:39AM +0200:
> > On Sat, Sep 16, 2017 at 10:25:19PM -0500, Scott Cheloha wrote:
> 
> >> The second example in the write(2) CAVEATS section is identical to
> >> the corresponding example in the read(2) page:
> >> 
> >>while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)
> 
> > I'm for either scraping the example altogether
> 
> Indeed, the above code is nonsensical.
> It will write the same bytes repeatedly in case of partial writes.
> 
> > or writing a proper one, which would mean embedding any version
> > of safe_write in the man page.
> 
> Here you are.
>   Ingo
> 
> 
> Index: write.2
> ===
> RCS file: /cvs/src/lib/libc/sys/write.2,v
> retrieving revision 1.39
> diff -u -p -r1.39 write.2
> --- write.2   5 Feb 2015 02:33:09 -   1.39
> +++ write.2   18 Sep 2017 14:43:41 -
> @@ -155,6 +155,18 @@ is returned.
>  Otherwise, a \-1 is returned and the global variable
>  .Va errno
>  is set to indicate the error.
> +.Sh EXAMPLES
> +The typical loop allowing partial writes looks like this:
> +.Bd -literal
> +const char *buf;
> +size_t bsz, off;
> +ssize_t nw;
> +int d;
> +
> +for (off = 0; off < bsz; off += nw)
> + if ((nw = write(d, buf + off, bsz - off)) == 0 || nw == -1)
> + err(1, "write");
> +.Ed
>  .Sh ERRORS
>  .Fn write ,
>  .Fn pwrite ,
> @@ -309,21 +321,11 @@ function call appeared in
>  .At v2 .
>  .Sh CAVEATS
>  Error checks should explicitly test for \-1.
> -Code such as
> -.Bd -literal -offset indent
> -while ((nr = write(fd, buf, sizeof(buf))) > 0)
> -.Ed
> -.Pp
> -is not maximally portable, as some platforms allow for
> +On some platforms, if
>  .Fa nbytes
> -to range between
> +is larger than
>  .Dv SSIZE_MAX
> -and
> +but smaller than
>  .Dv SIZE_MAX
> -\- 2, in which case the return value of an error-free
> -.Fn write
> +\- 2, the return value of an error-free call 
>  may appear as a negative number distinct from \-1.
> -Proper loops should use
> -.Bd -literal -offset indent
> -while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)
> -.Ed
Looks much better than what we had, okay espie@



Re: write.2: caveats: write(2) returns zero?

2017-09-18 Thread Ingo Schwarze
Hi Marc,

Marc Espie wrote on Sun, Sep 17, 2017 at 11:53:39AM +0200:
> On Sat, Sep 16, 2017 at 10:25:19PM -0500, Scott Cheloha wrote:

>> The second example in the write(2) CAVEATS section is identical to
>> the corresponding example in the read(2) page:
>> 
>>  while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)

> I'm for either scraping the example altogether

Indeed, the above code is nonsensical.
It will write the same bytes repeatedly in case of partial writes.

> or writing a proper one, which would mean embedding any version
> of safe_write in the man page.

Here you are.
  Ingo


Index: write.2
===
RCS file: /cvs/src/lib/libc/sys/write.2,v
retrieving revision 1.39
diff -u -p -r1.39 write.2
--- write.2 5 Feb 2015 02:33:09 -   1.39
+++ write.2 18 Sep 2017 14:43:41 -
@@ -155,6 +155,18 @@ is returned.
 Otherwise, a \-1 is returned and the global variable
 .Va errno
 is set to indicate the error.
+.Sh EXAMPLES
+The typical loop allowing partial writes looks like this:
+.Bd -literal
+const char *buf;
+size_t bsz, off;
+ssize_t nw;
+int d;
+
+for (off = 0; off < bsz; off += nw)
+   if ((nw = write(d, buf + off, bsz - off)) == 0 || nw == -1)
+   err(1, "write");
+.Ed
 .Sh ERRORS
 .Fn write ,
 .Fn pwrite ,
@@ -309,21 +321,11 @@ function call appeared in
 .At v2 .
 .Sh CAVEATS
 Error checks should explicitly test for \-1.
-Code such as
-.Bd -literal -offset indent
-while ((nr = write(fd, buf, sizeof(buf))) > 0)
-.Ed
-.Pp
-is not maximally portable, as some platforms allow for
+On some platforms, if
 .Fa nbytes
-to range between
+is larger than
 .Dv SSIZE_MAX
-and
+but smaller than
 .Dv SIZE_MAX
-\- 2, in which case the return value of an error-free
-.Fn write
+\- 2, the return value of an error-free call 
 may appear as a negative number distinct from \-1.
-Proper loops should use
-.Bd -literal -offset indent
-while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)
-.Ed



Re: write.2: caveats: write(2) returns zero?

2017-09-17 Thread Scott Cheloha
> On Sep 17, 2017, at 4:53 AM, Marc Espie  wrote:
> 
> On Sat, Sep 16, 2017 at 10:25:19PM -0500, Scott Cheloha wrote:
>> Hi,
>> 
>> [...]
>> 
>> --
>> Scott Cheloha
>> 
>> Index: lib/libc/sys/write.2
>> ===
>> RCS file: /cvs/src/lib/libc/sys/write.2,v
>> retrieving revision 1.39
>> diff -u -p -r1.39 write.2
>> --- lib/libc/sys/write.2 5 Feb 2015 02:33:09 -   1.39
>> +++ lib/libc/sys/write.2 17 Sep 2017 03:02:57 -
>> @@ -311,7 +311,7 @@ function call appeared in
>> Error checks should explicitly test for \-1.
>> Code such as
>> .Bd -literal -offset indent
>> -while ((nr = write(fd, buf, sizeof(buf))) > 0)
>> +while ((nw = write(fd, buf, sizeof(buf))) > 0)
>> .Ed
>> .Pp
>> is not maximally portable, as some platforms allow for
>> @@ -325,5 +325,5 @@ and
>> may appear as a negative number distinct from \-1.
>> Proper loops should use
>> .Bd -literal -offset indent
>> -while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)
>> +while ((nw = write(fd, buf, sizeof(buf))) != -1 && nw == sizeof(buf))
>> .Ed
> 
> Well, that's not okay either, because nw == sizeof(buf) will only make
> sense for file-based fds.

Ah, okay.  So my third question was about partial writes.

I left it out because I figured that we could just say explicitly
that the examples did not cover partial writes if need be.

At least, I think that's what you mean when you say that '== sizeof(buf)'
only makes sense for file-based fds.

> I'm for either scraping the example altogether or writing a proper
> one, which would mean embedding any version of safe_write in the
> man page.

Could you point to an example of safe_write in the tree that covers
what you're looking for?  Is it akin to writeall() in signify(1) or
atomicio() for nc(1)?

--
Scott Cheloha



Re: write.2: caveats: write(2) returns zero?

2017-09-17 Thread Marc Espie
On Sat, Sep 16, 2017 at 10:25:19PM -0500, Scott Cheloha wrote:
> Hi,
> 
> The second example in the write(2) CAVEATS section is identical to
> the corresponding example in the read(2) page:
> 
>   while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)
> 
> read(2) returns 0 on EOF, but that logic is inapplicable to write(2).
> 
> I'm not totally sure what the correct code should be but attached is
> my best guess.
> 
> Also, if "nr" is for "Number Read", because this is the write(2)
> page, would "nw" be better?
> 
> --
> Scott Cheloha
> 
> Index: lib/libc/sys/write.2
> ===
> RCS file: /cvs/src/lib/libc/sys/write.2,v
> retrieving revision 1.39
> diff -u -p -r1.39 write.2
> --- lib/libc/sys/write.2  5 Feb 2015 02:33:09 -   1.39
> +++ lib/libc/sys/write.2  17 Sep 2017 03:02:57 -
> @@ -311,7 +311,7 @@ function call appeared in
>  Error checks should explicitly test for \-1.
>  Code such as
>  .Bd -literal -offset indent
> -while ((nr = write(fd, buf, sizeof(buf))) > 0)
> +while ((nw = write(fd, buf, sizeof(buf))) > 0)
>  .Ed
>  .Pp
>  is not maximally portable, as some platforms allow for
> @@ -325,5 +325,5 @@ and
>  may appear as a negative number distinct from \-1.
>  Proper loops should use
>  .Bd -literal -offset indent
> -while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)
> +while ((nw = write(fd, buf, sizeof(buf))) != -1 && nw == sizeof(buf))
>  .Ed

Well, that's not okay either, because nw == sizeof(buf) will only make
sense for file-based fds.

I'm for either scraping the example altogether or writing a proper
one, which would mean embedding any version of safe_write in the
man page.



write.2: caveats: write(2) returns zero?

2017-09-16 Thread Scott Cheloha
Hi,

The second example in the write(2) CAVEATS section is identical to
the corresponding example in the read(2) page:

while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)

read(2) returns 0 on EOF, but that logic is inapplicable to write(2).

I'm not totally sure what the correct code should be but attached is
my best guess.

Also, if "nr" is for "Number Read", because this is the write(2)
page, would "nw" be better?

--
Scott Cheloha

Index: lib/libc/sys/write.2
===
RCS file: /cvs/src/lib/libc/sys/write.2,v
retrieving revision 1.39
diff -u -p -r1.39 write.2
--- lib/libc/sys/write.25 Feb 2015 02:33:09 -   1.39
+++ lib/libc/sys/write.217 Sep 2017 03:02:57 -
@@ -311,7 +311,7 @@ function call appeared in
 Error checks should explicitly test for \-1.
 Code such as
 .Bd -literal -offset indent
-while ((nr = write(fd, buf, sizeof(buf))) > 0)
+while ((nw = write(fd, buf, sizeof(buf))) > 0)
 .Ed
 .Pp
 is not maximally portable, as some platforms allow for
@@ -325,5 +325,5 @@ and
 may appear as a negative number distinct from \-1.
 Proper loops should use
 .Bd -literal -offset indent
-while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)
+while ((nw = write(fd, buf, sizeof(buf))) != -1 && nw == sizeof(buf))
 .Ed