[net.lang.c] Not checking printf's result causes another news bug

gnu@sun.uucp (John Gilmore) (08/15/85)

> > The printf() function CAN FAIL and if you don't test for it,
> > Murphy says that it WILL fail, under the worst possible
> > circumstances (e.g., while updating YOUR pay record).
> 
> /usr/lib/news/expire uses fprintf to re-write the active file.  It
> didn't take the time to check the return value, and happened to run
> one night when /usr was full.  Result -- a 0 length active file and
> a great deal of unhappy news software.  printf (and fprintf) DO FAIL!

Furthermore, the code in readnews/vnews that implements the "s"
command (save a message to a file) does not check.  The result is that
a day's worth of [manually] archived net.sources stuff ended up as zero
length files, when my net.sources file system filled up -- with no
error messages at all.  Luckily I noticed the empty files before the
original messages expired.

For the people asking "well what can I do if printf returns an error":
how about printing an error to standard error and stopping?  That's
better than letting the data be thrown away without warning.
(Interactive programs like vnews should, of course, not "stop" but
should print a message and go back to the command interpreter.)

root@bu-cs.UUCP (Barry Shein) (08/16/85)

All this talk about printf() return values not being checked causing
various catastrophes reminds me of another system that had what might
provide a good back-door solution to this without very much re-coding,
namely the IBM/OS SYNAD=addr option. You could set up a (in unix lingo)
a signal handler and if any I/O error occurred it would interrupt to
that routine. Now this was on a per-write (actually, per I/O) basis but
what I have in mind here is to do something like:

#define printf eprintf
#define fprintf efprintf

then add to main() something like

	signal(SIGIOT,myhandler) ;	/* choose a signal, SIGIOT seems good*/

and something reasonable for myhandler() and finally:

eprintf(fmt,a,b,c,d,e,f,g...)	/* etc or maybe use varargs */
{
	int n ;

	if((n = printf(fmt,a,b,...)) < 0)
		kill(0,SIGIOT) ;
	return(n) ;
}
and almost exactly the same for efprintf(fp,...).

(of course, the file with these routines must *not* have the #defines.

Then of course, you get to decide what to do now that you have the
error, but saves you from a lot of re-working of code.

	-Barry Shein, Boston University

Just a suggestion.

guy@sun.uucp (Guy Harris) (08/20/85)

> You could set up a (in unix lingo) a signal handler and if any I/O error
> occurred it would interrupt to that routine. Now this was on a per-write
> (actually, per I/O) basis but what I have in mind here is to do something
> like:
>
> #define printf eprintf
> #define fprintf efprintf
> 
> then add to main() something like
> 
> 	signal(SIGIOT,myhandler) ;	/* choose a signal, SIGIOT seems good*/

No, SIGIOT is what "abort()" causes (except on 4.xBSD - in System V it uses
"kill" so that you can get SIGIOT even if you don't have an IOT
instruction).  In S3/S5/4.3BSD, you can use SIGUSR1; in older BSD releases,
#define SIGUSR1 as 30, and in V7 #define it as 16.  This signal (as the name
suggests) is reserved for user program use.

In System III and System V, though, there is a "software signal" mechanism -
see SSIGNAL(3C).  The claim is made there that "this facility is used by the
Standard C Library to enable users to indicate the disposition of error
signals", but this claims is false; nowhere in the C library is it used.  I
suspect it was intended for this purpose, but nobody bothered changing the
library to use it.  For those of you with non-S3 or S5 systems who have a
source license, you can drop it in.

> and something reasonable for myhandler() and finally:
> 
> eprintf(fmt,a,b,c,d,e,f,g...)	/* etc or maybe use varargs */
> {

Or, preferably, use "vprintf" and its siblings if you have them.  They come
with S3, and with S5R2, but *not* with S5R1.  They can be easily implemented
in any system with "_doprnt" (S5R2 has it and that's how it implements them).

	Guy Harris