Files
modules/error.c
rkowen 930e57ec98 A whole slew of changes progressing to deap modulefile directories.
The current is not usuable, but will eventually be.
These changes are checked in for safe keeping while R.K.Owen is on
vacation.
2002-08-02 22:11:24 +00:00

1578 lines
44 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*****
** ** Module Header ******************************************************* **
** **
** Modules Revision 3.0 **
** Providing a flexible user environment **
** **
** File: error.c **
** First Edition: 91/10/23 **
** **
** Authors: Jens Hamisch, jens@Strawberry.COM **
** **
** Description: The modules error logger **
** **
** Exports: Module_Error **
** GetFacilityPtr **
** CheckFacility **
** Enable_Error **
** Disable_Error **
** Restore_Error **
** **
** Notes: **
** **
** ************************************************************************ **
****/
/** ** Copyright *********************************************************** **
** **
** Copyright 1991-1994 by John L. Furlan. **
** see LICENSE.GPL, which must be provided, for details **
** **
** ************************************************************************ **/
static char Id[] = "@(#)$Id: error.c,v 1.6 2002/08/02 22:11:23 rkowen Exp $";
static void *UseId[] = { &UseId, Id };
/** ************************************************************************ **/
/** HEADERS **/
/** ************************************************************************ **/
#include "modules_def.h"
#if HAVE_STDARG_H
# include <stdarg.h>
#else
# error "You need an ANSI C compiler"
#endif
#if defined(HAVE_SYSLOG) && defined(WITH_LOGGING)
# include <syslog.h>
#endif
#include <pwd.h>
#include <grp.h>
/** ************************************************************************ **/
/** LOCAL DATATYPES **/
/** ************************************************************************ **/
/**
** Error weights
**/
typedef enum _err_weights {
WGHT_NONE=0, /** Dummy value: No error **/
WGHT_VERBOSE, /** Verbose messages **/
WGHT_INFO=3, /** Informal message **/
WGHT_DEBUG=5, /** Debugger output **/
WGHT_TRACE, /** Tracing output **/
WGHT_WARN=10, /** Warning: Prog. flow not affected **/
WGHT_PROB=20, /** Problem: Prog. flow cond. aff. **/
WGHT_ERROR=25, /** Error and Fatal: Prog. flow aff. **/
WGHT_FATAL=27, /** Return to the caller **/
WGHT_PANIC=29 /** Panic: Exit program immediatelly **/
} ErrWeights;
/**
** Log facilities
**/
typedef struct _err_facility {
ErrWeights Weight; /** Error weight **/
char *facility; /** Log facility **/
char *def_facility; /** Default facility (facility undef)**/
} ErrFacilities;
typedef struct _facil_names {
char *name; /** Name of a facility **/
int token; /** Assigned token **/
} FacilityNames;
/**
** Error measurement table
**/
typedef struct {
ErrWeights error_weight; /** The weight itsself **/
char *message; /** Message to be printed **/
ErrCode ret_nov, /** Return code **/
ret_adv,
ret_exp;
} ErrMeasr;
/**
** Error code translation table
**/
typedef struct {
ErrType error_type; /** The error type as specified by **/
/** the caller **/
ErrWeights error_weight; /** The weight of this error **/
char *messages; /** List of messages to be printed **/
} ErrTransTab;
/** ************************************************************************ **/
/** CONSTANTS **/
/** ************************************************************************ **/
#define ARGLIST_SIZE 10
#define ERR_LINELEN 80 /** internal buffer size **/
#define ERR_BUFSIZE 4096 /** buffer for the whole error msg. **/
/** ************************************************************************ **/
/** MACROS **/
/** ************************************************************************ **/
/** not applicable **/
/** ************************************************************************ **/
/** LOCAL DATA **/
/** ************************************************************************ **/
static char module_name[] = "error.c"; /** File name of this module **/
/**
** Local flags
**/
static int quiet_on_error = 0;
/**
** Local strings
**/
static char unknown[] = "unknown"; /** If something's unknown **/
static char buffer[ ERR_LINELEN]; /** Internal string buffer **/
char *error_line = NULL;
static int strsize = 0;
/**
** Log facility table
**/
static char _stderr[] = "stderr";
static char _stdout[] = "stdout";
static char _null[] = "null";
static char _none[] = "none";
static char _unknown[] = "unknown";
static ErrFacilities Facilities[] = {
{ WGHT_NONE, NULL, NULL },
{ WGHT_VERBOSE, NULL, DEF_FACILITY_VERBOSE },
{ WGHT_INFO, NULL, DEF_FACILITY_INFO },
{ WGHT_DEBUG, NULL, DEF_FACILITY_DEBUG },
{ WGHT_TRACE, NULL, DEF_FACILITY_TRACE },
{ WGHT_WARN, NULL, DEF_FACILITY_WARN },
{ WGHT_PROB, NULL, DEF_FACILITY_PROB },
{ WGHT_ERROR, NULL, DEF_FACILITY_ERROR },
{ WGHT_FATAL, NULL, DEF_FACILITY_FATAL },
{ WGHT_PANIC, NULL, DEF_FACILITY_PANIC }
};
/**
** Syslog facility names
**/
static FacilityNames facility_names[] = {
#if defined(HAVE_SYSLOG) && defined(WITH_LOGGING)
{ "auth", LOG_AUTH },
{ "cron", LOG_CRON },
{ "daemon", LOG_DAEMON },
{ "kern", LOG_KERN },
{ "local0", LOG_LOCAL0 },
{ "local1", LOG_LOCAL1 },
{ "local2", LOG_LOCAL2 },
{ "local3", LOG_LOCAL3 },
{ "local4", LOG_LOCAL4 },
{ "local5", LOG_LOCAL5 },
{ "local6", LOG_LOCAL6 },
{ "local7", LOG_LOCAL7 },
{ "lpr", LOG_LPR },
{ "mail", LOG_MAIL },
{ "news", LOG_NEWS },
{ "user", LOG_USER },
{ "uucp", LOG_UUCP }
#else
{ "none", 0 }
#endif
};
/**
** Syslog level names
**/
static FacilityNames level_names[] = {
#if defined(HAVE_SYSLOG) && defined(WITH_LOGGING)
{ "alert", LOG_ALERT },
{ "crit", LOG_CRIT },
{ "debug", LOG_DEBUG },
{ "emerg", LOG_EMERG },
{ "err", LOG_ERR },
{ "info", LOG_INFO },
{ "notice", LOG_NOTICE },
{ "warning", LOG_WARNING }
#else
{ "none", 0 }
#endif
};
/**
** Error measurement table
** Take care that this list is sorted in ascending order concerning the error
** weights
**/
#define MEAS_VERB_NDX 1 /** Index of the 'VERBOSE' entry **/
static ErrMeasr Measurements[] = {
{ WGHT_NONE, "" , OK, OK, OK },
{ WGHT_VERBOSE,"VERB" , OK, OK, OK },
{ WGHT_INFO, "INFO" , OK, OK, OK },
{ WGHT_DEBUG, "DEBUG", OK, OK, OK },
{ WGHT_TRACE, "TRACE", OK, OK, OK },
{ WGHT_WARN, "WARN" , PROBLEM, WARN, OK },
{ WGHT_PROB, "PROB" , ERROR, PROBLEM, OK },
{ WGHT_ERROR, "ERROR", ERROR, ERROR, ERROR },
{ WGHT_FATAL, "FATAL", FATAL, FATAL, FATAL },
{ WGHT_PANIC, "PANIC", PANIC, PANIC, PANIC },
};
/**
** Error code translation table
** Take care that this list is sorted in ascending order concerning the error
** types
**/
static ErrTransTab TransTab[] = {
{ NO_ERR, WGHT_NONE, NULL },
{ NO_ERR_DEBUG, WGHT_DEBUG, "$*" },
{ NO_ERR_START, WGHT_DEBUG, "Starting $*" },
{ NO_ERR_END, WGHT_DEBUG, "Exit $*" },
{ NO_ERR_VERBOSE, WGHT_VERBOSE, NULL },
{ ERR_PARAM, WGHT_ERROR, "Paramter error concerning '$1'" },
{ ERR_USAGE, WGHT_ERROR, "Usage is '$*'" },
{ ERR_ARGSTOLONG, WGHT_ERROR, "'$1': Arguments to long. Max. is '$2'" },
{ ERR_OPT_AMBIG, WGHT_ERROR, "Option '$1' is ambiguous" },
{ ERR_OPT_NOARG, WGHT_ERROR, "Option '$1' allows no argument" },
{ ERR_OPT_REQARG, WGHT_ERROR, "Option '$1' requires an argument" },
{ ERR_OPT_UNKNOWN, WGHT_ERROR, "Unrecognized option '$1'" },
{ ERR_OPT_ILL, WGHT_ERROR, "Illegal option '$1'" },
{ ERR_OPT_INV, WGHT_ERROR, "Invalid option '$1'" },
{ ERR_USERLVL, WGHT_ERROR, "Undefined userlevel '$1'" },
{ ERR_GETOPT, WGHT_FATAL, "getopt() failed" },
{ ERR_OPEN, WGHT_ERROR, "Cannot open file '$1' for '$2'" },
{ ERR_POPEN, WGHT_ERROR, "Cannot open pipe '$1' for '$2'" },
{ ERR_OPENDIR, WGHT_ERROR, "Cannot open directory '$1' for reading" },
{ ERR_CLOSE, WGHT_WARN, "Cannot close file '$1'" },
{ ERR_PCLOSE, WGHT_WARN, "Cannot close pipe '$1'" },
{ ERR_CLOSEDIR, WGHT_WARN, "Cannot close directory '$1'" },
{ ERR_READ, WGHT_ERROR, "Error while reading file '$1'" },
{ ERR_READDIR, WGHT_ERROR, "Error while reading directory '$1'" },
{ ERR_WRITE, WGHT_ERROR, "Error while writing file '$1'" },
{ ERR_SEEK, WGHT_ERROR, "Seek error on file '$1'" },
{ ERR_FLUSH, WGHT_WARN, "Flush error on file '$1'" },
{ ERR_DUP, WGHT_WARN, "Cannot duplicate handle of file '$1'" },
{ ERR_DIRNAME, WGHT_ERROR, "Cannot build directory name" },
{ ERR_NAMETOLONG, WGHT_ERROR, "Requested directory name to long: "
"dir='$1',file='$2'" },
{ ERR_DIRNOTFOUND, WGHT_ERROR, "Directory '$1' not found" },
{ ERR_FILEINDIR, WGHT_ERROR, "File '$1' not found in directory '$2'" },
{ ERR_NODIR, WGHT_ERROR, "'$1' is not a directory" },
{ ERR_UNLINK, WGHT_WARN, "Cannot unlink '$1'" },
{ ERR_RENAME, WGHT_PROB, "Cannot rename '$1' to '$2'" },
{ ERR_ALLOC, WGHT_FATAL, "Out of memory." },
{ ERR_SOURCE, WGHT_WARN, "Error sourcing file '$1'" },
{ ERR_UNAME, WGHT_FATAL, "'uname (2)' failed." },
{ ERR_GETHOSTNAME, WGHT_FATAL, "'gethostname (2)' failed." },
{ ERR_GETDOMAINNAME,WGHT_FATAL, "'getdomainname (2)' failed." },
{ ERR_STRING, WGHT_FATAL, "string error" },
{ ERR_MODLIB, WGHT_FATAL, "Modules library error '$1'" },
{ ERR_DISPLAY, WGHT_ERROR, "Cannot open display" },
{ ERR_PARSE, WGHT_ERROR, "Parse error" },
{ ERR_EXEC, WGHT_ERROR, "Tcl command execution failed: $1" },
{ ERR_EXTRACT, WGHT_ERROR, "Cannot extract X11 resources" },
{ ERR_COMMAND, WGHT_ERROR, "'$1' is an unrecognized subcommand" },
{ ERR_LOCATE, WGHT_ERROR, "Unable to locate a modulefile for '$1'" },
{ ERR_MAGIC, WGHT_ERROR, "Magic cookie '#%Module' missing in '$1'" },
{ ERR_MODULE_PATH, WGHT_ERROR, "'MODULEPATH' not set" },
{ ERR_HOME, WGHT_ERROR, "'HOME' not set" },
{ ERR_SHELL, WGHT_ERROR, "Unknown shell type '$1'" },
{ ERR_DERELICT, WGHT_ERROR, "Unknown shell derelict '$1'" },
{ ERR_CONFLICT, WGHT_ERROR, "Module '$1' conflicts with the currently "
"loaded module(s) '$2*'" },
{ ERR_PREREQ, WGHT_ERROR, "Module '$1' depends on one of the "
"module(s) '$2*'" },
{ ERR_NOTLOADED, WGHT_ERROR, "Module '$1' is currently not loaded" },
{ ERR_DUP_SYMVERS, WGHT_PROB, "Duplicate version symbol '$1' found" },
{ ERR_SYMLOOP, WGHT_ERROR, "Version symbol '$1' loops" },
{ ERR_BADMODNAM, WGHT_PROB, "Invalid modulename '$1' found" },
{ ERR_DUP_ALIAS, WGHT_WARN, "Duplicate alias '$1' found" },
{ ERR_CACHE_INVAL, WGHT_ERROR, "Invalid cache version '$1' found" },
{ ERR_CACHE_LOAD, WGHT_WARN, "Couldn't load the cache properly" },
{ ERR_BEGINENV, WGHT_WARN, "Invalid update subcommand "
"- no .modulesbeginenv" },
{ ERR_INIT_TCL, WGHT_ERROR, "Cannot initialize TCL" },
{ ERR_INIT_TCLX, WGHT_WARN, "Cannot initialize TCLX modules using "
"extended commands might fail" },
{ ERR_INIT_ALPATH, WGHT_WARN, "Could not extend auto_path variable. "
"Module using autoloadable functions might "
"fail" },
{ ERR_INIT_STUP, WGHT_WARN, "Cannot find a 'module load' command in "
"any of the '$1' startup files" },
{ ERR_SET_VAR, WGHT_WARN, "Cannot set TCL variable '$1'" },
{ ERR_INFO_DESCR, WGHT_ERROR, "Unrecognized module info descriptor '$1'" },
{ ERR_INVWGHT_WARN, WGHT_WARN, "Invalid error weight '$1' found" },
{ ERR_INVFAC_WARN, WGHT_WARN, "Invalid log facility '$1'" },
{ ERR_COLON, WGHT_WARN, "Spurious colon in pattern '$1'" },
{ ERR_INTERNAL, WGHT_PANIC, "Modules Internal error" },
{ ERR_INTERAL, WGHT_PANIC, "Internal error in the alias handler" },
{ ERR_INTERRL, WGHT_PANIC, "Internal error in the error logger" },
{ ERR_INVAL, WGHT_PANIC, "Invalid error type '$1' found" },
{ ERR_INVWGHT, WGHT_PANIC, "Invalid error weight '$1' found" },
{ ERR_INVFAC, WGHT_PANIC, "Invalid log facility '$1'" },
{ ERR_ENVVAR, WGHT_FATAL, "The environment variables LOADMODULES and _LMFILES_ have inconsistent lengths." }
};
/** ************************************************************************ **/
/** PROTOTYPES **/
/** ************************************************************************ **/
static ErrTransTab *ErrorLookup( ErrType error_type );
static ErrMeasr *MeasLookup( ErrWeights weigth );
static int FlushError( ErrType Type,
char *module,
int lineno,
ErrWeights Weight,
char *WeightMsg,
char *ErrMsgs,
int argc,
char **argv);
static int PrintError( char *buffer,
ErrType Type,
char *module,
int lineno,
ErrWeights Weight,
char *WeightMsg,
char *ErrMsgs,
int argc,
char **argv);
static char *ErrorString( char *ErrMsgs,
int argc,
char **argv);
static void add_param( char **Control,
char **Target,
int *Length,
int argc,
char **argv);
static int scan_facility( char *s,
FacilityNames *table,
int size);
static char *GetFacility( ErrWeights Weight);
static ErrFacilities *GetFacility_sub( ErrWeights Weight);
static void Print_Tracing( char *buffer,
int result,
int argc,
char **argv);
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: Module_Tracing **
** Print_Tracing **
** Module_Verbosity **
** **
** Description: Display a tracing or verbose message **
** **
** First Edition: 95/12/27 **
** **
** Parameters: int result Result code of th module command **
** int argc Number od arguments to the module **
** command **
** char **argv Argument array **
** char *buffer Print buffer **
** **
** Result: - **
** **
** Attached Globals: g_current_module The module which is handled **
** by the current command **
** **
** ************************************************************************ **
++++*/
void Module_Tracing( int result,
int argc,
char **argv)
{
if( !FlushError( NO_ERR, (char *) NULL, result, WGHT_TRACE, (char *) NULL,
(char *) NULL, argc, argv)) {
ErrorLogger( ERR_INTERRL, LOC, NULL);
}
} /** End of 'Module_Tracing' **/
void Module_Verbosity( int argc,
char **argv)
{
if( sw_verbose && argc && *argv)
if( !FlushError( NO_ERR_VERBOSE, g_current_module,linenum,WGHT_VERBOSE,
Measurements[ MEAS_VERB_NDX].message, *argv, argc, argv)) {
ErrorLogger( ERR_INTERRL, LOC, NULL);
}
} /** End of 'Module_Verbosity' **/
static void Print_Tracing( char *buffer,
int result,
int argc,
char **argv)
{
char *s = buffer;
struct passwd *pwent;
struct group *grpent;
uid_t uid;
gid_t gid;
/**
** Print the arguments
**/
while( argc--) {
/* sprintf( s, "%s ", *argv++); */
strcpy( s, *argv++);
strcat( s, " ");
s += strlen( s);
}
/**
** Add the real and effective user- and group-id
**/
pwent = getpwuid( uid = getuid());
sprintf( s, " [%s(%d)", (pwent ? pwent->pw_name : _unknown), uid);
s += strlen( s);
grpent = getgrgid( gid = getgid());
sprintf( s, ".%s(%d)]", (grpent ? grpent->gr_name : _unknown), gid);
s += strlen( s);
pwent = getpwuid( uid = geteuid());
sprintf( s, " [%s(%d)", (pwent ? pwent->pw_name : _unknown), uid);
s += strlen( s);
grpent = getgrgid( gid = getegid());
sprintf( s, ".%s(%d)] = ", (grpent ? grpent->gr_name : _unknown), gid);
s += strlen( s);
/**
** Add the commands result
**/
switch( result) {
case TCL_OK:
strcpy( s, "TCL_OK");
break;
case TCL_ERROR:
strcpy( s, "TCL_ERROR");
break;
case TCL_RETURN:
strcpy( s, "TCL_RETURN");
break;
case TCL_BREAK:
strcpy( s, "TCL_BREAK");
break;
case TCL_CONTINUE:
strcpy( s, "TCL_CONTINUE");
break;
default:
strcpy( s, "UNKNOWN");
break;
}
s += strlen( s);
sprintf( s, "(%d)", result);
} /** End of 'Module_Tracing' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: Enable_Error, Disable_Error, Restore_Error **
** **
** Description: Enables, disables, or restores error logging **
** Sometimes an error isn't really an error **
** **
** First Edition: 1999/11/11 **
** **
** Parameters: none **
** **
** Result: none **
** **
** ************************************************************************ **
++++*/
static void save_error_state(int reset) {
static int in_effect = 0;
static int saved_state = 0;
if (reset && in_effect ) {
quiet_on_error = saved_state;
in_effect = 0;
} else if (!reset && !in_effect ) {
saved_state = quiet_on_error;
in_effect = 1;
}
}
void Enable_Error(void) {
save_error_state(0);
quiet_on_error = 0;
}
void Disable_Error(void) {
save_error_state(0);
quiet_on_error = 1;
}
void Restore_Error(void) {
quiet_on_error = 0; /* the default is to output errors */
save_error_state(1);
}
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: Module_Error **
** **
** Description: Error handling for the modules package **
** **
** First Edition: 95/08/06 **
** **
** Parameters: ErrType error_type Type of the error **
** char *module Affected module **
** int lineo Line number **
** ... Argument list **
** **
** Result: ErrCode OK No error **
** PROBLEM Problem. Program may **
** continue running **
** ERROR Caller should try to **
** exit gracefully **
** **
** Attached Globals: **
** **
** ************************************************************************ **
++++*/
int Module_Error( ErrType error_type,
char *module,
int lineno,
... )
{
int listsize = ARGLIST_SIZE, /** Initial size of the argu-**/
/** ment list **/
argc = 0; /** Actual number of args **/
char **argv, /** Argument array **/
*arg; /** A single argument **/
va_list parptr; /** Varargs scan pointer **/
ErrTransTab *TransPtr; /** Error transtab entry **/
ErrMeasr *MeasPtr; /** Measurement pointer **/
ErrCode ret_code;
int NoArgs = (error_type == ERR_ALLOC);
if( quiet_on_error ) return OK; /* do nothing - just OK */
/**
** Argument check
**/
if( NO_ERR_VERBOSE == error_type && !sw_verbose)
return( OK);
if( !module)
module = unknown;
/**
** Build the argument array at first
**/
if( NULL == (argv = (char **) malloc( listsize * sizeof( char *)))) {
module = module_name;
error_type = ERR_ALLOC;
NoArgs = 1;
}
va_start( parptr, lineno);
while( !NoArgs && (NULL != (arg = va_arg( parptr, char *)))) {
/**
** Conditionally realloc
**/
while( argc >= listsize) {
listsize += ARGLIST_SIZE;
if( NULL == (argv = (char **) realloc( argv,
listsize * sizeof(char *)))) {
module = module_name;
error_type = ERR_ALLOC;
NoArgs = 1;
break;
}
}
argv[ argc++] = arg;
} /** while **/
if( NO_ERR_VERBOSE == error_type && !argc)
return( OK);
/**
** Locate the error translation table entry according to the
** passed error type
**/
if( NULL == (TransPtr = ErrorLookup( error_type))) {
if( argv)
null_free((void *) &argv);
return( ErrorLogger( ERR_INVAL, LOC, (sprintf( buffer, "%d",
error_type), buffer), NULL));
}
/**
** Now locate the assigned error weight ...
**/
if( NULL == (MeasPtr = MeasLookup( TransPtr->error_weight))) {
if( argv)
null_free((void *) &argv);
argc = 0;
return( ErrorLogger( ERR_INVWGHT, LOC, (sprintf( buffer, "%d",
TransPtr->error_weight), buffer), NULL));
}
/**
** Use the return code as defined for the current user level
**/
switch( sw_userlvl) {
case UL_NOVICE:
ret_code = MeasPtr->ret_nov;
break;
case UL_ADVANCED:
ret_code = MeasPtr->ret_adv;
break;
case UL_EXPERT:
ret_code = MeasPtr->ret_exp;
break;
}
/**
** Print the error message
**/
if( TransPtr->error_weight <= WGHT_TRACE || ret_code != OK)
if( !FlushError( error_type, module, lineno, TransPtr->error_weight,
MeasPtr->message, TransPtr->messages, argc, argv)) {
if( argv)
null_free((void *) &argv);
argc = 0;
return( ErrorLogger( ERR_INTERRL, LOC, NULL));
}
/**
** Return to the caller ... conditionally ...
**/
if( WARN == ret_code)
ret_code = OK;
if( argv)
null_free((void *) &argv);
argc = 0;
if( ret_code > ERROR)
exit( ret_code);
return( ret_code);
} /** End of 'Module_Error' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: ErrorLookup **
** **
** Description: Look up the passed error type in the translation tab.**
** **
** First Edition: 95/08/06 **
** **
** Parameters: ErrType error_type Type of the error **
** **
** Result: ErrTransTab* NULL Not found **
** else Pointer to the acc. entry **
** **
** Attached Globals: **
** **
** ************************************************************************ **
++++*/
static ErrTransTab *ErrorLookup( ErrType error_type )
{
ErrTransTab *low, *mid, *high, *save; /** Search pointers **/
/**
** Init serach pointers
**/
low = TransTab;
high = TransTab + (sizeof( TransTab) / sizeof( TransTab[0]) -1);
mid = (ErrTransTab *) NULL;
/**
** Search loop
**/
while( low < high) {
save = mid;
mid = low + ((high - low) / 2);
if( save == mid)
low = mid = high; /** Just for safety ... **/
if( mid->error_type < error_type ) {
low = mid;
} else if( mid->error_type > error_type ) {
high = mid;
} else
return( mid); /** Yep! Got it! **/
} /** while **/
/**
** Maybe the loop has been finished before the comparison took place
** (low == high) and hit!
**/
if( mid->error_type == error_type )
return( mid); /** Yep! Got it! **/
/**
** If this point is reached, nothing has been found ...
**/
return( NULL);
} /** End of 'ErrorLookup' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: MeasLookup **
** **
** Description: Look up the passed error weight in the measurement **
** table **
** **
** First Edition: 95/08/06 **
** **
** Parameters: ErrWeights weigth Weight of the error **
** **
** Result: ErrMeasr* NULL Not found **
** else Pointer to the acc. entry **
** **
** Attached Globals: **
** **
** ************************************************************************ **
++++*/
static ErrMeasr *MeasLookup( ErrWeights weigth )
{
ErrMeasr *low, *mid, *high, *save; /** Search pointers **/
/**
** Init serach pointers
**/
low = Measurements;
high = Measurements + (sizeof( Measurements) / sizeof( Measurements[0]) -1);
save = (ErrMeasr *) NULL;
mid = (ErrMeasr *) NULL;
/**
** Search loop
**/
while( low < high) {
save = mid;
mid = low + ((high - low) / 2);
if( save == mid)
low = mid = high; /** Just to be sure ... **/
if( mid->error_weight < weigth ) {
low = mid;
} else if( mid->error_weight > weigth ) {
high = mid;
} else
return( mid); /** Yep! Got it! **/
} /** while **/
/**
** Maybe the loop has been finished before the comparison took place
** (low == high) and hit!
**/
if( mid->error_weight == weigth )
return( mid); /** Yep! Got it! **/
/**
** If this point is reached, nothing has been found ...
**/
return( NULL);
} /** End of 'MeasLookup' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: FlushError **
** **
** Description: Print the error message. Decide which facility to **
** use and schedule the according logger routine **
** **
** First Edition: 95/12/21 **
** **
** Parameters: ErrType Type Error type as passed **
** char *module Module name **
** int lineno Line number **
** ErrWeights Weight Error Weight **
** char *WeightMsg Printable Weight **
** char *ErrMsgs Error message **
** int argc Number of arguments **
** char **argv Argument array **
** **
** Result: int 1 Everything OK **
** 0 Error occured while printing **
** **
** ************************************************************************ **
++++*/
static int FlushError( ErrType Type,
char *module,
int lineno,
ErrWeights Weight,
char *WeightMsg,
char *ErrMsgs,
int argc,
char **argv)
{
char *facilities, *buffer;
char *fac;
FILE *facfp;
char *errmsg_buffer;
int fac_alloc = 0;
/**
** get the error facilities at first. If there isn't any, we may
** return on success immediatelly.
**/
if((char *) NULL == (facilities = GetFacility( Weight)))
goto success0;
/**
** PANIC and FATAL error messages ought to be on stderr at least!
**/
if( WGHT_FATAL == Weight || WGHT_PANIC == Weight)
if( !strstr( facilities, _stderr)) {
if((char *) NULL == (buffer = stringer(NULL,0,
_stderr,":", facilities, NULL))) {
ErrorLogger( ERR_STRING, LOC, NULL);
goto unwind0;
}
facilities = buffer;
fac_alloc = 1;
}
/**
** Print the error message into the buffer
**/
if((char *) NULL == (errmsg_buffer = stringer(NULL, ERR_BUFSIZE, NULL))) {
ErrorLogger( ERR_ALLOC, LOC, NULL);
goto unwind1;
}
/**
** In case of verbosity, the first argument is the ErrMsgs format string
**/
if( WGHT_VERBOSE == Weight) {
ErrMsgs = *argv++;
--argc;
}
if( WGHT_TRACE == Weight)
Print_Tracing( errmsg_buffer, lineno, argc, argv);
else if( !PrintError( errmsg_buffer, Type, module, lineno, Weight,
WeightMsg, ErrMsgs, argc, argv))
goto unwind2;
/**
** Now tokenize the facilities string and schedule the error messge
** for every single facility
**/
for( fac = strtok( facilities, ":");
fac;
fac = strtok( (char *) NULL, ":") ) {
/**
** Check for filenames. Two specials are defined: stderr and stdout
** Otherwise filenames are expected to begin on '.' or '/'.
** Everthing not recognized as a filename is assumed to be a
** syslog facility
** 'null' and 'none' are known as 'no logging'
**/
if( !strcmp( fac, _null) || !strcmp( fac, _none))
continue;
else if( !strcmp( fac, _stderr))
fprintf( stderr, "%s", errmsg_buffer);
else if( !strcmp( fac, _stdout))
fprintf( stdout, "%s", errmsg_buffer);
/**
** Syslog
**/
else if( '.' != *fac && '/' != *fac) {
#if defined(HAVE_SYSLOG) && defined(WITH_LOGGING)
int syslog_fac, syslog_lvl;
if( CheckFacility( fac, &syslog_fac, &syslog_lvl)) {
openlog( "modulecmd", LOG_PID, syslog_fac);
setlogmask( LOG_UPTO( syslog_lvl));
syslog( (syslog_fac | syslog_lvl), "%s", errmsg_buffer);
closelog();
/**
** Invalid facilities ... take care not to end up in
** infinite loops
**/
} else if( Type == ERR_INVFAC ||
OK == ErrorLogger( ERR_INVFAC, LOC, fac, NULL))
continue;
#else
# ifdef SYSLOG_DIR
/* this is an intential memory leak */
buffer = stringer(NULL,0, SYSLOG_DIR, "/", fac);
fac = buffer;
# endif
#endif
}
/**
** Custom files ...
** This may result from the syslog part above
**/
if( '.' == *fac || '/' == *fac) {
if((FILE *) NULL == (facfp = fopen( fac, "a"))) {
if( WGHT_PANIC == Weight) /** Avoid endless loops! **/
goto unwind2;
/**
** Invalid facilities ... take care not to end up in
** infinite loops
**/
if( Type == ERR_INVFAC ||
OK == ErrorLogger( ERR_INVFAC, LOC, fac, NULL))
continue;
else
goto unwind2;
}
fprintf( facfp, "%s", errmsg_buffer);
if( EOF == fclose( facfp))
if( OK != ErrorLogger( ERR_CLOSE, LOC, fac, NULL))
goto unwind2;
}
} /** for **/
/**
** Return on success
**/
null_free((void *) &errmsg_buffer);
if( fac_alloc)
null_free((void *) &facilities);
success0:
return( 1); /** -------- EXIT (SUCCESS) -------> **/
unwind2:
null_free((void *) &errmsg_buffer);
unwind1:
if( fac_alloc)
null_free((void *) &facilities);
unwind0:
return( 0); /** -------- EXIT (FAILURE) -------> **/
} /** End of 'FlushError' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: GetFacility **
** **
** Description: Get the log facility according to the passed error **
** weight **
** **
** First Edition: 95/12/21 **
** **
** Parameters: ErrWeights Weight Error Weight **
** **
** Result: char* NULL No facility found **
** Otherwise Pointer to the colon separa- **
** ted facility string **
** **
** ************************************************************************ **
++++*/
static char *GetFacility( ErrWeights Weight)
{
ErrFacilities *facility;
/**
** Get the facility table entry at first
**/
if( !(facility = GetFacility_sub( Weight)))
return((char *) NULL);
/**
** Now we've got two possibilities:
** First of all there may be a custom facilitiy defined
** Otherwise the default facility is to be returned now
**/
return( facility->facility ? facility->facility : facility->def_facility);
} /** End of 'GetFacility' **/
static ErrFacilities *GetFacility_sub( ErrWeights Weight)
{
ErrFacilities *low, *mid, *high, *save;
char buffer[ 20];
/**
** Binary search for the passed facility in the Facilities table.
** This requires the table to be sorted on ascending error weight
**/
low = Facilities;
high = Facilities + (sizeof( Facilities) / sizeof( Facilities[0]));
save = (ErrFacilities *) NULL;
mid = (ErrFacilities *) NULL;
while( low < high) {
save = mid;
mid = low + ((high - low) / 2);
if( save == mid)
low = mid = high; /** Just to be sure ... **/
if( mid->Weight > Weight)
high = mid;
else if( mid->Weight < Weight)
low = mid;
else
break; /** found! **/
}
/**
** We have to check, if we've found something or if there's an internal
** error (wrong weight)
**/
if( mid->Weight != Weight) {
if( OK == ErrorLogger( ERR_INVWGHT, LOC, (sprintf( buffer, "%d",
Weight), buffer), NULL))
return( NULL);
}
return( mid);
} /** End of 'GetFacility_sub' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: CheckFacility **
** **
** Description: Check the passwd string to be a valid combination **
** of <syslog_facility>.<syslog_level> **
** **
** First Edition: 95/12/21 **
** **
** Parameters: char *string Input facility string **
** int *facility Buffer for the real facility **
** int *level Buffer for the real level **
** **
** Result: int 1 Success **
** 0 Failure. String not valid **
** **
** ************************************************************************ **
++++*/
int CheckFacility( char *string, int *facility, int *level)
{
char *s, *buf;
int x;
/**
** We do not want to change the strings ... so allocate a buffer here
**/
if((char *) NULL == (buf = stringer(NULL,0, string,NULL)))
if( OK == ErrorLogger( ERR_STRING, LOC, NULL))
goto unwind0;
/**
** We cannot use strtok here, because there's one initialized in an
** outter loop!
**/
for( s=buf; s && *s && *s != '.'; s++);
if( !s || !*s)
goto unwind1;
*s = '\0';
/**
** This should be the facility
**/
if( -1 == (x = scan_facility( buf, facility_names,
(sizeof( facility_names) / sizeof( facility_names[0])) )))
goto unwind1;
*facility = x;
/**
** This should be the level
**/
if( -1 == (x = scan_facility( ++s, level_names,
(sizeof( level_names) / sizeof( level_names[0])) )))
goto unwind1;
*level = x;
/**
** Success
**/
null_free((void *) &buf);
return( 1); /** -------- EXIT (SUCCESS) -------> **/
unwind1:
null_free((void *) &buf);
unwind0:
return( 0); /** -------- EXIT (FAILURE) -------> **/
} /** End of 'CheckFacility' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: scan_facility **
** **
** Description: Scan the passed facility names table for the given **
** string and pass back the assigned token **
** **
** First Edition: 95/12/21 **
** **
** Parameters: char *s String to be checked **
** FacilityNames *table Table of valid names and **
** tokens **
** int size Size of the table **
** **
** Result: int -1 name not found in the table **
** Otherwise Assigned token **
** **
** ************************************************************************ **
++++*/
static int scan_facility( char *s, FacilityNames *table, int size)
{
FacilityNames *low, *mid, *high, *save;
low = table;
high = table + size;
save = (FacilityNames *) NULL;
while( low < high) {
int x; /** Have to use this, because strcmp will **/
/** not return -1 and 1 on Solaris 2.x **/
save = mid;
mid = low + ((high -low) / 2);
if( save == mid)
low = mid = high; /** To prevent endless loops **/
x = strcmp( mid->name, s);
if( x < 0 )
low = mid;
else if( x > 0)
high = mid;
else
return( mid->token);
} /** while **/
return( !strcmp( mid->name, s) ? mid->token : -1 );
} /** End of 'scan_facility' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: GetFacilityPtr **
** **
** Description: Scan the passed facility names table for the given **
** string and pass back the assigned token **
** **
** First Edition: 95/12/21 **
** **
** Parameters: char *facility Name of the facility **
** **
** Result: char** NULL Invalid facility name **
** Otherwise Pointer to the facilty string**
** reference **
** **
** ************************************************************************ **
++++*/
char **GetFacilityPtr( char *facility)
{
int i, len;
ErrMeasr *measptr;
char *buf, *s, *t;
ErrFacilities *facptr;
/**
** Try to figure out the error weight at first
** Need the given weight in upper case for this
**/
len = strlen( facility);
if((char *) NULL == (buf = stringer(NULL, 0, facility, NULL)))
if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
goto unwind0;
for( t = buf; *t; ++t) *t = toupper(*t);
/**
** Now look up the measurements table for the uppercase weight
**/
i = sizeof( Measurements) / sizeof( Measurements[ 0]);
measptr = Measurements;
while( i) {
if( !strncmp( measptr->message, buf, len))
break;
i--; measptr++;
}
null_free((void *) &buf);
if( !i) /** not found **/
goto unwind0;
/**
** Now get the facility table entry
**/
if((ErrFacilities *) NULL == (facptr = GetFacility_sub(
measptr->error_weight))) {
ErrorLogger( ERR_INVWGHT_WARN, LOC, facility, NULL);
goto unwind0;
}
/**
** Got it ... return the desired pointer
**/
return( &facptr->facility); /** -------- EXIT (RESULT) -------> **/
unwind0:
return((char **) NULL); /** -------- EXIT (FAILURE) -------> **/
} /** End of 'GetFacilityPtr' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: PrintError **
** **
** Description: Print the error message **
** **
** First Edition: 95/08/06 **
** **
** Parameters: char *errbuffer Buffer to hold the **
** error messge **
** ErrType Type Error type as passed **
** char *module Module name **
** int lineno Line number **
** ErrWeights Weight Error Weight **
** char *WeightMsg Printable Weight **
** char *ErrMsgs Error message **
** int argc Number of arguments **
** char **argv Argument array **
** **
** Result: int 1 Everything OK **
** 0 Error occured while printing **
** **
** Notes: According to the error type, the passed module and line num- **
** ber will be handled as a module-file related one or depending**
** on the packages source code: **
** **
** src -> ERR_IN_MODULEFILE -> modulefile -> ERR_INTERNAL -> src**
** **
** ************************************************************************ **
++++*/
static int PrintError( char *errbuffer,
ErrType Type,
char *module,
int lineno,
ErrWeights Weight,
char *WeightMsg,
char *ErrMsgs,
int argc,
char **argv)
{
char *error_string;
/**
** Build the error string at first. Note - we cannot alloc memory any
** more!
**/
if( ERR_ALLOC == Type)
error_string = ErrMsgs;
else
if( NULL == (error_string = ErrorString( ErrMsgs, argc, argv)))
return( 0);
/**
** Print
**/
if( ERR_INTERNAL > Type && ERR_IN_MODULEFILE < Type &&
linenum && g_current_module )
sprintf( errbuffer, "%s(%s):%s:%d: %s\n", g_current_module,
(sprintf( buffer, "%d", linenum), buffer),
WeightMsg, Type, (error_string ? error_string : "") );
else
sprintf( errbuffer, "%s(%s):%s:%d: %s\n", (module ? module : "??"),
( lineno ? (sprintf( buffer, "%d", lineno), buffer) : "??" ),
WeightMsg, Type, (error_string ? error_string : "") );
/**
** Success
**/
return( 1);
} /** End of 'PrintError' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: ErrorString **
** **
** Description: Print the error message **
** **
** First Edition: 95/08/06 **
** **
** Parameters: char *ErrMsgs Error message **
** int argc Number of arguments **
** char **argv Argument array **
** **
** Result: char* NULL Parse or alloc error **
** else Pointer to the error string **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
++++*/
static char *ErrorString( char *ErrMsgs,
int argc,
char **argv)
{
char *s; /** Insertion pointer **/
int len = 0; /** Current length **/
int backslash = 0; /** backslash found ? **/
if( !ErrMsgs)
return( NULL);
/**
** Allocate memory if neccessary
**/
if( !error_line)
if((char *) NULL ==(error_line = stringer(NULL,strsize = ERR_LINELEN,
NULL))){
ErrorLogger( ERR_STRING, LOC, NULL);
return( NULL);
}
s = error_line;
/**
** Scan the error strings to be printed
**/
while( *ErrMsgs) {
/**
** Check for special characters
**/
switch( *ErrMsgs) {
case '\\': if( !backslash) {
backslash = 1;
ErrMsgs++;
continue; /** while( *ErrMsgs) **/
}
break; /** switch **/
case '$': if( !backslash) {
ErrMsgs++;
add_param( &ErrMsgs, &s, &len, argc, argv);
error_line = s - len;
continue; /** while( *ErrMsgs) **/
}
break; /** switch **/
} /** switch **/
/**
** Add a single character to the error string
**/
if( ++len >= strsize - 5) { /** 5 Bytes for safety **/
if( NULL == (error_line = (char *) realloc( error_line,
strsize += ERR_LINELEN))) {
ErrorLogger( ERR_ALLOC, LOC, NULL);
return( NULL);
}
s = error_line + len - 1;
}
*s++ = *ErrMsgs++;
backslash = 0;
} /** while( *ErrMsgs) **/
/**
** Success. Return a pointer to the newly created string
**/
*s++ = '\0';
return( error_line);
} /** End of 'ErrorString' **/
/*++++
** ** Function-Header ***************************************************** **
** **
** Function: add_param **
** **
** Description: Put an argument to the error string **
** **
** First Edition: 95/08/06 **
** **
** Parameters: char **Control Parameter control **
** char **Target Target to print to **
** int *Length Current length of the**
** output string **
** int argc Number of arguments **
** char **argv Argument array **
** **
** Result: - **
** **
** Attached Globals: - **
** **
** ************************************************************************ **
++++*/
static void add_param( char **Control,
char **Target,
int *Length,
int argc,
char **argv)
{
char *s; /** Scan pointer fot the ctrl field **/
int index, last = 0; /** parameter index **/
int len = 0; /** Parameter string length **/
/**
** Copy the current control field into the buffer
**/
for( s = buffer; **Control; (*Control)++ ) {
if( **Control == '*') {
last = argc;
continue;
} else if( **Control < '0' || **Control > '9')
break;
*s++ = **Control;
}
*s = '\0';
/**
** Has something been found ? If not, print a '$'
**/
if( s == buffer && !last) {
if( ++(*Length) >= strsize) {
if( NULL == (error_line = (char*) realloc( error_line,
strsize += ERR_LINELEN))) {
ErrorLogger( ERR_ALLOC, LOC, NULL);
return;
}
*Target = error_line + *Length - 1;
}
*(*Target++) = '$';
} else {
/**
** Something has been found. Form the parameter index at first
**/
if( s == buffer)
index = 0;
else
index = atoi( buffer) - 1;
if( !last)
last = index + 1;
if( last > argc)
last = argc;
/**
** Spool them all out
**/
while( index < last) {
len = strlen( argv[ index]);
while(( *Length + len + 1) >= strsize - 5) {
if( NULL == (error_line = (char*) realloc( error_line,
strsize += ERR_LINELEN))) {
ErrorLogger( ERR_ALLOC, LOC, NULL);
return;
}
*Target = error_line + *Length;
}
strcpy( *Target, argv[ index]);
*Target += len;
*Length += len;
index++;
} /** while **/
} /** if **/
} /** End of 'add_param' **/