[comp.unix.internals] checking return values of close

mjr@hussar.dco.dec.com (Marcus J. Ranum) (10/19/90)

In article <19547:Oct1818:25:2690@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:

>You allude to a real problem, though: an application may have to deal
>with disk-full errors on any write(). An fwaste(fd,n) syscall, to
>allocate n bytes for a file, would solve this.

	Gee - why not just have your systems programmer allocate a fixed
number of sectors of disk for each file when you create it ? :)  Oh, oops,
I forgot - it's been done. Is anyone seriously considering an fwaste()
system call ? I can imagine the results of that ("gee, better make sure I
have a spare megabyte for this one in case I need space next week - this
disk is getting awfully tight because of all the software that uses fwaste()
to grab a spare 256K)

	What's the big deal, anyhow ? So you check your close() calls
if it's important to you that your files close properly. I'm sure everyone
makes sure that fprintf() and printf() don't return EOF, too. I do. I've
had people mention that my code might be big and slow because of all the
error checking, but nothing in my experience runs as slowly as code that
has dumped core.

	A good rule of thumb is that,
"if it returns a value, it might be trying to tell you something."

	I've seen DBMS' that don't check returns on read(2) and write(2),
but I'd be reluctant to use one, and very upset if I bought one.

mjr.
-- 
Nothing is beautiful unless it is large. Vastness and immensity can make
you forget a great many weaknesses.
	- Emperor Napoleon I, predicting the development of X-window in 1813

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/19/90)

In article <1990Oct18.194707.12313@decuac.dec.com> mjr@hussar.dco.dec.com (Marcus J. Ranum) writes:
> Is anyone seriously considering an fwaste()
> system call ? I can imagine the results of that ("gee, better make sure I
> have a spare megabyte for this one in case I need space next week - this
> disk is getting awfully tight because of all the software that uses fwaste()
> to grab a spare 256K)

At worst the application will ftruncate() before closing the file.
fwaste()ing too much is just as dumb as write()ing too much. 

Periodically there are requests for functions to do the same thing. Most
applications know how much disk they need, and it's a lot better to
allocate the space beforehand than to wait for disaster to strike. What
do you think the news package's ``spacefor'' does? fwaste() is also very
useful for asynchronous I/O.

> 	What's the big deal, anyhow ? So you check your close() calls
> if it's important to you that your files close properly.

And do what if it returns EDQUOT? It is simply wrong for write() to
succeed if there's no space for the data. The application might erase
what it wrote; how do you expect it to recover if it doesn't find out
until later? Well?

What excuse do you have for forcing applications to buffer all their
data until close()? There's no efficiency loss in making write() return
accurate errors.

> I'm sure everyone
> makes sure that fprintf() and printf() don't return EOF, too.

But those are meant to use internal buffers, and if you want better
error checking you can and should be using descriptors directly. There's
no level to escape to below descriptors if they don't do the job.

---Dan

bet@bent.mc.duke.edu (Bennett Todd -- gaj) (10/20/90)

Anyone who cares about writing robust programs should be checking the return
values of every system call that can return an error. This can get tedious;
I've seen a solution in other people's programs that I like, and which I've
adopted for my own use.

There is an external "char *" variable "progname", which I initialize to
argv[0] as the first line of executable code in main(). Thereafter, if I
don't want to program any special handling and recovery of an error, but
just print a message and exit, I call a routine whose name is prefixed with
"e". Thus if I call eclose() I don't have to check for an error return; if
anything goes wrong it will end up running

	(void) fprintf(stderr, "%s: close() failed: %s\n", progname,
                                 ((errno == 0)        ? "No error!?" :
	                          ((errno < sys_nerr) ? sys_errlist[errno] :
	                                                "Unknown error")));
	exit(1);

only with the filename included (see below).

I've got routines starting with 'e' for everything that I've needed so far
out of sections 2 and 3 of the UPM; it sure takes the pain out of whipping
out robust utilities. I also have some other goodies tucked in to this
library. Emalloc() overallocates by a fixed amount and inserts a header and
appends a trailer; erealloc()/efree() check the header and trailer,
reporting that the malloc arena has been corrupted if they have been
stomped. Eopen() and efopen() stash a copy of the filename in a table
indexed by the file descriptor; all the routines that take file descriptors
attempt to report the filename by checking that table, and report the file
descriptor number if the filename isn't available. The program size penalty
isn't all that great, the source code doesn't get any more cluttered, and
the resulting programs seem to be more robust in the face of full
filesystems and suchlike.

If anyway wants a copy I'll be glad to email or post my library; it fits
neatly in two mailings/postings, one for libc.h and one for everything else.

-Bennett
bet@orion.mc.duke.edu