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