Re: echo(1): check for stdio errors
On 2022/08/10 19:37, Scott Cheloha wrote: > On Thu, Aug 11, 2022 at 02:22:08AM +0200, Jeremie Courreges-Anglas wrote: > > On Wed, Aug 10 2022, Scott Cheloha wrote: > > > [...] > > > > > > 1. Our ksh(1) already checks for stdout errors in the echo builtin. > > > > So do any of the scripts in our source tree use /bin/echo for whatever > > reason? If so, could one of these scripts be broken if /bin/echo > > started to report an error? Shouldn't those scripts be reviewed? > > I didn't look. > > There are... hundreds files that look like shell scripts in src. > > $ cd /usr/src > $ find . -exec egrep -l '\#.*\!.*sh' > ~/src-shell-script-paths > $ wc -l ~/src-shell-script-paths > 1118 /home/ssc/src-shell-script-paths > > A lot of them are in regress/. > > I guess I better start looking. The list is much smaller if you just search the tree for /bin/echo
Re: echo(1): check for stdio errors
On Thu, Aug 11, 2022 at 02:22:08AM +0200, Jeremie Courreges-Anglas wrote: > On Wed, Aug 10 2022, Scott Cheloha wrote: > > [...] > > > > 1. Our ksh(1) already checks for stdout errors in the echo builtin. > > So do any of the scripts in our source tree use /bin/echo for whatever > reason? If so, could one of these scripts be broken if /bin/echo > started to report an error? Shouldn't those scripts be reviewed? I didn't look. There are... hundreds files that look like shell scripts in src. $ cd /usr/src $ find . -exec egrep -l '\#.*\!.*sh' > ~/src-shell-script-paths $ wc -l ~/src-shell-script-paths 1118 /home/ssc/src-shell-script-paths A lot of them are in regress/. I guess I better start looking.
Re: echo(1): check for stdio errors
On Wed, Aug 10 2022, Scott Cheloha wrote: > On Wed, Aug 10, 2022 at 02:23:08PM -0600, Theo de Raadt wrote: >> Scott Cheloha wrote: >> >> > On Wed, Aug 10, 2022 at 12:26:17PM -0600, Theo de Raadt wrote: >> > > Scott Cheloha wrote: >> > > >> > > > We're sorta-kinda circling around adding the missing (?) stdio error >> > > > checking to other utilities in bin/ and usr.bin/, no? I want to be >> > > > sure I understand how to do the next patch, because if we do that it >> > > > will probably be a bunch of programs all at once. >> > > >> > > This specific program has not checked for this condition since at least >> > > 2 AT UNIX. >> > > >> > > Your change does not just add a new warning. It adds a new exit code >> > > condition. >> > > >> > > Some scripts using echo, which accepted the condition because echo would >> > > exit 0 and not check for this condition, will now see this exit 1. Some >> > > scripts will abort, because they use "set -o errexit" or similar. >> > > >> > > You are changing the exit code for a command which is used a lot. >> > > >> > > POSIX does not require or specify exit 1 for this condition. If you >> > > disagree, please show where it says so. >> > >> > It's the usual thing. >0 if "an error occurred". >> >> The 40 year old code base says otherwise. >> >> > Here is my thinking: >> > >> >echo(1) has ONE job: print the arguments given. >> > >> > If it fails to print those arguments, shouldn't we signal that to the >> > program that forked echo(1)? >> >> Only if you validate all callers can handle this change in behaviour. >> >> > How is echo(1) supposed to differentiate between a write(2) that is >> > allowed to fail, e.g. a diagnostic printout from fw_update to the >> > user's stderr, and one that is not allowed to fail? >> >> Perhaps it is not supposed to validate this problem in 2022, because it >> didn't validate it for 40 years. >> >> > Consider this scenario: >> > >> > 1. A shell script uses echo(1) to write something to a file. >> > >> >/bin/echo foo.dat >> /var/workerd/data-processing-list >> > >> > 2. The bytes don't arrive on disk because the file system is full. >> > >> > 3. The shell script succeeds because echo(1) can't fail, even if >> > it fails to do what it was told to do. >> > >> > Isn't that bad? >> > >> > And it isn't necessarily true that some other thing will fail later >> > and the whole interlocking system will fail. ENOSPC is a transient >> > condition. One write(2) can fail and the next write(2) can succeed. >> >> Yet, for 40 years noone complained. >> >> Consider the situation you break and change the behaviour of 1000's of >> shell scripts, and haven'd lifted your finger once to review all the >> shell scripts that call echo. >> >> Have you even compared this behaviour to the echo built-ins in all >> the shells? > > I assume what you mean to say is, roughly: > > Gee, this seems risky. > > What do other echo implementations do? > > 1. Our ksh(1) already checks for stdout errors in the echo builtin. So do any of the scripts in our source tree use /bin/echo for whatever reason? If so, could one of these scripts be broken if /bin/echo started to report an error? Shouldn't those scripts be reviewed? /bin/echo may look unimportant but I think it deserves the same treatment as more complex tools that you may modify in a similar way. While I agree that adding more error reporting would be good, it sounds fair that it should be done while caring for the actual errors. ;) [...] -- jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE
Re: echo(1): check for stdio errors
On Wed, Aug 10, 2022 at 02:23:08PM -0600, Theo de Raadt wrote: > Scott Cheloha wrote: > > > On Wed, Aug 10, 2022 at 12:26:17PM -0600, Theo de Raadt wrote: > > > Scott Cheloha wrote: > > > > > > > We're sorta-kinda circling around adding the missing (?) stdio error > > > > checking to other utilities in bin/ and usr.bin/, no? I want to be > > > > sure I understand how to do the next patch, because if we do that it > > > > will probably be a bunch of programs all at once. > > > > > > This specific program has not checked for this condition since at least > > > 2 AT UNIX. > > > > > > Your change does not just add a new warning. It adds a new exit code > > > condition. > > > > > > Some scripts using echo, which accepted the condition because echo would > > > exit 0 and not check for this condition, will now see this exit 1. Some > > > scripts will abort, because they use "set -o errexit" or similar. > > > > > > You are changing the exit code for a command which is used a lot. > > > > > > POSIX does not require or specify exit 1 for this condition. If you > > > disagree, please show where it says so. > > > > It's the usual thing. >0 if "an error occurred". > > The 40 year old code base says otherwise. > > > Here is my thinking: > > > > echo(1) has ONE job: print the arguments given. > > > > If it fails to print those arguments, shouldn't we signal that to the > > program that forked echo(1)? > > Only if you validate all callers can handle this change in behaviour. > > > How is echo(1) supposed to differentiate between a write(2) that is > > allowed to fail, e.g. a diagnostic printout from fw_update to the > > user's stderr, and one that is not allowed to fail? > > Perhaps it is not supposed to validate this problem in 2022, because it > didn't validate it for 40 years. > > > Consider this scenario: > > > > 1. A shell script uses echo(1) to write something to a file. > > > > /bin/echo foo.dat >> /var/workerd/data-processing-list > > > > 2. The bytes don't arrive on disk because the file system is full. > > > > 3. The shell script succeeds because echo(1) can't fail, even if > > it fails to do what it was told to do. > > > > Isn't that bad? > > > > And it isn't necessarily true that some other thing will fail later > > and the whole interlocking system will fail. ENOSPC is a transient > > condition. One write(2) can fail and the next write(2) can succeed. > > Yet, for 40 years noone complained. > > Consider the situation you break and change the behaviour of 1000's of > shell scripts, and haven'd lifted your finger once to review all the > shell scripts that call echo. > > Have you even compared this behaviour to the echo built-ins in all > the shells? I assume what you mean to say is, roughly: Gee, this seems risky. What do other echo implementations do? 1. Our ksh(1) already checks for stdout errors in the echo builtin. 2. FreeBSD's /bin/echo has checked for writev(2) errors in /bin/echo since 2003: https://cgit.freebsd.org/src/commit/bin/echo/echo.c?id=91b7d6dc5871f532b1a86ee76389a9bc348bdf58 3. NetBSD's /bin/echo has checked for stdout errors with ferror(3) since 2008: http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/echo/echo.c?rev=1.18=text/x-cvsweb-markup_with_tag=MAIN 4. NetBSD's /bin/sh echo builtin has checked for write errors since 2008: http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/sh/bltin/echo.c?rev=1.14=text/x-cvsweb-markup_with_tag=MAIN 5. OpenSolaris has checked for fflush(3) errors in /usr/bin/echo since 2005 (OpenSolaris launch): https://github.com/illumos/illumos-gate/blob/7c478bd95313f5f23a4c958a745db2134aa03244/usr/src/cmd/echo/echo.c#L144 6. Looking forward, illumos inherited and retains the behavior in their /usr/bin/echo. 7. Extrapolating backward, we can assume Solaris did that checking in /usr/bin/echo prior to 2005. 8. GNU Coreutils echo has checked for fflush(3) and fclose(3) errors on stdout since 2000: https://git.savannah.gnu.org/cgit/coreutils.git/commit/src/echo.c?id=d3683509b3953beb014e540f6d6194658ede1dea They use close_stdout() in an atexit(3) hook. close_stdout() is a convenience function provided by gnulib since 1998 that does what I described: https://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commitdiff;h=23928550db5d400f27fa67de29c738ca324a31ea;hp=f76477e515b36a1e10f7734aac3c5478ccf75989 Maybe of note is that they do this atexit(3) stdout flush/close error checking for many of their utilities. 9. The GNU Bash echo builtin has checked for write errors since v2.04, in 2000: https://git.savannah.gnu.org/cgit/bash.git/commit/builtins/echo.def?id=bb70624e964126b7ac4ff085ba163a9c35ffa18f They even noted it in the CHANGES file for that release: https://git.savannah.gnu.org/cgit/bash.git/commit/CHANGES?id=bb70624e964126b7ac4ff085ba163a9c35ffa18f -- I don't think that we are first movers in this case.
Re: echo(1): check for stdio errors
On Wed, Aug 10 2022, "Theo de Raadt" wrote: > Scott Cheloha wrote: > >> We're sorta-kinda circling around adding the missing (?) stdio error >> checking to other utilities in bin/ and usr.bin/, no? I want to be >> sure I understand how to do the next patch, because if we do that it >> will probably be a bunch of programs all at once. > > > This specific program has not checked for this condition since at least > 2 AT UNIX. > > Your change does not just add a new warning. It adds a new exit code > condition. > > Some scripts using echo, which accepted the condition because echo would > exit 0 and not check for this condition, will now see this exit 1. Some > scripts will abort, because they use "set -o errexit" or similar. About this, and only related to echo: the builtin version in ksh(1) does report an error. I have just tried the mentioned ENOSPC case with exec 3>/tmp/o/file; echo foobar >&3; echo $? and /tmp/o being a full MFS filesystem. So shell scripts run with ksh(1) should already handle echo - the builtin - failures. I think it makes sense for the echo(1) executable to behave like the shell builtin. For the other programs, well, I don't have a strong feeling. I'll just note that adding stdio error reporting has been done in some other projects. -- jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE
Re: echo(1): check for stdio errors
Scott Cheloha wrote: > On Wed, Aug 10, 2022 at 12:26:17PM -0600, Theo de Raadt wrote: > > Scott Cheloha wrote: > > > > > We're sorta-kinda circling around adding the missing (?) stdio error > > > checking to other utilities in bin/ and usr.bin/, no? I want to be > > > sure I understand how to do the next patch, because if we do that it > > > will probably be a bunch of programs all at once. > > > > This specific program has not checked for this condition since at least > > 2 AT UNIX. > > > > Your change does not just add a new warning. It adds a new exit code > > condition. > > > > Some scripts using echo, which accepted the condition because echo would > > exit 0 and not check for this condition, will now see this exit 1. Some > > scripts will abort, because they use "set -o errexit" or similar. > > > > You are changing the exit code for a command which is used a lot. > > > > POSIX does not require or specify exit 1 for this condition. If you > > disagree, please show where it says so. > > It's the usual thing. >0 if "an error occurred". The 40 year old code base says otherwise. > Here is my thinking: > > echo(1) has ONE job: print the arguments given. > > If it fails to print those arguments, shouldn't we signal that to the > program that forked echo(1)? Only if you validate all callers can handle this change in behaviour. > How is echo(1) supposed to differentiate between a write(2) that is > allowed to fail, e.g. a diagnostic printout from fw_update to the > user's stderr, and one that is not allowed to fail? Perhaps it is not supposed to validate this problem in 2022, because it didn't validate it for 40 years. > Consider this scenario: > > 1. A shell script uses echo(1) to write something to a file. > > /bin/echo foo.dat >> /var/workerd/data-processing-list > > 2. The bytes don't arrive on disk because the file system is full. > > 3. The shell script succeeds because echo(1) can't fail, even if > it fails to do what it was told to do. > > Isn't that bad? > > And it isn't necessarily true that some other thing will fail later > and the whole interlocking system will fail. ENOSPC is a transient > condition. One write(2) can fail and the next write(2) can succeed. Yet, for 40 years noone complained. Consider the situation you break and change the behaviour of 1000's of shell scripts, and haven'd lifted your finger once to review all the shell scripts that call echo. Have you even compared this behaviour to the echo built-ins in all the shells? Isn't that bad? Your proposal is dead in the water until you assess *the code that calls echo*. If you find one script that breaks, the proposal is even more dead.
Re: echo(1): check for stdio errors
On Wed, Aug 10, 2022 at 12:26:17PM -0600, Theo de Raadt wrote: > Scott Cheloha wrote: > > > We're sorta-kinda circling around adding the missing (?) stdio error > > checking to other utilities in bin/ and usr.bin/, no? I want to be > > sure I understand how to do the next patch, because if we do that it > > will probably be a bunch of programs all at once. > > This specific program has not checked for this condition since at least > 2 AT UNIX. > > Your change does not just add a new warning. It adds a new exit code > condition. > > Some scripts using echo, which accepted the condition because echo would > exit 0 and not check for this condition, will now see this exit 1. Some > scripts will abort, because they use "set -o errexit" or similar. > > You are changing the exit code for a command which is used a lot. > > POSIX does not require or specify exit 1 for this condition. If you > disagree, please show where it says so. It's the usual thing. >0 if "an error occurred". https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html EXIT STATUS The following exit values shall be returned: 0 Successful completion. >0 An error occurred. CONSEQUENCES OF ERRORS Default. > So my question is: What will be broken by this change? > > Nothing isn't an answer. I can write a 5 line shell script that will > observe the change in behaviour. Many large shell scripts could break > from this. I am thinking of fw_update and the installer, but it could > also be a problem in Makefiles. Here is my thinking: echo(1) has ONE job: print the arguments given. If it fails to print those arguments, shouldn't we signal that to the program that forked echo(1)? How is echo(1) supposed to differentiate between a write(2) that is allowed to fail, e.g. a diagnostic printout from fw_update to the user's stderr, and one that is not allowed to fail? > > I want to be sure I understand how to do the next patch, because if we > > do that it will probably be a bunch of programs all at once. > > If you cannot speak to the exit code command changing for this one > simple program, I think there is no case for adding to to hundreds of > other programs. Unless POSIX specifies the requirement, I'd like to see > some justification. > > There will always be situations that UNIX didn't anticipate or handle, > and then POSIX failed to specify. Such things are now unhandled, probably > forever, and have become defacto standards. > > On the balance, is your diff improving on some dangerous problem, or is > it introducing a vast number of dangerous new risks which cannot be > identified (and which would require an audit of every known script > calling echo). Has such an audit been started? Consider this scenario: 1. A shell script uses echo(1) to write something to a file. /bin/echo foo.dat >> /var/workerd/data-processing-list 2. The bytes don't arrive on disk because the file system is full. 3. The shell script succeeds because echo(1) can't fail, even if it fails to do what it was told to do. Isn't that bad? And it isn't necessarily true that some other thing will fail later and the whole interlocking system will fail. ENOSPC is a transient condition. One write(2) can fail and the next write(2) can succeed.
Re: echo(1): check for stdio errors
Scott Cheloha wrote: > We're sorta-kinda circling around adding the missing (?) stdio error > checking to other utilities in bin/ and usr.bin/, no? I want to be > sure I understand how to do the next patch, because if we do that it > will probably be a bunch of programs all at once. This specific program has not checked for this condition since at least 2 AT UNIX. Your change does not just add a new warning. It adds a new exit code condition. Some scripts using echo, which accepted the condition because echo would exit 0 and not check for this condition, will now see this exit 1. Some scripts will abort, because they use "set -o errexit" or similar. You are changing the exit code for a command which is used a lot. POSIX does not require or specify exit 1 for this condition. If you disagree, please show where it says so. So my question is: What will be broken by this change? Nothing isn't an answer. I can write a 5 line shell script that will observe the change in behaviour. Many large shell scripts could break from this. I am thinking of fw_update and the installer, but it could also be a problem in Makefiles. > I want to be sure I understand how to do the next patch, because if we > do that it will probably be a bunch of programs all at once. If you cannot speak to the exit code command changing for this one simple program, I think there is no case for adding to to hundreds of other programs. Unless POSIX specifies the requirement, I'd like to see some justification. There will always be situations that UNIX didn't anticipate or handle, and then POSIX failed to specify. Such things are now unhandled, probably forever, and have become defacto standards. On the balance, is your diff improving on some dangerous problem, or is it introducing a vast number of dangerous new risks which cannot be identified (and which would require an audit of every known script calling echo). Has such an audit been started?
Re: echo(1): check for stdio errors
On Sat, Jul 30, 2022 at 05:23:37PM -0600, Todd C. Miller wrote: > On Sat, 30 Jul 2022 18:19:02 -0500, Scott Cheloha wrote: > > > Bump. The standard's error cases for fflush(3) are identical to those > > for fclose(3): > > > > https://pubs.opengroup.org/onlinepubs/9699919799/functions/fflush.html > > https://pubs.opengroup.org/onlinepubs/9699919799/functions/fclose.html > > > > Is the fact that our fclose(3) can succeed even if the error flag is > > set a bug? > > As far as I can tell, neither fflush() nor fclose() check the status > of the error flag, though they may set it of course. That is why > I was suggesting an explicit ferror() call at the end. I'm sorry, I'm having a dumb moment, I don't quite understand what you're looking for. Please tweak my patch so it's the way you want it, with the ferror(3) call in the right spot. We're sorta-kinda circling around adding the missing (?) stdio error checking to other utilities in bin/ and usr.bin/, no? I want to be sure I understand how to do the next patch, because if we do that it will probably be a bunch of programs all at once. Index: echo.c === RCS file: /cvs/src/bin/echo/echo.c,v retrieving revision 1.10 diff -u -p -r1.10 echo.c --- echo.c 9 Oct 2015 01:37:06 - 1.10 +++ echo.c 10 Aug 2022 18:00:12 - @@ -53,12 +53,15 @@ main(int argc, char *argv[]) nflag = 0; while (*argv) { - (void)fputs(*argv, stdout); - if (*++argv) - putchar(' '); + if (fputs(*argv, stdout) == EOF) + err(1, "stdout"); + if (*++argv && putchar(' ') == EOF) + err(1, "stdout"); } - if (!nflag) - putchar('\n'); + if (!nflag && putchar('\n') == EOF) + err(1, "stdout"); + if (fflush(stdout) == EOF || ferror(stdout) || fclose(stdout) == EOF) + err(1, "stdout"); return 0; }
Re: echo(1): check for stdio errors
On Sat, 30 Jul 2022 18:19:02 -0500, Scott Cheloha wrote: > Bump. The standard's error cases for fflush(3) are identical to those > for fclose(3): > > https://pubs.opengroup.org/onlinepubs/9699919799/functions/fflush.html > https://pubs.opengroup.org/onlinepubs/9699919799/functions/fclose.html > > Is the fact that our fclose(3) can succeed even if the error flag is > set a bug? As far as I can tell, neither fflush() nor fclose() check the status of the error flag, though they may set it of course. That is why I was suggesting an explicit ferror() call at the end. - todd
Re: echo(1): check for stdio errors
On Mon, Jul 11, 2022 at 01:27:23PM -0500, Scott Cheloha wrote: > On Mon, Jul 11, 2022 at 08:31:04AM -0600, Todd C. Miller wrote: > > On Sun, 10 Jul 2022 20:58:35 -0900, Philip Guenther wrote: > > > > > Three thoughts: > > > 1) Since stdio errors are sticky, is there any real advantage to checking > > > each call instead of just checking the final fclose()? > > My thinking was that we have no idea how many arguments we're going to > print, so we may as well fail as soon as possible. > > Maybe in more complex programs there would be a code-length or > complexity-reducing upside to deferring the ferror(3) check until, > say, the end of a subroutine or something. > > > > [...] > > > > Will that really catch all errors? From what I can tell, fclose(3) > > can succeed even if the error flag was set. The pattern I prefer > > is to use a final fflush(3) followed by a call to ferror(3) before > > the fclose(3). > > [...] Bump. The standard's error cases for fflush(3) are identical to those for fclose(3): https://pubs.opengroup.org/onlinepubs/9699919799/functions/fflush.html https://pubs.opengroup.org/onlinepubs/9699919799/functions/fclose.html Is the fact that our fclose(3) can succeed even if the error flag is set a bug? Also, can I go ahead with this? With this patch, echo(1) fails if we (for example) try to write to a full file system. So we are certainly catching more stdio failures: $ /bin/echo test > /tmp/myfile /tmp: write failed, file system is full $ echo $? 0 $ obj/echo test > /tmp/myfile /tmp: write failed, file system is full echo: stdout: No space left on device $ echo $? 1 Progress! Note that the shell builtin already fails in this case: $ type echo echo is a shell builtin $ echo test > /tmp/myfile /tmp: write failed, file system is full jetsam$ echo $? 1 Index: echo.c === RCS file: /cvs/src/bin/echo/echo.c,v retrieving revision 1.10 diff -u -p -r1.10 echo.c --- echo.c 9 Oct 2015 01:37:06 - 1.10 +++ echo.c 30 Jul 2022 23:10:24 - @@ -53,12 +53,15 @@ main(int argc, char *argv[]) nflag = 0; while (*argv) { - (void)fputs(*argv, stdout); - if (*++argv) - putchar(' '); + if (fputs(*argv, stdout) == EOF) + err(1, "stdout"); + if (*++argv && putchar(' ') == EOF) + err(1, "stdout"); } - if (!nflag) - putchar('\n'); + if (!nflag && putchar('\n') == EOF) + err(1, "stdout"); + if (fflush(stdout) == EOF || fclose(stdout) == EOF) + err(1, "stdout"); return 0; }
Re: echo(1): check for stdio errors
On Mon, Jul 11, 2022 at 08:31:04AM -0600, Todd C. Miller wrote: > On Sun, 10 Jul 2022 20:58:35 -0900, Philip Guenther wrote: > > > Three thoughts: > > 1) Since stdio errors are sticky, is there any real advantage to checking > > each call instead of just checking the final fclose()? My thinking was that we have no idea how many arguments we're going to print, so we may as well fail as soon as possible. Maybe in more complex programs there would be a code-length or complexity-reducing upside to deferring the ferror(3) check until, say, the end of a subroutine or something. > > [...] > > Will that really catch all errors? From what I can tell, fclose(3) > can succeed even if the error flag was set. The pattern I prefer > is to use a final fflush(3) followed by a call to ferror(3) before > the fclose(3). That's weird, I was under the impression POSIX mandated an error case for the implicit fflush(3) done by fclose(3). But I'm looking at the standard and seeing nothing specific. So, yes? It is probably more portable to check fflush(3) explicitly? This feels redundant though. Like, obviously I want to flush the descriptor when we close the stream, and obviously I would want to know if the flush failed. That's why I'm using stdio. Index: echo.c === RCS file: /cvs/src/bin/echo/echo.c,v retrieving revision 1.10 diff -u -p -r1.10 echo.c --- echo.c 9 Oct 2015 01:37:06 - 1.10 +++ echo.c 11 Jul 2022 18:19:39 - @@ -53,12 +53,15 @@ main(int argc, char *argv[]) nflag = 0; while (*argv) { - (void)fputs(*argv, stdout); - if (*++argv) - putchar(' '); + if (fputs(*argv, stdout) == EOF) + err(1, "stdout"); + if (*++argv && putchar(' ') == EOF) + err(1, "stdout"); } - if (!nflag) - putchar('\n'); + if (!nflag && putchar('\n') == EOF) + err(1, "stdout"); + if (fflush(stdout) == EOF || fclose(stdout) == EOF) + err(1, "stdout"); return 0; }
Re: echo(1): check for stdio errors
On Sun, 10 Jul 2022 20:58:35 -0900, Philip Guenther wrote: > Three thoughts: > 1) Since stdio errors are sticky, is there any real advantage to checking > each call instead of just checking the final fclose()? Will that really catch all errors? From what I can tell, fclose(3) can succeed even if the error flag was set. The pattern I prefer is to use a final fflush(3) followed by a call to ferror(3) before the fclose(3). - todd
Re: echo(1): check for stdio errors
On Sun, Jul 10, 2022 at 1:08 PM Scott Cheloha wrote: > ok? > > Index: echo.c > === > RCS file: /cvs/src/bin/echo/echo.c,v > retrieving revision 1.10 > diff -u -p -r1.10 echo.c > --- echo.c 9 Oct 2015 01:37:06 - 1.10 > +++ echo.c 10 Jul 2022 22:00:18 - > @@ -53,12 +53,15 @@ main(int argc, char *argv[]) > nflag = 0; > > while (*argv) { > - (void)fputs(*argv, stdout); > - if (*++argv) > - putchar(' '); > + if (fputs(*argv, stdout) == EOF) > + err(1, "stdout"); > + if (*++argv && putchar(' ') == EOF) > + err(1, "stdout"); > } > if (!nflag) > putchar('\n'); > + if (fclose(stdout) == EOF) > + err(1, "stdout"); > > return 0; > } > > Three thoughts: 1) Since stdio errors are sticky, is there any real advantage to checking each call instead of just checking the final fclose()? 2) It is claimed that POSIX requires *all* standard utilities to return failure if any writes to stdout failed. If it's important to fix this in 'echo', can we sketch out how we might fix make fixing this in the other utilities easier? I believe at least some chunk of the GNU utilities now use an atexit() handler to do that; is that a reasonable idea and if not can we come up with something better? 3) It would be no end of surprise and frustration for the external echo utility to behave differently than the sh builtin. Philip
echo(1): check for stdio errors
ok? Index: echo.c === RCS file: /cvs/src/bin/echo/echo.c,v retrieving revision 1.10 diff -u -p -r1.10 echo.c --- echo.c 9 Oct 2015 01:37:06 - 1.10 +++ echo.c 10 Jul 2022 22:00:18 - @@ -53,12 +53,15 @@ main(int argc, char *argv[]) nflag = 0; while (*argv) { - (void)fputs(*argv, stdout); - if (*++argv) - putchar(' '); + if (fputs(*argv, stdout) == EOF) + err(1, "stdout"); + if (*++argv && putchar(' ') == EOF) + err(1, "stdout"); } if (!nflag) putchar('\n'); + if (fclose(stdout) == EOF) + err(1, "stdout"); return 0; }