[comp.unix.programmer] Error handling

scs@adam.mit.edu (Steve Summit) (12/06/90)

While I'm up on an error handling soapbox, I'd like to discuss
what else to do with errno values other than call perror to
interpret and print them.  (This relates to a long discussion
which raged on comp.unix. er, "internals" a while ago.  I'm
crossposting to comp.unix.programmer because this pertains mostly
to Unix/Posix programming.)

In article <14617@smoke.brl.mil>, Doug Gwyn pointed out that (in
Posix),

>The allowable values of errno (<errno.h>
>macros) are specified for each function.

While this is useful information, and helps you figure out how
each function might fail, it is often a bad idea to build
knowledge of specific errno values into a program.  To be sure,
some errno values may be interesting, and a program may well wish
to handle them specially, but (as evidenced by recent discussion)
a lot of people seem to want to believe that the documented vales
are guaranteed to be the only only ones that the function will
ever "return."  This is a dangerous and unnecessary assumption.
It leads to code that ignores error returns because the author
inspected the list of possible errno's and decided that the
program could handle all of them, or that all of them "couldn't
happen" (or that it couldn't handle any of them, and "don't check
for error conditions you can't handle").  All of these
rationalizations are poor.  Don't use

	(void)syscall(...);

or

	if(syscall(...) < 0)
		{
		switch(errno)
			{
			case ENOENT:
				/* ...build one... */
				break;

			case EINTR:
				/* ...retry... */
				break;
			}
		}

Most of the time, use something like

	if(syscall(...) < 0)
		{
		perror("syscall failed");
		return ERROR;
		}

(but see my previous article for other useful information which
should be included in the error message, and how to do so
conveniently.)

If there are a few errno values which you know how to "correct"
(i.e. handle in some special way), use code like the switch
statement above, but include a default case:

	default:
		perror("syscall failed");
		return ERROR;

If the system call "can't fail," or if your program "can't handle
it" (i.e. somehow has to keep processing, even though the system
call failed), or if a failure truly wouldn't matter (e.g. close
fails on a file open for reading), at least use something like

	if(syscall(...) < 0)
		{
		perror("warning: syscall failed");
		fprintf(stderr, "(continuing anyway; hope things are okay)\n");
		}

This lets the user know that something might be amiss.

No matter what the documentation says today, errno values are the
sort of thing that change all the time (or are implemented
slightly incorrectly by a system implementer who didn't read the
fine print), and it is useful to add new ones as systems expand
or are otherwise improved, so it makes sense for a program that
might be around for a while to anticipate the occurrence of
errno's it hasn't heard of yet.

                                                 Steve Summit
                                                 scs@adam.mit.edu