You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
532 lines
21 KiB
532 lines
21 KiB
\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.) |
|
|
|
@setfilename com_err.info |
|
@settitle A Common Error Description Library for UNIX |
|
|
|
@ifinfo |
|
@dircategory Development |
|
@direntry |
|
* Com_err: (com_err). A Common Error Description Library for UNIX. |
|
@end direntry |
|
@end ifinfo |
|
|
|
@c smallbook |
|
|
|
@iftex |
|
@finalout |
|
@end iftex |
|
|
|
@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. |
|
|
|
@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 |
|
@end ifinfo |
|
|
|
@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 |
|
|
|
@node Top, Why com_err?, (dir), (dir) |
|
|
|
@top A Common Error Description Library for UNIX |
|
|
|
This manual documents the com_err library. |
|
|
|
@menu |
|
* Why com_err?:: |
|
* Error codes:: |
|
* Error table source file:: |
|
* The error-table compiler:: |
|
* Run-time support routines:: |
|
* Coding Conventions:: |
|
* Building and Installation:: |
|
* Bug Reports:: |
|
* Acknowledgements:: |
|
@end menu |
|
|
|
@page |
|
|
|
@node Why com_err?, Error codes, Top, Top |
|
@chapter 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. |
|
|
|
@node Error codes, Error table source file, Why com_err?, Top |
|
@chapter 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. |
|
|
|
@node Error table source file, The error-table compiler, Error codes, Top |
|
@chapter 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 |
|
|
|
@node The error-table compiler, Run-time support routines, Error table source file, Top |
|
@chapter 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. |
|
|
|
@node Run-time support routines, Coding Conventions, The error-table compiler, Top |
|
@chapter 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. |
|
|
|
@deftypefun const char *error_message (long @var{code}); |
|
|
|
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. |
|
|
|
@end deftypefun |
|
|
|
@deftypefun void com_err (const char *@var{whoami}, long @var{error_code}, const char *@var{format}, ...); |
|
|
|
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.''} |
|
|
|
The module reporting the error should be passed in via @var{whoami}. |
|
If @var{format} is @code{(char *)NULL}, the formatted message will not be |
|
printed. @var{format} may not be omitted. |
|
|
|
@end deftypefun |
|
|
|
@deftypefun void com_err_va (const char *@var{whoami}, long @var{error_code}, const char *@var{format}, va_list @var{args}); |
|
|
|
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). |
|
|
|
@end deftypefun |
|
|
|
@deftypefun void *set_com_err_hook (void (*@var{proc}) (const char *@var{whoami}, long @var{error_code}, va_list @var{args}) (const char *@var{whoami}, long @var{error_code}, va_list @var{args})); |
|
|
|
@deftypefunx void reset_com_err_hook (); |
|
|
|
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 @cite{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 @cite{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). |
|
|
|
@end deftypefun |
|
|
|
@node Coding Conventions, Building and Installation, Run-time support routines, Top |
|
@chapter 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 consistency 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 concurrency 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 |
|
|
|
@node Building and Installation, Bug Reports, Coding Conventions, Top |
|
@chapter 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. |
|
|
|
@node Bug Reports, Acknowledgements, Building and Installation, Top |
|
@chapter Bug Reports |
|
|
|
The principal author of this library is: Ken |
|
Raeburn, @t{raeburn@@MIT.EDU}. |
|
|
|
This version of the com_err library is being maintained by Theodore |
|
Ts'o, and so bugs and comments should be sent to @t{tytso@@thunk.org}. |
|
|
|
|
|
@node Acknowledgements, , Bug Reports, Top |
|
@chapter 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. |
|
|
|
@contents |
|
@bye
|
|
|