| \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 |