/***** ** ** 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.2 2001/06/09 09:48:46 rkowen Exp $"; static void *UseId[] = { &UseId, Id }; /** ************************************************************************ **/ /** HEADERS **/ /** ************************************************************************ **/ #include "modules_def.h" #if HAVE_STDARG_H # include #else # error "You need an ANSI C compiler" #endif #if defined(HAVE_SYSLOG) && defined(WITH_LOGGING) # include #endif #include #include /** ************************************************************************ **/ /** 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_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_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_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'" }, }; /** ************************************************************************ **/ /** 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) free( 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) free( 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) free( argv); argc = 0; return( ErrorLogger( ERR_INTERRL, LOC, NULL)); } /** ** Return to the caller ... conditionally ... **/ if( WARN == ret_code) ret_code = OK; if( argv) free( 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))) return( 1); /** ** PANIC and FATAL error messages ought to be on stderr at least! **/ if( WGHT_FATAL == Weight || WGHT_PANIC == Weight) { if( !strstr( facilities, _stderr)) { int x = strlen( facilities); if((char *) NULL == (buffer = (char *) malloc( x + 2 + strlen( _stderr) ))) { ErrorLogger( ERR_ALLOC, LOC, NULL); return( 0); } strcpy( buffer, _stderr); buffer[ 6] = ':'; strcpy( &buffer[7], facilities); facilities = buffer; fac_alloc = 1; } } /** ** Print the error message into the buffer **/ if((char *) NULL == (errmsg_buffer = (char *) malloc( ERR_BUFSIZE))) { ErrorLogger( ERR_ALLOC, LOC, NULL); if( fac_alloc) free( facilities); return( 0); } /** ** 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)) { free( errmsg_buffer); if( fac_alloc) free( facilities); return( 0); } /** ** 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 /* sprintf( buffer, "%s/%s", SYSLOG_DIR, fac); */ strcpy( buffer, SYSLOG_DIR); strcat( buffer, "/"); strcat( buffer, 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! **/ free( errmsg_buffer); if( fac_alloc) free( facilities); return( 0); } /** ** Invalid facilities ... take care not to end up in ** infinite loops **/ if( Type == ERR_INVFAC || OK == ErrorLogger( ERR_INVFAC, LOC, fac, NULL)) { continue; } else { free( errmsg_buffer); if( fac_alloc) free( facilities); return( 0); } } fprintf( facfp, "%s", errmsg_buffer); if( EOF == fclose( facfp)) if( OK != ErrorLogger( ERR_CLOSE, LOC, fac, NULL)) { free( errmsg_buffer); return( 0); } } } /** for **/ /** ** Return on success **/ free( errmsg_buffer); if( fac_alloc) free( facilities); return( 1); } /** 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 . ** ** ** ** 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 = strdup( string))) if( OK == ErrorLogger( ERR_ALLOC, LOC, NULL)) return( 0); /** ** We cannot use strtok here, because there's one initialized in an ** outter loop! **/ for( s=buf; s && *s && *s != '.'; s++); if( !s || !*s) { free( buf); return( 0); /** Bad formed string. **/ } *s = '\0'; /** ** This should be the facility **/ if( -1 == (x = scan_facility( buf, facility_names, (sizeof( facility_names) / sizeof( facility_names[0])) ))) { free( buf); return( 0); } *facility = x; /** ** This should be the level **/ if( -1 == (x = scan_facility( ++s, level_names, (sizeof( level_names) / sizeof( level_names[0])) ))) { free( buf); return( 0); } *level = x; /** ** Success **/ free( buf); return( 1); } /** 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 Invalif 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 = malloc( len + 1))) if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) return((char **) NULL); s = facility; t = buf; while( *t++ = toupper( *s++)); /** ** 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++; } free( buf); if( !i) /** not found **/ return((char **) NULL); /** ** Now get the facility table entry **/ if((ErrFacilities *) NULL == (facptr = GetFacility_sub( measptr->error_weight))) { ErrorLogger( ERR_INVWGHT_WARN, LOC, facility, NULL); return((char **) NULL); } /** ** Got it ... return the desired pointer **/ return( &facptr->facility); } /** 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( NULL == (error_line = (char *) malloc( strsize = ERR_LINELEN))) { ErrorLogger( ERR_ALLOC, 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' **/