blob: 2f4b26612975fb95a383bafc8cfcc507fbcd88cf [file] [log] [blame]
\input texinfo @c -*-texinfo-*-
@c $Header$
@c $Source$
@c $Locker$
@c Note that although this source file is in texinfo format (more
@c or less), it is not yet suitable for turning into an ``info''
@c file. Sorry, maybe next time.
@c
@c In order to produce hardcopy documentation from a texinfo file,
@c run ``tex com_err.texinfo'' which will load in texinfo.tex,
@c provided in this distribution. (texinfo.tex is from the Free
@c Software Foundation, and is under different copyright restrictions
@c from the rest of this package.)
@ifinfo
@barfo
@end ifinfo
@iftex
@tolerance 10000
@c Mutate section headers...
@begingroup
@catcode#=6
@gdef@secheading#1#2#3{@secheadingi {#3@enspace #1}}
@endgroup
@end iftex
@setfilename com_err
@settitle A Common Error Description Library for UNIX
@ifinfo
This file documents the use of the Common Error Description library.
Copyright (C) 1987, 1988 Student Information Processing Board of the
Massachusetts Institute of Technology.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
used in advertising or publicity pertaining to distribution of the software
without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B.
make no representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied warranty.
Note that the file texinfo.tex, provided with this distribution, is from
the Free Software Foundation, and is under different copyright restrictions
from the remainder of this package.
@end ifinfo
@ignore
Permission is granted to process this file through Tex and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
@setchapternewpage odd
@titlepage
@center @titlefont{A Common Error Description}
@center @titlefont{Library for UNIX}
@sp 2
@center Ken Raeburn
@center Bill Sommerfeld
@sp 1
@center MIT Student Information Processing Board
@sp 3
@center last updated 1 January 1989
@center for version 1.2
@center ***DRAFT COPY ONLY***
@vskip 2in
@center @b{Abstract}
UNIX has always had a clean and simple system call interface, with a
standard set of error codes passed between the kernel and user
programs. Unfortunately, the same cannot be said of many of the
libraries layered on top of the primitives provided by the kernel.
Typically, each one has used a different style of indicating errors to
their callers, leading to a total hodgepodge of error handling, and
considerable amounts of work for the programmer. This paper describes
a library and associated utilities which allows a more uniform way for
libraries to return errors to their callers, and for programs to
describe errors and exceptional conditions to their users.
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1987, 1988 by the Student Information Processing
Board of the Massachusetts Institute of Technology.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
used in advertising or publicity pertaining to distribution of the software
without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B.
make no representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied warranty.
Note that the file texinfo.tex, provided with this distribution, is from
the Free Software Foundation, and is under different copyright restrictions
from the remainder of this package.
@end titlepage
@ifinfo
@c should put a menu here someday....
@end ifinfo
@page
@section Why com_err?
In building application software packages, a programmer often has to
deal with a number of libraries, each of which can use a different
error-reporting mechanism. Sometimes one of two values is returned,
indicating simply SUCCESS or FAILURE, with no description of errors
encountered. Sometimes it is an index into a table of text strings,
where the name of the table used is dependent on the library being
used when the error is generated; since each table starts numbering at
0 or 1, additional information as to the source of the error code is
needed to determine which table to look at. Sometimes no text messages are
supplied at all, and the programmer must supply them at any point at which
he may wish to report error conditions.
Often, a global variable is assigned some value describing the error, but
the programmer has to know in each case whether to look at @code{errno},
@code{h_errno}, the return value from @code{hes_err()}, or whatever other
variables or routines are specified.
And what happens if something
in the procedure of
examining or reporting the error changes the same variable?
The package we have developed is an attempt to present a common
error-handling mechanism to manipulate the most common form of error code
in a fashion that does not have the problems listed above.
A list of up to 256 text messages is supplied to a translator we have
written, along with the three- to four-character ``name'' of the error
table. The library using this error table need only call a routine
generated from this error-table source to make the table ``known'' to the
com_err library, and any error code the library generates can be converted
to the corresponding error message. There is also a default format for
error codes accidentally returned before making the table known, which is
of the form @samp{unknown code foo 32}, where @samp{foo} would be the name
of the table.
@section Error codes
Error codes themselves are 32 bit (signed) integers, of which the high
order 24 bits are an identifier of which error table the error code is
from, and the low order 8 bits are a sequential error number within
the table. An error code may thus be easily decomposed into its component
parts. Only the lowest 32 bits of an error code are considered significant
on systems which support wider values.
Error table 0 is defined to match the UNIX system call error table
(@code{sys_errlist}); this allows @code{errno} values to be used directly
in the library (assuming that @code{errno} is of a type with the same width
as @t{long}). Other error table numbers are formed by compacting together
the first four characters of the error table name. The mapping between
characters in the name and numeric values in the error code are defined in
a system-independent fashion, so that two systems that can pass integral
values between them can reliably pass error codes without loss of meaning;
this should work even if the character sets used are not the same.
(However, if this is to be done, error table 0 should be avoided, since the
local system call error tables may differ.)
Any variable which is to contain an error code should be declared @t{long}.
The draft proposed American National Standard for C (as of May, 1988)
requires that @t{long} variables be at least 32 bits; any system which does
not support 32-bit @t{long} values cannot make use of this package (nor
much other software that assumes an ANSI-C environment base) without
significant effort.
@section Error table source file
The error table source file begins with the declaration of the table name,
as
@example
error_table @var{tablename}
@end example
Individual error codes are
specified with
@example
error_code @var{ERROR_NAME}, @var{"text message"}
@end example
where @samp{ec} can also be used as a short form of @samp{error_code}. To
indicate the end of the table, use @samp{end}. Thus, a (short) sample
error table might be:
@example
error_table dsc
error_code DSC_DUP_MTG_NAME,
"Meeting already exists"
ec DSC_BAD_PATH,
"A bad meeting pathname was given"
ec DSC_BAD_MODES,
"Invalid mode for this access control list"
end
@end example
@section The error-table compiler
The error table compiler is named @code{compile_et}. It takes one
argument, the pathname of a file (ending in @samp{.et}, e.g.,
@samp{dsc_err.et}) containing an error table source file. It parses the
error table, and generates two output files -- a C header file
(@samp{discuss_err.h}) which contains definitions of the numerical values
of the error codes defined in the error table, and a C source file which
should be compiled and linked with the executable. The header file must be
included in the source of a module which wishes to reference the error
codes defined; the object module generated from the C code may be linked in
to a program which wishes to use the printed forms of the error codes.
This translator accepts a @kbd{-language @var{lang}} argument, which
determines for which language (or language variant) the output should be
written. At the moment, @var{lang} is currently limited to @kbd{ANSI-C}
and @kbd{K&R-C}, and some abbreviated forms of each. Eventually, this will
be extended to include some support for C++. The default is currently
@kbd{K&R-C}, though the generated sources will have ANSI-C code
conditionalized on the symbol @t{__STDC__}.
@section Run-time support routines
Any source file which uses the routines supplied with or produced by the
com_err package should include the header file @file{<com_err.h>}. It
contains declarations and definitions which may be needed on some systems.
(Some functions cannot be referenced properly without the return type
declarations in this file. Some functions may work properly on most
architectures even without the header file, but relying on this is not
recommended.)
The run-time support routines and variables provided via this package
include the following:
@example
void initialize_@var{xxxx}_error_table (void);
@end example
One of these routines is built by the error compiler for each error table.
It makes the @var{xxxx} error table ``known'' to the error reporting
system. By convention, this routine should be called in the initialization
routine of the @var{xxxx} library. If the library has no initialization
routine, some combination of routines which form the core of the library
should ensure that this routine is called. It is not advised to leave it
the caller to make this call.
There is no harm in calling this routine more than once.
@example
#define ERROR_TABLE_BASE_@var{xxxx} @var{nnnnn}L
@end example
This symbol contains the value of the first error code entry in the
specified table.
This rarely needs be used by the
programmer.
@example
const char *error_message (long code);
@end example
This routine returns the character string error message associated
with @code{code}; if this is associated with an unknown error table, or
if the code is associated with a known error table but the code is not
in the table, a string of the form @samp{Unknown code @var{xxxx nn}} is
returned, where @var{xxxx} is the error table name produced by
reversing the compaction performed on the error table number implied
by that error code, and @var{nn} is the offset from that base value.
Although this routine is available for use when needed, its use should be
left to circumstances which render @code{com_err} (below) unusable.
@example
void com_err (const char *whoami, /* module reporting error */
long code, /* error code */
const char *format, /* format for additional detail */
...); /* (extra parameters) */
@end example
This routine provides an alternate way to print error messages to
standard error; it allows the error message to be passed in as a
parameter, rather than in an external variable. @emph{Provide grammatical
context for ``message.''}
If @var{format} is @code{(char *)NULL}, the formatted message will not be
printed. @var{format} may not be omitted.
@example
#include <stdarg.h>
void com_err_va (const char *whoami,
long code,
const char *format,
va_list args);
@end example
This routine provides an interface, equivalent to @code{com_err} above,
which may be used by higher-level variadic functions (functions which
accept variable numbers of arguments).
@example
#include <stdarg.h>
void (*set_com_err_hook (void (*proc) ())) ();
void (*@var{proc}) (const char *whoami, long code, va_list args);
void reset_com_err_hook ();
@end example
These two routines allow a routine to be dynamically substituted for
@samp{com_err}. After @samp{set_com_err_hook} has been called,
calls to @samp{com_err} will turn into calls to the new hook routine.
@samp{reset_com_err_hook} turns off this hook. This may intended to
be used in daemons (to use a routine which calls @var{syslog(3)}), or
in a window system application (which could pop up a dialogue box).
If a program is to be used in an environment in which simply printing
messages to the @code{stderr} stream would be inappropriate (such as in a
daemon program which runs without a terminal attached),
@code{set_com_err_hook} may be used to redirect output from @code{com_err}.
The following is an example of an error handler which uses @var{syslog(3)}
as supplied in BSD 4.3:
@example
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
/* extern openlog (const char * name, int logopt, int facility); */
/* extern syslog (int priority, char * message, ...); */
void hook (const char * whoami, long code,
const char * format, va_list args)
@{
char buffer[BUFSIZ];
static int initialized = 0;
if (!initialized) @{
openlog (whoami,
LOG_NOWAIT|LOG_CONS|LOG_PID|LOG_NDELAY,
LOG_DAEMON);
initialized = 1;
@}
vsprintf (buffer, format, args);
syslog (LOG_ERR, "%s %s", error_message (code), buffer);
@}
@end example
After making the call
@code{set_com_err_hook (hook);},
any calls to @code{com_err} will result in messages being sent to the
@var{syslogd} daemon for logging.
The name of the program, @samp{whoami}, is supplied to the
@samp{openlog()} call, and the message is formatted into a buffer and
passed to @code{syslog}.
Note that since the extra arguments to @code{com_err} are passed by
reference via the @code{va_list} value @code{args}, the hook routine may
place any form of interpretation on them, including ignoring them. For
consistency, @code{printf}-style interpretation is suggested, via
@code{vsprintf} (or @code{_doprnt} on BSD systems without full support for
the ANSI C library).
@section Coding Conventions
The following conventions are just some general stylistic conventions
to follow when writing robust libraries and programs. Conventions
similar to this are generally followed inside the UNIX kernel and most
routines in the Multics operating system. In general, a routine
either succeeds (returning a zero error code, and doing some side
effects in the process), or it fails, doing minimal side effects; in
any event, any invariant which the library assumes must be maintained.
In general, it is not in the domain of non user-interface library
routines to write error messages to the user's terminal, or halt the
process. Such forms of ``error handling'' should be reserved for
failures of internal invariants and consistancy checks only, as it
provides the user of the library no way to clean up for himself in the
event of total failure.
Library routines which can fail should be set up to return an error
code. This should usually be done as the return value of the
function; if this is not acceptable, the routine should return a
``null'' value, and put the error code into a parameter passed by
reference.
Routines which use the first style of interface can be used from
user-interface levels of a program as follows:
@example
@{
if ((code = initialize_world(getuid(), random())) != 0) @{
com_err("demo", code,
"when trying to initialize world");
exit(1);
@}
if ((database = open_database("my_secrets", &code))==NULL) @{
com_err("demo", code,
"while opening my_secrets");
exit(1);
@}
@}
@end example
A caller which fails to check the return status is in error. It is
possible to look for code which ignores error returns by using lint;
look for error messages of the form ``foobar returns value which is
sometimes ignored'' or ``foobar returns value which is always
ignored.''
Since libraries may be built out of other libraries, it is often necessary
for the success of one routine to depend on another. When a lower level
routine returns an error code, the middle level routine has a few possible
options. It can simply return the error code to its caller after doing
some form of cleanup, it can substitute one of its own, or it can take
corrective action of its own and continue normally. For instance, a
library routine which makes a ``connect'' system call to make a network
connection may reflect the system error code @code{ECONNREFUSED}
(Connection refused) to its caller, or it may return a ``server not
available, try again later,'' or it may try a different server.
Cleanup which is typically necessary may include, but not be limited
to, freeing allocated memory which will not be needed any more,
unlocking concurrancy locks, dropping reference counts, closing file
descriptors, or otherwise undoing anything which the procedure did up
to this point. When there are a lot of things which can go wrong, it
is generally good to write one block of error-handling code which is
branched to, using a goto, in the event of failure. A common source
of errors in UNIX programs is failing to close file descriptors on
error returns; this leaves a number of ``zombied'' file descriptors
open, which eventually causes the process to run out of file
descriptors and fall over.
@example
@{
FILE *f1=NULL, *f2=NULL, *f3=NULL;
int status = 0;
if ( (f1 = fopen(FILE1, "r")) == NULL) @{
status = errno;
goto error;
@}
/*
* Crunch for a while
*/
if ( (f2 = fopen(FILE2, "w")) == NULL) @{
status = errno;
goto error;
@}
if ( (f3 = fopen(FILE3, "a+")) == NULL) @{
status = errno;
goto error;
@}
/*
* Do more processing.
*/
fclose(f1);
fclose(f2);
fclose(f3);
return 0;
error:
if (f1) fclose(f1);
if (f2) fclose(f2);
if (f3) fclose(f3);
return status;
@}
@end example
@section Building and Installation
The distribution of this package will probably be done as a compressed
``tar''-format file available via anonymous FTP from SIPB.MIT.EDU.
Retrieve @samp{pub/com_err.tar.Z} and extract the contents. A subdirectory
@t{profiled} should be created to hold objects compiled for profiling.
Running ``make all'' should then be sufficient to build the library and
error-table compiler. The files @samp{libcom_err.a},
@samp{libcom_err_p.a}, @samp{com_err.h}, and @samp{compile_et} should be
installed for use; @samp{com_err.3} and @samp{compile_et.1} can also be
installed as manual pages.
Potential problems:
@itemize @bullet
@item Use of @code{strcasecmp}, a routine provided in BSD for
case-insensitive string comparisons. If an equivalent routine is
available, you can modify @code{CFLAGS} in the makefile to define
@code{strcasecmp} to the name of that routine.
@item Compilers that defined @code{__STDC__} without providing the header
file @code{<stdarg.h>}. One such example is Metaware's High ``C''
compiler, as provided at Project Athena on the IBM RT/PC workstation; if
@code{__HIGHC__} is defined, it is assumed that @code{<stdarg.h>} is not
available, and therefore @code{<varargs.h>} must be used. If the symbol
@code{VARARGS} is defined (e.g., in the makefile), @code{<varargs.h>} will
be used.
@item If your linker rejects symbols that are simultaneously defined in two
library files, edit @samp{Makefile} to remove @samp{perror.c} from the
library. This file contains a version of @var{perror(3)} which calls
@code{com_err} instead of calling @code{write} directly.
@end itemize
As I do not have access to non-BSD systems, there are probably
bugs present that may interfere with building or using this package on
other systems. If they are reported to me, they can probably be fixed for
the next version.
@section Bug Reports
Please send any comments or bug reports to the principal author: Ken
Raeburn, @t{Raeburn@@Athena.MIT.EDU}.
@section Acknowledgements
I would like to thank: Bill Sommerfeld, for his help with some of this
documentation, and catching some of the bugs the first time around;
Honeywell Information Systems, for not killing off the @emph{Multics}
operating system before I had an opportunity to use it; Honeywell's
customers, who persuaded them not to do so, for a while; Ted Anderson of
CMU, for catching some problems before version 1.2 left the nest; Stan
Zanarotti and several others of MIT's Student Information Processing Board,
for getting us started with ``discuss,'' for which this package was
originally written; and everyone I've talked into --- I mean, asked to read
this document and the ``man'' pages.
@bye