Re: write.2: caveats: write(2) returns zero?
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?
On Wed, Sep 20, 2017 at 5:52 PM, Marc Espiewrote: > 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?
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?
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?
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?
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?
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?
> On Sep 17, 2017, at 4:53 AM, Marc Espiewrote: > > 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?
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?
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