1    | /*****
2    |  ** ** Module Header ******************************************************* **
3    |  ** 									     **
4    |  **   Modules Revision 3.0						     **
5    |  **   Providing a flexible user environment				     **
6    |  ** 									     **
7    |  **   File:		error.c						     **
8    |  **   First Edition:	1991/10/23					     **
9    |  ** 									     **
10   |  **   Authors:	Jens Hamisch, jens@Strawberry.COM			     **
11   |  ** 									     **
12   |  **   Description:	The modules error logger			     **
13   |  ** 									     **
14   |  **   Exports:		Module_Error					     **
15   |  **			GetFacilityPtr					     **
16   |  **			CheckFacility					     **
17   |  **			Enable_Error					     **
18   |  **			Disable_Error					     **
19   |  **			Restore_Error					     **
20   |  **									     **
21   |  **   Notes:								     **
22   |  ** 									     **
23   |  ** ************************************************************************ **
24   |  ****/
25   | 
26   | /** ** Copyright *********************************************************** **
27   |  ** 									     **
28   |  ** Copyright 1991-1994 by John L. Furlan.                      	     **
29   |  ** see LICENSE.GPL, which must be provided, for details		     **
30   |  ** 									     ** 
31   |  ** ************************************************************************ **/
32   | 
33   | static char Id[] = "@(#)$Id: error.c.src.html,v 1.6 2006/01/18 05:35:11 rkowen Exp $";
34   | static void *UseId[] = { &UseId, Id };
35   | 
36   | /** ************************************************************************ **/
37   | /** 				      HEADERS				     **/
38   | /** ************************************************************************ **/
39   | 
40   | #include "modules_def.h"
41   | #if HAVE_STDARG_H
42   | #  include <stdarg.h>
43   | #else
44   | #  error "You need an ANSI C compiler"
45   | #endif
46   | 
47   | #if defined(HAVE_SYSLOG) && defined(WITH_LOGGING)
48   | #  include <syslog.h>
49   | #endif
50   | 
51   | #include <pwd.h>
52   | #include <grp.h>
53   | 
54   | /** ************************************************************************ **/
55   | /** 				  LOCAL DATATYPES			     **/
56   | /** ************************************************************************ **/
57   | 
58   | /**
59   |  **  Error weights
60   |  **/
61   | 
62   | typedef enum _err_weights	{
63   |     WGHT_NONE=0,			/** Dummy value: No error	     **/
64   |     WGHT_VERBOSE,			/** Verbose messages		     **/
65   |     WGHT_INFO=3,			/** Informal message	 	     **/
66   |     WGHT_DEBUG=5,			/** Debugger output		     **/
67   |     WGHT_TRACE,				/** Tracing output		     **/
68   |     WGHT_WARN=10,			/** Warning: Prog. flow not affected **/
69   |     WGHT_PROB=20,			/** Problem: Prog. flow cond. aff.   **/
70   |     WGHT_ERROR=25,			/** Error and Fatal: Prog. flow aff. **/
71   |     WGHT_FATAL=27,			/**   Return to the caller	     **/
72   |     WGHT_PANIC=29			/** Panic: Exit program immediatelly **/
73   | } ErrWeights;
74   | 
75   | /**
76   |  **  Log facilities
77   |  **/
78   | 
79   | typedef	struct	_err_facility	{
80   |     ErrWeights	 Weight;		/** Error weight 		     **/
81   |     char	*facility;		/** Log facility		     **/
82   |     char	*def_facility;		/** Default facility (facility undef)**/
83   | } ErrFacilities;
84   | 
85   | typedef struct	_facil_names	{
86   |     char 	*name;			/** Name of a facility		     **/
87   |     int		 token;			/** Assigned token		     **/
88   | } FacilityNames;
89   | 
90   | /**
91   |  **  Error measurement table
92   |  **/
93   | 
94   | typedef	struct	{
95   |     ErrWeights	 error_weight;		/** The weight itsself		     **/
96   |     char	*message;		/** Message to be printed	     **/
97   |     ErrCode	 ret_nov,		/** Return code			     **/
98   | 		 ret_adv,
99   | 		 ret_exp;
100  | } ErrMeasr;
101  | 
102  | /**
103  |  **  Error code translation table
104  |  **/
105  | 
106  | typedef struct  { 
107  |     ErrType	  error_type;		/** The error type as specified by   **/
108  | 					/** the caller			     **/
109  |     ErrWeights    error_weight;		/** The weight of this error         **/
110  |     char	 *messages;		/** List of messages to be printed   **/
111  | } ErrTransTab;
112  | 
113  | /** ************************************************************************ **/
114  | /** 				     CONSTANTS				     **/
115  | /** ************************************************************************ **/
116  | 
117  | #define	ARGLIST_SIZE	10
118  | #define	ERR_LINELEN	80		/** internal buffer size	     **/
119  | #define ERR_BUFSIZE	4096		/** buffer for the whole error msg.  **/
120  | 
121  | /** ************************************************************************ **/
122  | /**				      MACROS				     **/
123  | /** ************************************************************************ **/
124  | 
125  | /** not applicable **/
126  | 
127  | /** ************************************************************************ **/
128  | /** 				    LOCAL DATA				     **/
129  | /** ************************************************************************ **/
130  | 
131  | static	char	module_name[] = "error.c";	/** File name of this module **/
132  | 
133  | /**
134  |  **  Local flags
135  |  **/
136  | static	int	quiet_on_error = 0;
137  | 
138  | /**
139  |  **  Local strings
140  |  **/
141  | 
142  | static	char	unknown[] = "unknown";		/** If something's unknown   **/
143  | 
144  | static	char	 buffer[ ERR_LINELEN];		/** Internal string buffer   **/
145  | 	char	*error_line = NULL;
146  | static	int	 strsize = 0;
147  | 
148  | /**
149  |  **  Log facility table
150  |  **/
151  | 
152  | static	char	_stderr[] = "stderr";
153  | static	char	_stdout[] = "stdout";
154  | static	char	_null[] = "null";
155  | static	char	_none[] = "none";
156  | static	char	_unknown[] = "unknown";
157  | 
158  | static	ErrFacilities	Facilities[] = {
159  |     { WGHT_NONE,	NULL,	NULL },
160  |     { WGHT_VERBOSE,	NULL,	DEF_FACILITY_VERBOSE },
161  |     { WGHT_INFO,	NULL,	DEF_FACILITY_INFO },
162  |     { WGHT_DEBUG,	NULL,	DEF_FACILITY_DEBUG },
163  |     { WGHT_TRACE,	NULL,	DEF_FACILITY_TRACE },
164  |     { WGHT_WARN,	NULL,	DEF_FACILITY_WARN },
165  |     { WGHT_PROB,	NULL,	DEF_FACILITY_PROB },
166  |     { WGHT_ERROR,	NULL,	DEF_FACILITY_ERROR },
167  |     { WGHT_FATAL,	NULL,	DEF_FACILITY_FATAL },
168  |     { WGHT_PANIC,	NULL,	DEF_FACILITY_PANIC }
169  | };
170  | 
171  | /**
172  |  **  Syslog facility names
173  |  **/
174  | 
175  | static	FacilityNames	facility_names[] = {
176  | #if defined(HAVE_SYSLOG) && defined(WITH_LOGGING)
177  |     { "auth", LOG_AUTH },
178  |     { "cron", LOG_CRON },
179  |     { "daemon", LOG_DAEMON },
180  |     { "kern", LOG_KERN },
181  |     { "local0", LOG_LOCAL0 },
182  |     { "local1", LOG_LOCAL1 },
183  |     { "local2", LOG_LOCAL2 },
184  |     { "local3", LOG_LOCAL3 },
185  |     { "local4", LOG_LOCAL4 },
186  |     { "local5", LOG_LOCAL5 },
187  |     { "local6", LOG_LOCAL6 },
188  |     { "local7", LOG_LOCAL7 },
189  |     { "lpr", LOG_LPR },
190  |     { "mail", LOG_MAIL },
191  |     { "news", LOG_NEWS },
192  |     { "user", LOG_USER },
193  |     { "uucp", LOG_UUCP }
194  | #else
195  |     { "none", 0 }
196  | #endif
197  | };
198  | 
199  | /**
200  |  **  Syslog level names
201  |  **/
202  | 
203  | static	FacilityNames	level_names[] = {
204  | #if defined(HAVE_SYSLOG) && defined(WITH_LOGGING)
205  |     { "alert", LOG_ALERT },
206  |     { "crit", LOG_CRIT },
207  |     { "debug", LOG_DEBUG },
208  |     { "emerg", LOG_EMERG },
209  |     { "err", LOG_ERR },
210  |     { "info", LOG_INFO },
211  |     { "notice", LOG_NOTICE },
212  |     { "warning", LOG_WARNING }
213  | #else
214  |     { "none", 0 }
215  | #endif
216  | };
217  | 
218  | /**
219  |  **  Error measurement table
220  |  **  Take care that this list is sorted in ascending order concerning the error
221  |  **  weights
222  |  **/
223  | 
224  | #define	MEAS_VERB_NDX	1	/** Index of the 'VERBOSE' entry	    **/
225  | 
226  | static	ErrMeasr	Measurements[] = {
227  |     { WGHT_NONE,   ""	  , OK,      OK,      OK },	
228  |     { WGHT_VERBOSE,"VERB" , OK,      OK,      OK },
229  |     { WGHT_INFO,   "INFO" , OK,      OK,      OK },
230  |     { WGHT_DEBUG,  "DEBUG", OK,      OK,      OK },
231  |     { WGHT_TRACE,  "TRACE", OK,      OK,      OK },
232  |     { WGHT_WARN,   "WARN" , PROBLEM, WARN,    OK },
233  |     { WGHT_PROB,   "PROB" , ERROR,   PROBLEM, OK },
234  |     { WGHT_ERROR,  "ERROR", ERROR,   ERROR,   ERROR },
235  |     { WGHT_FATAL,  "FATAL", FATAL,   FATAL,   FATAL },
236  |     { WGHT_PANIC,  "PANIC", PANIC,   PANIC,   PANIC },
237  | };
238  | 
239  | /**
240  |  **  Error code translation table
241  |  **  Take care that this list is sorted in ascending order concerning the error
242  |  **  types
243  |  **/
244  | 
245  | static	ErrTransTab	TransTab[] = {
246  |     { NO_ERR,		WGHT_NONE,  NULL },
247  |     { NO_ERR_DEBUG,	WGHT_DEBUG, "$*" },
248  |     { NO_ERR_START,	WGHT_DEBUG, "Starting $*" },
249  |     { NO_ERR_END,	WGHT_DEBUG, "Exit $*" },
250  |     { NO_ERR_VERBOSE,	WGHT_VERBOSE,  NULL },
251  |     { ERR_PARAM,	WGHT_ERROR, "Paramter error concerning '$1'" },
252  |     { ERR_USAGE,	WGHT_ERROR, "Usage is '$*'" },
253  |     { ERR_ARGSTOLONG,	WGHT_ERROR, "'$1': Arguments to long. Max. is '$2'" },
254  |     { ERR_OPT_AMBIG,	WGHT_ERROR, "Option '$1' is ambiguous" },
255  |     { ERR_OPT_NOARG,	WGHT_ERROR, "Option '$1' allows no argument" },
256  |     { ERR_OPT_REQARG,	WGHT_ERROR, "Option '$1' requires an argument" },
257  |     { ERR_OPT_UNKNOWN,	WGHT_ERROR, "Unrecognized option '$1'" },
258  |     { ERR_OPT_ILL,	WGHT_ERROR, "Illegal option '$1'" },
259  |     { ERR_OPT_INV,	WGHT_ERROR, "Invalid option '$1'" },
260  |     { ERR_USERLVL,	WGHT_ERROR, "Undefined userlevel '$1'" },
261  |     { ERR_GETOPT,	WGHT_FATAL, "getopt() failed" },
262  |     { ERR_OPEN,		WGHT_ERROR, "Cannot open file '$1' for '$2'" },
263  |     { ERR_POPEN,	WGHT_ERROR, "Cannot open pipe '$1' for '$2'" },
264  |     { ERR_OPENDIR,	WGHT_ERROR, "Cannot open directory '$1' for reading" },
265  |     { ERR_CLOSE,	WGHT_WARN,  "Cannot close file '$1'" },
266  |     { ERR_PCLOSE,	WGHT_WARN,  "Cannot close pipe '$1'" },
267  |     { ERR_CLOSEDIR,	WGHT_WARN,  "Cannot close directory '$1'" },
268  |     { ERR_READ,		WGHT_ERROR, "Error while reading file '$1'" },
269  |     { ERR_READDIR,	WGHT_ERROR, "Error while reading directory '$1'" },
270  |     { ERR_WRITE,	WGHT_ERROR, "Error while writing file '$1'" },
271  |     { ERR_SEEK,		WGHT_ERROR, "Seek error on file '$1'" },
272  |     { ERR_FLUSH,	WGHT_WARN,  "Flush error on file '$1'" },
273  |     { ERR_DUP,		WGHT_WARN,  "Cannot duplicate handle of file '$1'" },
274  |     { ERR_DIRNAME,	WGHT_ERROR, "Cannot build directory name" },
275  |     { ERR_NAMETOLONG,	WGHT_ERROR, "Requested directory name to long: "
276  | 				    "dir='$1',file='$2'" },
277  |     { ERR_DIRNOTFOUND,	WGHT_ERROR, "Directory '$1' not found" },
278  |     { ERR_FILEINDIR,	WGHT_ERROR, "File '$1' not found in directory '$2'" },
279  |     { ERR_NODIR,	WGHT_ERROR, "'$1' is not a directory" },
280  |     { ERR_UNLINK,	WGHT_WARN,  "Cannot unlink '$1'" },
281  |     { ERR_RENAME,	WGHT_PROB,  "Cannot rename '$1' to '$2'" },
282  |     { ERR_ALLOC,	WGHT_FATAL, "Out of memory." },
283  |     { ERR_SOURCE,	WGHT_WARN,  "Error sourcing file '$1'" },
284  |     { ERR_UNAME,	WGHT_FATAL, "'uname (2)' failed." },
285  |     { ERR_GETHOSTNAME,	WGHT_FATAL, "'gethostname (2)' failed." },
286  |     { ERR_GETDOMAINNAME,WGHT_FATAL, "'getdomainname (2)' failed." },
287  |     { ERR_STRING,	WGHT_FATAL, "string error" },
288  |     { ERR_DISPLAY,	WGHT_ERROR, "Cannot open display" },
289  |     { ERR_PARSE,	WGHT_ERROR, "Parse error" },
290  |     { ERR_EXEC,		WGHT_ERROR, "Tcl command execution failed: $1" },
291  |     { ERR_EXTRACT,	WGHT_ERROR, "Cannot extract X11 resources" },
292  |     { ERR_COMMAND,	WGHT_ERROR, "'$1' is an unrecognized subcommand" },
293  |     { ERR_LOCATE,	WGHT_ERROR, "Unable to locate a modulefile for '$1'" },
294  |     { ERR_MAGIC,	WGHT_ERROR, "Magic cookie '#%Module' missing in '$1'" },
295  |     { ERR_MODULE_PATH,	WGHT_ERROR, "'MODULEPATH' not set" },
296  |     { ERR_HOME,		WGHT_ERROR, "'HOME' not set" },
297  |     { ERR_SHELL,	WGHT_ERROR, "Unknown shell type '$1'" },
298  |     { ERR_DERELICT,	WGHT_ERROR, "Unknown shell derelict '$1'" },
299  |     { ERR_CONFLICT,	WGHT_ERROR, "Module '$1' conflicts with the currently "
300  | 				    "loaded module(s) '$2*'" },
301  |     { ERR_PREREQ,	WGHT_ERROR, "Module '$1' depends on one of the "
302  | 				    "module(s) '$2*'" },
303  |     { ERR_NOTLOADED,	WGHT_ERROR, "Module '$1' is currently not loaded" },
304  |     { ERR_DUP_SYMVERS,	WGHT_PROB,  "Duplicate version symbol '$1' found" },
305  |     { ERR_SYMLOOP,	WGHT_ERROR, "Version symbol '$1' loops" },
306  |     { ERR_BADMODNAM,	WGHT_PROB,  "Invalid modulename '$1' found" },
307  |     { ERR_DUP_ALIAS,	WGHT_WARN,  "Duplicate alias '$1' found" },
308  |     { ERR_CACHE_INVAL,	WGHT_ERROR, "Invalid cache version '$1' found" },
309  |     { ERR_CACHE_LOAD,	WGHT_WARN,  "Couldn't load the cache properly" },
310  |     { ERR_BEGINENV,	WGHT_WARN, "Invalid update subcommand - "
311  | #ifdef BEGINENV
312  | #  if BEGINENV == 99
313  | 	"No _MODULESBEGINENV_ file"
314  | #  else
315  | 	"No .modulesbeginenv file"
316  | #  endif
317  | #else
318  | 	".modulesbeginenv not supported"
319  | #endif
320  | 	},
321  |     { ERR_BEGINENVX,	WGHT_WARN,
322  | 	"Invalid update subcommand - No MODULESBEGINENV - hence not supported"},
323  |     { ERR_INIT_TCL,	WGHT_ERROR, "Cannot initialize TCL" },
324  |     { ERR_INIT_TCLX,	WGHT_WARN,  "Cannot initialize TCLX modules using "
325  | 				    "extended commands might fail" },
326  |     { ERR_INIT_ALPATH,	WGHT_WARN,  "Could not extend auto_path variable. "
327  | 				    "Module using autoloadable functions might "
328  | 				    "fail" },
329  |     { ERR_INIT_STUP,	WGHT_WARN,  "Cannot find a 'module load' command in "
330  | 				    "any of the '$1' startup files" },
331  |     { ERR_SET_VAR,	WGHT_WARN,  "Cannot set TCL variable '$1'" },
332  |     { ERR_INFO_DESCR,	WGHT_ERROR, "Unrecognized module info descriptor '$1'" },
333  |     { ERR_INVWGHT_WARN,	WGHT_WARN,  "Invalid error weight '$1' found" },
334  |     { ERR_INVFAC_WARN,	WGHT_WARN,  "Invalid log facility '$1'" },
335  |     { ERR_COLON,	WGHT_WARN,  "Spurious colon in pattern '$1'" },
336  |     { ERR_INTERAL,	WGHT_PANIC, "Internal error in the alias handler" },
337  |     { ERR_INTERRL,	WGHT_PANIC, "Internal error in the error logger" },
338  |     { ERR_INVAL,	WGHT_PANIC, "Invalid error type '$1' found" },
339  |     { ERR_INVWGHT,	WGHT_PANIC, "Invalid error weight '$1' found" },
340  |     { ERR_INVFAC,	WGHT_PANIC, "Invalid log facility '$1'" },
341  |     { ERR_ENVVAR,       WGHT_FATAL, "The environment variables LOADMODULES and _LMFILES_ have inconsistent lengths." }
342  | };
343  | 
344  | /** ************************************************************************ **/
345  | /**				    PROTOTYPES				     **/
346  | /** ************************************************************************ **/
347  | 
348  | static	ErrTransTab	*ErrorLookup(	ErrType error_type );
349  | 
350  | static	ErrMeasr	*MeasLookup(	ErrWeights weigth );
351  | 
352  | static	int	FlushError(	ErrType		  Type,
353  | 				char		 *module,
354  | 				int		  lineno,
355  | 				ErrWeights	  Weight,
356  | 				char		 *WeightMsg,
357  | 				char		 *ErrMsgs,
358  | 				int		  argc,
359  | 				char		**argv);
360  | 
361  | static	int	PrintError(	char		 *buffer,
362  | 				ErrType		  Type,
363  | 				char		 *module,
364  | 				int		  lineno,
365  | 				ErrWeights	  Weight,
366  | 				char		 *WeightMsg,
367  | 				char		 *ErrMsgs,
368  | 				int		  argc,
369  | 				char		**argv);
370  | 
371  | static	char	*ErrorString(	char		 *ErrMsgs,
372  | 				int		  argc,
373  | 				char		**argv);
374  | 
375  | static	void	add_param(	char		**Control,
376  | 				char		**Target,
377  | 				int		 *Length,
378  | 				int		  argc,
379  | 				char		**argv);
380  | 
381  | static	int	scan_facility(	char		 *s,
382  | 				FacilityNames	 *table,
383  | 				int		  size);
384  | 
385  | static	char	*GetFacility(	ErrWeights	  Weight);
386  | static	ErrFacilities	*GetFacility_sub( ErrWeights Weight);
387  | 
388  | static	void Print_Tracing(	char	 *buffer,
389  | 				int	  result,
390  | 			   	int	  argc,
391  | 			   	char	**argv);
392  | 
393  | /*++++
394  |  ** ** Function-Header ***************************************************** **
395  |  ** 									     **
396  |  **   Function:		Module_Tracing					     **
397  |  **			Print_Tracing					     **
398  |  **			Module_Verbosity				     **
399  |  ** 									     **
400  |  **   Description:	Display a tracing or verbose message		     **
401  |  ** 									     **
402  |  **   First Edition:	1995/12/27					     **
403  |  ** 									     **
404  |  **   Parameters:	int	result	Result code of th module command     **
405  |  **			int	argc	Number od arguments to the module    **
406  |  **					command				     **
407  |  **			char	**argv	Argument array			     **
408  |  **			char	*buffer	Print buffer			     **
409  |  ** 									     **
410  |  **   Result:		-						     **
411  |  ** 									     **
412  |  **   Attached Globals:	g_current_module	The module which is handled  **
413  |  **						by the current command	     **
414  |  ** 									     **
415  |  ** ************************************************************************ **
416  |  ++++*/
417  | 
418  | void Module_Tracing(	int	result,
419  | 		   	int	argc,
420  | 		   	char	**argv)
421  | {
422  |     if( !FlushError( NO_ERR, (char *) NULL, result, WGHT_TRACE, (char *) NULL,
423  | 	(char *) NULL, argc, argv)) {
424  | 	ErrorLogger( ERR_INTERRL, LOC, NULL);
425  |     }
426  | 
427  | } /** End of 'Module_Tracing' **/
428  | 
429  | void Module_Verbosity(	int	argc,
430  | 		   	char	**argv)
431  | {
432  |     if( sw_verbose && argc && *argv)
433  | 	if( !FlushError( NO_ERR_VERBOSE, g_current_module,linenum,WGHT_VERBOSE,
434  | 	    Measurements[ MEAS_VERB_NDX].message, *argv, argc, argv)) {
435  | 	    ErrorLogger( ERR_INTERRL, LOC, NULL);
436  | 	}
437  | 
438  | } /** End of 'Module_Verbosity' **/
439  | 
440  | static	void Print_Tracing(	char	 *buffer,
441  | 				int	  result,
442  | 			   	int	  argc,
443  | 			   	char	**argv)
444  | {
445  |     char 		*s = buffer;
446  |     struct passwd 	*pwent;
447  |     struct group 	*grpent;
448  |     uid_t 		 uid;
449  |     gid_t 		 gid;
450  | 
451  |     /**
452  |      **  Print the arguments
453  |      **/
454  | 
455  |     while( argc--) {
456  | 	/* sprintf( s, "%s ", *argv++); */
457  | 	strcpy( s, *argv++);
458  | 	strcat( s, " ");
459  | 	s += strlen( s);
460  |     }
461  | 
462  |     /**
463  |      **  Add the real and effective user- and group-id
464  |      **/
465  | 
466  |     pwent = getpwuid( uid = getuid());
467  |     sprintf( s, " [%s(%d)", (pwent ? pwent->pw_name : _unknown), uid);
468  |     s += strlen( s);
469  |     grpent = getgrgid( gid = getgid());
470  |     sprintf( s, ".%s(%d)]", (grpent ? grpent->gr_name : _unknown), gid);
471  |     s += strlen( s);
472  | 
473  |     pwent = getpwuid( uid = geteuid());
474  |     sprintf( s, " [%s(%d)", (pwent ? pwent->pw_name : _unknown), uid);
475  |     s += strlen( s);
476  |     grpent = getgrgid( gid = getegid());
477  |     sprintf( s, ".%s(%d)] = ", (grpent ? grpent->gr_name : _unknown), gid);
478  |     s += strlen( s);
479  | 
480  |     /**
481  |      **  Add the commands result
482  |      **/
483  | 
484  |     switch( result) {
485  | 	case TCL_OK:
486  | 	    strcpy( s, "TCL_OK");
487  | 	    break;
488  | 	case TCL_ERROR:
489  | 	    strcpy( s, "TCL_ERROR");
490  | 	    break;
491  | 	case TCL_RETURN:
492  | 	    strcpy( s, "TCL_RETURN");
493  | 	    break;
494  | 	case TCL_BREAK:
495  | 	    strcpy( s, "TCL_BREAK");
496  | 	    break;
497  | 	case TCL_CONTINUE:
498  | 	    strcpy( s, "TCL_CONTINUE");
499  | 	    break;
500  | 	default:
501  | 	    strcpy( s, "UNKNOWN");
502  | 	    break;
503  |     }
504  | 
505  |     s += strlen( s);
506  |     sprintf( s, "(%d)", result);
507  | 
508  | } /** End of 'Module_Tracing' **/
509  | 
510  | /*++++
511  |  ** ** Function-Header ***************************************************** **
512  |  ** 									     **
513  |  **   Function:		Enable_Error, Disable_Error, Restore_Error	     **
514  |  ** 									     **
515  |  **   Description:	Enables, disables, or restores error logging	     **
516  |  ** 			Sometimes an error isn't really an error	     **
517  |  ** 									     **
518  |  **   First Edition:	1999/11/11					     **
519  |  ** 									     **
520  |  **   Parameters:	none						     **
521  |  ** 									     **
522  |  **   Result:		none						     **
523  |  ** 									     **
524  |  ** ************************************************************************ **
525  |  ++++*/
526  | 
527  | static void save_error_state(int reset) {
528  | 	static int in_effect = 0;
529  | 	static int saved_state = 0;
530  | 
531  | 	if (reset && in_effect ) {
532  | 		quiet_on_error = saved_state;
533  | 		in_effect = 0;
534  | 	} else if (!reset && !in_effect ) {
535  | 		saved_state = quiet_on_error;
536  | 		in_effect = 1;
537  | 	}
538  | }
539  | 
540  | 
541  | void Enable_Error(void) {
542  | 	save_error_state(0);
543  | 	quiet_on_error = 0;
544  | }
545  | 
546  | void Disable_Error(void) {
547  | 	save_error_state(0);
548  | 	quiet_on_error = 1;
549  | }
550  | 
551  | void Restore_Error(void) {
552  | 	quiet_on_error = 0;	/* the default is to output errors */
553  | 	save_error_state(1);
554  | }
555  | 
556  | /*++++
557  |  ** ** Function-Header ***************************************************** **
558  |  ** 									     **
559  |  **   Function:		Module_Error					     **
560  |  ** 									     **
561  |  **   Description:	Error handling for the modules package		     **
562  |  ** 									     **
563  |  **   First Edition:	1995/08/06					     **
564  |  ** 									     **
565  |  **   Parameters:	ErrType		 error_type	Type of the error    **
566  |  **			char		*module		Affected module	     **
567  |  **			int		 lineo		Line number	     **
568  |  **			...				Argument list	     **
569  |  ** 									     **
570  |  **   Result:		ErrCode		OK		No error	     **
571  |  **					PROBLEM		Problem. Program may **
572  |  **							continue running     **
573  |  **					ERROR		Caller should try to **
574  |  **							exit gracefully      **
575  |  ** 									     **
576  |  **   Attached Globals:							     **
577  |  ** 									     **
578  |  ** ************************************************************************ **
579  |  ++++*/
580  | 
581  | int Module_Error(	ErrType		  error_type,
582  | 		   	char		 *module,
583  | 		   	int		  lineno,
584  | 		   	... )
585  | {
586  |     int		  listsize = ARGLIST_SIZE,	/** Initial size of the argu-**/
587  | 						/** ment list		     **/
588  | 		  argc = 0;			/** Actual number of args    **/
589  |     char	**argv,				/** Argument array	     **/
590  | 		 *arg;				/** A single argument	     **/
591  |     va_list	  parptr;			/** Varargs scan pointer     **/
592  |     ErrTransTab	 *TransPtr;			/** Error transtab entry     **/
593  |     ErrMeasr	 *MeasPtr;			/** Measurement pointer      **/
594  |     ErrCode	  ret_code;
595  |     int		  NoArgs = (error_type == ERR_ALLOC);
596  | 
597  |     if( quiet_on_error ) return OK;		/* do nothing - just OK */
598  | 
599  |     /**
600  |      **  Argument check
601  |      **/
602  |     if( NO_ERR_VERBOSE == error_type && !sw_verbose)
603  | 	return( OK);
604  | 
605  |     if( !module)
606  | 	module = unknown;
607  | 
608  |     /**
609  |      **  Build the argument array at first
610  |      **/
611  | 
612  |     if( NULL == (argv = (char **) malloc( listsize * sizeof( char *)))) {
613  | 	module = module_name;
614  | 	error_type = ERR_ALLOC;
615  | 	NoArgs = 1;
616  |     }
617  | 
618  |     va_start( parptr, lineno);
619  |     while( !NoArgs && (NULL != (arg = va_arg( parptr, char *)))) {
620  | 
621  | 	/**
622  | 	 **  Conditionally realloc
623  | 	 **/
624  | 	while( argc >= listsize) {
625  | 	    listsize += ARGLIST_SIZE;
626  | 	    if( NULL == (argv = (char **) realloc( argv,
627  | 		listsize * sizeof(char *)))) {
628  | 		module = module_name;
629  | 		error_type = ERR_ALLOC;
630  | 		NoArgs = 1;
631  | 		break;
632  | 	    }
633  | 	}
634  | 
635  | 	argv[ argc++] = arg;
636  | 
637  |     } /** while **/
638  |     
639  |     if( NO_ERR_VERBOSE == error_type && !argc)
640  | 	return( OK);
641  | 
642  |     /**
643  |      **  Locate the error translation table entry according to the 
644  |      **  passed error type
645  |      **/
646  |     if( NULL == (TransPtr = ErrorLookup( error_type))) {
647  | 	if( argv)
648  | 	    null_free((void *) &argv);
649  | 	return( ErrorLogger( ERR_INVAL, LOC, (sprintf( buffer, "%d",
650  | 	    error_type), buffer), NULL));
651  |     }
652  |     
653  |     /**
654  |      **  Now locate the assigned error weight ...
655  |      **/
656  | 
657  |     if( NULL == (MeasPtr = MeasLookup( TransPtr->error_weight))) {
658  | 	if( argv)
659  | 	    null_free((void *) &argv);
660  | 	argc = 0;
661  | 	return( ErrorLogger( ERR_INVWGHT, LOC, (sprintf( buffer, "%d",
662  | 	    TransPtr->error_weight), buffer), NULL));
663  |     }
664  | 
665  |     /**
666  |      **  Use the return code as defined for the current user level
667  |      **/
668  |     switch( sw_userlvl) {
669  | 	case UL_NOVICE:
670  | 	    ret_code = MeasPtr->ret_nov;
671  | 	    break;
672  | 	case UL_ADVANCED:
673  | 	    ret_code = MeasPtr->ret_adv;
674  | 	    break;
675  | 	case UL_EXPERT:
676  | 	    ret_code = MeasPtr->ret_exp;
677  | 	    break;
678  |     }
679  | 
680  |     /**
681  |      **  Print the error message
682  |      **/
683  |     if( TransPtr->error_weight <= WGHT_TRACE || ret_code != OK)
684  | 	if( !FlushError( error_type, module, lineno, TransPtr->error_weight,
685  | 	    MeasPtr->message, TransPtr->messages, argc, argv)) {
686  | 	    if( argv)
687  | 		null_free((void *) &argv);
688  | 	    argc = 0;
689  | 	    return( ErrorLogger( ERR_INTERRL, LOC, NULL));
690  | 	}
691  | 
692  |     /**
693  |      **  Return to the caller ... conditionally ...
694  |      **/
695  |     if( WARN == ret_code)
696  | 	ret_code = OK;
697  | 
698  |     if( argv)
699  | 	null_free((void *) &argv);
700  |     argc = 0;
701  | 
702  |     if( ret_code > ERROR)
703  | 	exit( ret_code);
704  | 
705  |     return( ret_code);
706  | } /** End of 'Module_Error' **/
707  | 
708  | /*++++
709  |  ** ** Function-Header ***************************************************** **
710  |  ** 									     **
711  |  **   Function:		ErrorLookup					     **
712  |  ** 									     **
713  |  **   Description:	Look up the passed error type in the translation tab.**
714  |  ** 									     **
715  |  **   First Edition:	1995/08/06					     **
716  |  ** 									     **
717  |  **   Parameters:	ErrType		 error_type	Type of the error    **
718  |  ** 									     **
719  |  **   Result:		ErrTransTab*	NULL	Not found		     **
720  |  **					else	Pointer to the acc. entry    **
721  |  ** 									     **
722  |  **   Attached Globals:							     **
723  |  ** 									     **
724  |  ** ************************************************************************ **
725  |  ++++*/
726  | 
727  | static	ErrTransTab	*ErrorLookup(	ErrType error_type )
728  | {
729  |     ErrTransTab	*low, *mid, *high, *save;	/** Search pointers	     **/
730  | 
731  |     /**
732  |      **  Init serach pointers
733  |      **/
734  | 
735  |     low = TransTab;
736  |     high = TransTab + (sizeof( TransTab) / sizeof( TransTab[0]) -1);
737  |     mid = (ErrTransTab *) NULL;
738  | 
739  |     /**
740  |      **  Search loop
741  |      **/
742  | 
743  |     while( low < high) {
744  | 
745  | 	save = mid;
746  | 	mid = low + ((high - low) / 2);
747  | 	if( save == mid)
748  | 	    low = mid = high;			/** Just for safety ...	     **/
749  | 
750  | 	if( mid->error_type < error_type ) {
751  | 	    low = mid;
752  | 	} else if( mid->error_type > error_type ) {
753  | 	    high = mid;
754  | 	} else
755  | 	    return( mid);		/** Yep! Got it!		     **/
756  | 
757  |     } /** while **/
758  | 
759  |     /**
760  |      **  Maybe the loop has been finished before the comparison took place
761  |      **  (low == high) and hit!
762  |      **/
763  | 
764  |     if( mid->error_type == error_type )
765  | 	return( mid);               	/** Yep! Got it!                     **/
766  | 
767  |     /**
768  |      **  If this point is reached, nothing has been found ...
769  |      **/
770  | 
771  |     return( NULL);
772  | 
773  | } /** End of 'ErrorLookup' **/
774  | 
775  | /*++++
776  |  ** ** Function-Header ***************************************************** **
777  |  ** 									     **
778  |  **   Function:		MeasLookup					     **
779  |  ** 									     **
780  |  **   Description:	Look up the passed error weight in the measurement   **
781  |  **			table						     **
782  |  ** 									     **
783  |  **   First Edition:	1995/08/06					     **
784  |  ** 									     **
785  |  **   Parameters:	ErrWeights	weigth	Weight of the error	     **
786  |  ** 									     **
787  |  **   Result:		ErrMeasr*	NULL	Not found		     **
788  |  **					else	Pointer to the acc. entry    **
789  |  ** 									     **
790  |  **   Attached Globals:							     **
791  |  ** 									     **
792  |  ** ************************************************************************ **
793  |  ++++*/
794  | 
795  | static	ErrMeasr	*MeasLookup(	ErrWeights weigth )
796  | {
797  |     ErrMeasr	*low, *mid, *high, *save;	/** Search pointers	     **/
798  | 
799  |     /**
800  |      **  Init serach pointers
801  |      **/
802  | 
803  |     low = Measurements;
804  |     high = Measurements + (sizeof( Measurements) / sizeof( Measurements[0]) -1);
805  |     save = (ErrMeasr *) NULL;
806  |     mid = (ErrMeasr *) NULL;
807  | 
808  |     /**
809  |      **  Search loop
810  |      **/
811  | 
812  |     while( low < high) {
813  | 
814  | 	save = mid;
815  | 	mid = low + ((high - low) / 2);
816  | 	if( save == mid)
817  | 	    low = mid = high;			/** Just to be sure ...      **/
818  | 
819  | 	if( mid->error_weight < weigth ) {
820  | 	    low = mid;
821  | 	} else if( mid->error_weight > weigth ) {
822  | 	    high = mid;
823  | 	} else
824  | 	    return( mid);		/** Yep! Got it!		     **/
825  | 
826  |     } /** while **/
827  | 
828  |     /**
829  |      **  Maybe the loop has been finished before the comparison took place
830  |      **  (low == high) and hit!
831  |      **/
832  | 
833  |     if( mid->error_weight == weigth )
834  | 	return( mid);               	/** Yep! Got it!                     **/
835  | 
836  |     /**
837  |      **  If this point is reached, nothing has been found ...
838  |      **/
839  | 
840  |     return( NULL);
841  | 
842  | } /** End of 'MeasLookup' **/
843  | 
844  | /*++++
845  |  ** ** Function-Header ***************************************************** **
846  |  ** 									     **
847  |  **   Function:		FlushError					     **
848  |  ** 									     **
849  |  **   Description:	Print the error message. Decide which facility to    **
850  |  **			use and schedule the according logger routine	     **
851  |  ** 									     **
852  |  **   First Edition:	1995/12/21					     **
853  |  ** 									     **
854  |  **   Parameters:	ErrType		  Type		Error type as passed **
855  |  **			char		 *module	Module name	     **
856  |  **			int		  lineno	Line number	     **
857  |  **		  	ErrWeights	  Weight	Error Weight	     **
858  |  **			char		 *WeightMsg	Printable Weight     **
859  |  **			char		 *ErrMsgs	Error message	     **
860  |  **			int		  argc		Number of arguments  **
861  |  **			char		**argv		Argument array	     **
862  |  ** 									     **
863  |  **   Result:		int	1		Everything OK		     **
864  |  **				0		Error occured while printing **
865  |  ** 									     **
866  |  ** ************************************************************************ **
867  |  ++++*/
868  | 
869  | static	int	FlushError(	ErrType		  Type,
870  | 				char		 *module,
871  | 				int		  lineno,
872  | 				ErrWeights	  Weight,
873  | 				char		 *WeightMsg,
874  | 				char		 *ErrMsgs,
875  | 				int		  argc,
876  | 				char		**argv)
877  | {
878  |     char	*facilities, *buffer;
879  |     char 	*fac;
880  |     FILE	*facfp;
881  |     char	*errmsg_buffer;
882  |     int		 fac_alloc = 0;
883  | 
884  |     /**
885  |      **  get the error facilities at first. If there isn't any, we may
886  |      **  return on success immediatelly.
887  |      **/
888  |     if((char *) NULL == (facilities = GetFacility( Weight)))
889  | 	goto success0;
890  | 
891  |     /**
892  |      **  PANIC and FATAL error messages ought to be on stderr at least!
893  |      **/
894  |     if( WGHT_FATAL == Weight || WGHT_PANIC == Weight)
895  | 	if( !strstr( facilities, _stderr)) {
896  | 
897  | 	    if((char *) NULL == (buffer = stringer(NULL,0,
898  | 		    _stderr,":", facilities, NULL))) {
899  | 		ErrorLogger( ERR_STRING, LOC, NULL);
900  | 		goto unwind0;
901  | 	    }
902  | 
903  | 	    facilities = buffer;
904  | 	    fac_alloc = 1;
905  | 	}
906  | 
907  |     /**
908  |      **  Print the error message into the buffer
909  |      **/
910  |     if((char *) NULL == (errmsg_buffer = stringer(NULL, ERR_BUFSIZE, NULL))) {
911  | 	ErrorLogger( ERR_ALLOC, LOC, NULL);
912  | 	goto unwind1;
913  |     }
914  | 
915  |     /**
916  |      **  In case of verbosity, the first argument is the ErrMsgs format string
917  |      **/
918  |     if( WGHT_VERBOSE == Weight) {
919  | 	ErrMsgs = *argv++;
920  | 	--argc;
921  |     }
922  | 
923  |     if( WGHT_TRACE == Weight)
924  | 	Print_Tracing( errmsg_buffer, lineno, argc, argv);
925  |     else if( !PrintError( errmsg_buffer, Type, module, lineno, Weight,
926  | 	WeightMsg, ErrMsgs, argc, argv))
927  | 	    goto unwind2;
928  | 
929  |     /**
930  |      **  Now tokenize the facilities string and schedule the error messge
931  |      **  for every single facility
932  |      **/
933  |     for( fac = strtok( facilities, ":");
934  | 	 fac;
935  | 	 fac = strtok( (char *) NULL, ":") ) {
936  | 
937  | 	/**
938  | 	 **  Check for filenames. Two specials are defined: stderr and stdout
939  | 	 **  Otherwise filenames are expected to begin on '.' or '/'.
940  | 	 **  Everthing not recognized as a filename is assumed to be a
941  | 	 **  syslog facility
942  | 	 **  'null' and 'none' are known as 'no logging'
943  | 	 **/
944  | 	if( !strcmp( fac, _null) || !strcmp( fac, _none))
945  | 	    continue;
946  | 
947  | 	else if( !strcmp( fac, _stderr))
948  | 	    fprintf( stderr, "%s", errmsg_buffer);
949  | 	
950  | 	else if( !strcmp( fac, _stdout)) 
951  | 	    fprintf( stdout, "%s", errmsg_buffer);
952  | 
953  | 	/**
954  | 	 **  Syslog
955  | 	 **/
956  | 	else if( '.' != *fac && '/' != *fac) {
957  | #if defined(HAVE_SYSLOG) && defined(WITH_LOGGING)
958  | 	    int syslog_fac, syslog_lvl;
959  | 
960  | 	    if( CheckFacility( fac, &syslog_fac, &syslog_lvl)) {
961  | 		openlog( "modulecmd", LOG_PID, syslog_fac);
962  | 		setlogmask( LOG_UPTO( syslog_lvl));
963  | 		syslog( (syslog_fac | syslog_lvl), "%s", errmsg_buffer);
964  | 		closelog();
965  | 
966  | 	    /**
967  | 	     **  Invalid facilities ... take care not to end up in 
968  | 	     **  infinite loops
969  | 	     **/
970  | 	    } else if( Type == ERR_INVFAC ||
971  | 	               OK == ErrorLogger( ERR_INVFAC, LOC, fac, NULL)) 
972  | 		continue;
973  | 
974  | #else
975  | #  ifdef	SYSLOG_DIR
976  | 	    /* this is an intential memory leak */
977  | 	    buffer = stringer(NULL,0, SYSLOG_DIR, "/", fac);
978  | 	    fac = buffer;
979  | #  endif
980  | #endif
981  | 	}
982  | 
983  | 	/**
984  | 	 **  Custom files ...
985  | 	 **  This may result from the syslog part above
986  | 	 **/
987  | 	if( '.' == *fac || '/' == *fac) {
988  | 	    if((FILE *) NULL == (facfp = fopen( fac, "a"))) {
989  | 
990  | 		if( WGHT_PANIC == Weight)	/** Avoid endless loops!     **/
991  | 		    goto unwind2;
992  | 
993  | 		/**
994  | 		 **  Invalid facilities ... take care not to end up in 
995  | 		 **  infinite loops
996  | 		 **/
997  | 		if( Type == ERR_INVFAC ||
998  | 		    OK == ErrorLogger( ERR_INVFAC, LOC, fac, NULL))
999  | 		    continue;
1000 | 		else
1001 | 		    goto unwind2;
1002 | 	    }
1003 | 
1004 | 	    fprintf( facfp, "%s", errmsg_buffer);
1005 | 
1006 | 	    if( EOF == fclose( facfp))
1007 | 		if( OK != ErrorLogger( ERR_CLOSE, LOC, fac, NULL))
1008 | 		    goto unwind2;
1009 | 
1010 | 	}
1011 |     } /** for **/
1012 | 
1013 |     /**
1014 |      **  Return on success
1015 |      **/
1016 |     null_free((void *) &errmsg_buffer);
1017 |     if( fac_alloc)
1018 | 	null_free((void *) &facilities);
1019 | success0:
1020 |     return( 1);				/** -------- EXIT (SUCCESS) -------> **/
1021 | 
1022 | unwind2:
1023 |     null_free((void *) &errmsg_buffer);
1024 | unwind1:
1025 |     if( fac_alloc)
1026 | 	null_free((void *) &facilities);
1027 | unwind0:
1028 |     return( 0);				/** -------- EXIT (FAILURE) -------> **/
1029 | 
1030 | } /** End of 'FlushError' **/
1031 | 
1032 | /*++++
1033 |  ** ** Function-Header ***************************************************** **
1034 |  ** 									     **
1035 |  **   Function:		GetFacility					     **
1036 |  ** 									     **
1037 |  **   Description:	Get the log facility according to the passed error   **
1038 |  **			weight						     **
1039 |  ** 									     **
1040 |  **   First Edition:	1995/12/21					     **
1041 |  ** 									     **
1042 |  **   Parameters:	ErrWeights	  Weight	Error Weight	     **
1043 |  ** 									     **
1044 |  **   Result:		char*	NULL		No facility found	     **
1045 |  **				Otherwise	Pointer to the colon separa- **
1046 |  **						ted facility string	     **
1047 |  ** 									     **
1048 |  ** ************************************************************************ **
1049 |  ++++*/
1050 | 
1051 | static	char	*GetFacility(	ErrWeights	  Weight)
1052 | {
1053 |     ErrFacilities	*facility;
1054 | 
1055 |     /**
1056 |      **  Get the facility table entry at first
1057 |      **/
1058 |     if( !(facility = GetFacility_sub( Weight)))
1059 | 	return((char *) NULL);
1060 | 
1061 |     /**
1062 |      **  Now we've got two possibilities:
1063 |      **      First of all there may be a custom facilitiy defined
1064 |      **	     Otherwise the default facility is to be returned now
1065 |      **/
1066 |     return( facility->facility ? facility->facility : facility->def_facility);
1067 | 
1068 | } /** End of 'GetFacility' **/
1069 | 
1070 | static	ErrFacilities	*GetFacility_sub(	ErrWeights	  Weight)
1071 | {
1072 |     ErrFacilities	*low, *mid, *high, *save;
1073 |     char		buffer[ 20];
1074 | 
1075 |     /**
1076 |      **  Binary search for the passed facility in the Facilities table.
1077 |      **  This requires the table to be sorted on ascending error weight
1078 |      **/
1079 |     low = Facilities;
1080 |     high = Facilities + (sizeof( Facilities) / sizeof( Facilities[0]));
1081 |     save = (ErrFacilities *) NULL;
1082 |     mid = (ErrFacilities *) NULL;
1083 | 
1084 |     while( low < high) {
1085 | 	save = mid;
1086 | 	mid = low + ((high - low) / 2);
1087 | 	if( save == mid)
1088 | 	    low = mid = high;			/** Just to be sure ...	     **/
1089 | 
1090 | 	if( mid->Weight > Weight) 
1091 | 	    high = mid;
1092 | 	else if( mid->Weight < Weight)
1093 | 	    low = mid;
1094 | 	else
1095 | 	    break;	/** found! **/
1096 |     }
1097 | 
1098 |     /**
1099 |      **  We have to check, if we've found something or if there's an internal
1100 |      **  error (wrong weight)
1101 |      **/
1102 |     if( mid->Weight != Weight) {
1103 | 	if( OK == ErrorLogger( ERR_INVWGHT, LOC, (sprintf( buffer, "%d",
1104 | 	    Weight), buffer), NULL))
1105 | 	    return( NULL);
1106 |     }
1107 | 
1108 |     return( mid);
1109 | 
1110 | } /** End of 'GetFacility_sub' **/
1111 | 
1112 | /*++++
1113 |  ** ** Function-Header ***************************************************** **
1114 |  ** 									     **
1115 |  **   Function:		CheckFacility					     **
1116 |  ** 									     **
1117 |  **   Description:	Check the passwd string to be a valid combination    **
1118 |  **			of       <syslog_facility>.<syslog_level>	     **
1119 |  ** 									     **
1120 |  **   First Edition:	1995/12/21					     **
1121 |  ** 									     **
1122 |  **   Parameters:	char	*string		Input facility string	     **
1123 |  **			int	*facility	Buffer for the real facility **
1124 |  **			int	*level		Buffer for the real level    **
1125 |  ** 									     **
1126 |  **   Result:		int	1		Success			     **
1127 |  **				0		Failure. String not valid    **
1128 |  ** 									     **
1129 |  ** ************************************************************************ **
1130 |  ++++*/
1131 | 
1132 | int	CheckFacility(	char *string, int *facility, int *level)
1133 | {
1134 |     char *s, *buf;
1135 |     int x;
1136 | 
1137 |     /**
1138 |      **  We do not want to change the strings ... so allocate a buffer here
1139 |      **/
1140 |     if((char *) NULL == (buf = stringer(NULL,0, string,NULL)))
1141 | 	if( OK == ErrorLogger( ERR_STRING, LOC, NULL))
1142 | 	    goto unwind0;
1143 | 
1144 |     /** 
1145 |      **  We cannot use strtok here, because there's one initialized in an
1146 |      **  outter loop!
1147 |      **/
1148 |     for( s=buf; s && *s && *s != '.'; s++);
1149 |     if( !s || !*s)
1150 | 	goto unwind1;
1151 |     *s = '\0';
1152 | 	
1153 |     /**
1154 |      **  This should be the facility
1155 |      **/
1156 |     if( -1 == (x = scan_facility( buf, facility_names,
1157 | 	    (sizeof( facility_names) / sizeof( facility_names[0])) )))
1158 | 	goto unwind1;
1159 |     *facility = x;
1160 | 
1161 |     /**
1162 |      **  This should be the level
1163 |      **/
1164 |     if( -1 == (x = scan_facility( ++s, level_names, 
1165 | 	    (sizeof( level_names) / sizeof( level_names[0])) )))
1166 | 	goto unwind1;
1167 |     *level = x;
1168 | 
1169 |     /**
1170 |      **  Success
1171 |      **/
1172 |     null_free((void *) &buf);
1173 |     return( 1);				/** -------- EXIT (SUCCESS) -------> **/
1174 | 
1175 | unwind1:
1176 |     null_free((void *) &buf);
1177 | unwind0:
1178 |     return( 0);				/** -------- EXIT (FAILURE) -------> **/
1179 | 
1180 | } /** End of 'CheckFacility' **/
1181 | 
1182 | /*++++
1183 |  ** ** Function-Header ***************************************************** **
1184 |  ** 									     **
1185 |  **   Function:		scan_facility					     **
1186 |  ** 									     **
1187 |  **   Description:	Scan the passed facility names table for the given   **
1188 |  **			string and pass back the assigned token		     **
1189 |  ** 									     **
1190 |  **   First Edition:	1995/12/21					     **
1191 |  ** 									     **
1192 |  **   Parameters:	char		*s	String to be checked	     **
1193 |  **			FacilityNames	*table	Table of valid names and     **
1194 |  **						tokens			     **
1195 |  **			int		 size	Size of the table	     **
1196 |  ** 									     **
1197 |  **   Result:		int	-1		name not found in the table  **
1198 |  **				Otherwise	Assigned token		     **
1199 |  ** 									     **
1200 |  ** ************************************************************************ **
1201 |  ++++*/
1202 | 
1203 | static	int	scan_facility( char *s, FacilityNames *table, int size)
1204 | {
1205 |     FacilityNames *low, *mid, *high, *save;
1206 | 
1207 |     low = table;
1208 |     high = table + size;
1209 |     save = (FacilityNames *) NULL;
1210 | 
1211 |     while( low < high) {
1212 | 	int x;			/** Have to use this, because strcmp will    **/
1213 | 				/** not return -1 and 1 on Solaris 2.x	     **/
1214 | 	save = mid;
1215 | 	mid = low + ((high - low) / 2);
1216 | 	if( save == mid)
1217 | 	    low = mid = high;			/** To prevent endless loops **/
1218 | 
1219 | 	if (mid == high)
1220 | 		return -1;
1221 | 	x = strcmp( mid->name, s);
1222 | 
1223 | 	if( x < 0 )
1224 | 	    low = mid;
1225 | 	else if( x > 0)
1226 | 	    high = mid;
1227 | 	else
1228 | 	    return( mid->token);
1229 | 
1230 |     } /** while **/
1231 | 
1232 |     return( !strcmp( mid->name, s) ? mid->token : -1 );
1233 | 
1234 | } /** End of 'scan_facility' **/
1235 | 
1236 | /*++++
1237 |  ** ** Function-Header ***************************************************** **
1238 |  ** 									     **
1239 |  **   Function:		GetFacilityPtr					     **
1240 |  ** 									     **
1241 |  **   Description:	Scan the passed facility names table for the given   **
1242 |  **			string and pass back the assigned token		     **
1243 |  ** 									     **
1244 |  **   First Edition:	1995/12/21					     **
1245 |  ** 									     **
1246 |  **   Parameters:	char	*facility	Name of the facility	     **
1247 |  ** 									     **
1248 |  **   Result:		char**	NULL		Invalid facility name	     **
1249 |  **				Otherwise	Pointer to the facilty string**
1250 |  **						reference		     **
1251 |  ** 									     **
1252 |  ** ************************************************************************ **
1253 |  ++++*/
1254 | 
1255 | char	**GetFacilityPtr( char *facility)
1256 | {
1257 |     int		 	 i, len;
1258 |     ErrMeasr		*measptr;
1259 |     char		*buf, *s, *t;
1260 |     ErrFacilities	*facptr;
1261 | 
1262 |     /**
1263 |      **  Try to figure out the error weight at first
1264 |      **  Need the given weight in upper case for this
1265 |      **/
1266 |     len = strlen( facility);
1267 | 
1268 |     if((char *) NULL == (buf = stringer(NULL, 0, facility, NULL)))
1269 | 	if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
1270 | 	    goto unwind0;
1271 | 
1272 |     for( t = buf; *t; ++t) *t = toupper(*t);
1273 |     
1274 |     /**
1275 |      **  Now look up the measurements table for the uppercase weight
1276 |      **/
1277 |     i = sizeof( Measurements) / sizeof( Measurements[ 0]);
1278 |     measptr = Measurements;
1279 | 
1280 |     while( i) {
1281 | 	if( !strncmp( measptr->message, buf, len))
1282 | 	    break;
1283 | 	i--; measptr++;
1284 |     }
1285 | 
1286 |     null_free((void *) &buf);
1287 | 
1288 |     if( !i) 					/** not found		     **/
1289 | 	goto unwind0;
1290 |     
1291 |     /**
1292 |      **  Now get the facility table entry
1293 |      **/
1294 | 
1295 |     if((ErrFacilities *) NULL == (facptr = GetFacility_sub(
1296 | 	measptr->error_weight))) {
1297 | 	ErrorLogger( ERR_INVWGHT_WARN, LOC, facility, NULL); 
1298 | 	goto unwind0;
1299 |     }
1300 | 
1301 |     /**
1302 |      **  Got it ... return the desired pointer
1303 |      **/
1304 |     return( &facptr->facility);		/** -------- EXIT (RESULT)  -------> **/
1305 | 
1306 | unwind0:
1307 |     return((char **) NULL);		/** -------- EXIT (FAILURE) -------> **/
1308 | 
1309 | } /** End of 'GetFacilityPtr' **/
1310 | 
1311 | /*++++
1312 |  ** ** Function-Header ***************************************************** **
1313 |  ** 									     **
1314 |  **   Function:		PrintError					     **
1315 |  ** 									     **
1316 |  **   Description:	Print the error message				     **
1317 |  ** 									     **
1318 |  **   First Edition:	1995/08/06					     **
1319 |  ** 									     **
1320 |  **   Parameters:	char             *errbuffer	Buffer to hold the   **
1321 |  **							error messge	     **
1322 |  **			ErrType		  Type		Error type as passed **
1323 |  **			char		 *module	Module name	     **
1324 |  **			int		  lineno	Line number	     **
1325 |  **		  	ErrWeights	  Weight	Error Weight	     **
1326 |  **			char		 *WeightMsg	Printable Weight     **
1327 |  **			char		 *ErrMsgs	Error message	     **
1328 |  **			int		  argc		Number of arguments  **
1329 |  **			char		**argv		Argument array	     **
1330 |  ** 									     **
1331 |  **   Result:		int	1		Everything OK		     **
1332 |  **				0		Error occured while printing **
1333 |  ** 									     **
1334 |  **   Notes:	According to the error type, the passed module and line num- **
1335 |  **		ber will be handled as a module-file related one or depending**
1336 |  **		on the packages source code:				     **
1337 |  **									     **
1338 |  **		src -> ERR_IN_MODULEFILE -> modulefile -> ERR_INTERNAL -> src**
1339 |  ** 									     **
1340 |  ** ************************************************************************ **
1341 |  ++++*/
1342 | 
1343 | static	int	PrintError(	char 		 *errbuffer,
1344 | 				ErrType		  Type,
1345 | 				char		 *module,
1346 | 				int		  lineno,
1347 | 				ErrWeights	  Weight,
1348 | 				char		 *WeightMsg,
1349 | 				char		 *ErrMsgs,
1350 | 				int		  argc,
1351 | 				char		**argv)
1352 | {
1353 |     char	*error_string;
1354 | 
1355 |     /**
1356 |      **  Build the error string at first. Note - we cannot alloc memory any
1357 |      **  more!
1358 |      **/
1359 |     if( ERR_ALLOC == Type) 
1360 | 	error_string = ErrMsgs;
1361 |     else
1362 | 	if( NULL == (error_string = ErrorString( ErrMsgs, argc, argv)))
1363 | 	    return( 0);
1364 | 
1365 |     /**
1366 |      **  Print
1367 |      **/
1368 | 
1369 |     if( ERR_INTERNAL > Type && ERR_IN_MODULEFILE < Type &&
1370 | 	linenum && g_current_module )
1371 | 
1372 | 	sprintf( errbuffer, "%s(%s):%s:%d: %s\n", g_current_module,
1373 | 	    (sprintf( buffer, "%d", linenum), buffer),
1374 | 	    WeightMsg, Type, (error_string ? error_string : "") );
1375 |     else
1376 | 
1377 | 	sprintf( errbuffer, "%s(%s):%s:%d: %s\n", (module ? module : "??"),
1378 | 	    ( lineno ? (sprintf( buffer, "%d", lineno), buffer) : "??" ),
1379 | 	    WeightMsg, Type, (error_string ? error_string : "") );
1380 | 
1381 |     /**
1382 |      **  Success
1383 |      **/
1384 |     return( 1);
1385 | 
1386 | } /** End of 'PrintError' **/
1387 | 
1388 | /*++++
1389 |  ** ** Function-Header ***************************************************** **
1390 |  ** 									     **
1391 |  **   Function:		ErrorString					     **
1392 |  ** 									     **
1393 |  **   Description:	Print the error message				     **
1394 |  ** 									     **
1395 |  **   First Edition:	1995/08/06					     **
1396 |  ** 									     **
1397 |  **   Parameters:	char		 *ErrMsgs	Error message	     **
1398 |  **			int		  argc		Number of arguments  **
1399 |  **			char		**argv		Argument array	     **
1400 |  ** 									     **
1401 |  **   Result:		char*	NULL		Parse or alloc error	     **
1402 |  **				else		Pointer to the error string  **
1403 |  ** 									     **
1404 |  **   Attached Globals:	-						     **
1405 |  **									     **
1406 |  ** ************************************************************************ **
1407 |  ++++*/
1408 | 
1409 | static	char	*ErrorString(	char		 *ErrMsgs,
1410 | 				int		  argc,
1411 | 				char		**argv)
1412 | {
1413 |     char	*s;			/** Insertion pointer		     **/
1414 |     int		len = 0;		/** Current length		     **/
1415 |     int		backslash = 0;		/** backslash found ?		     **/
1416 | 
1417 |     if( !ErrMsgs)
1418 | 	return( NULL);
1419 | 
1420 |     /**
1421 |      **  Allocate memory if neccessary
1422 |      **/
1423 |     if( !error_line)
1424 | 	if((char *) NULL ==(error_line = stringer(NULL,strsize = ERR_LINELEN,
1425 | 		NULL))){
1426 | 	    ErrorLogger( ERR_STRING, LOC, NULL);
1427 | 	    return( NULL);
1428 | 	}
1429 | 
1430 |     s = error_line;
1431 | 
1432 |     /**
1433 |      **  Scan the error strings to be printed
1434 |      **/
1435 |     while( *ErrMsgs) {
1436 | 
1437 | 	/**
1438 | 	 **  Check for special characters
1439 | 	 **/
1440 | 	switch( *ErrMsgs) {
1441 | 	    case '\\':	if( !backslash) {
1442 | 				backslash = 1;
1443 | 				ErrMsgs++;
1444 | 				continue;	/** while( *ErrMsgs) **/
1445 | 			    }
1446 | 			    break;	/** switch **/
1447 | 
1448 | 	    case '$':	if( !backslash) {
1449 | 				ErrMsgs++;
1450 | 				add_param( &ErrMsgs, &s, &len, argc, argv);
1451 | 				error_line = s - len;
1452 | 				continue;	/** while( *ErrMsgs) **/
1453 | 			    }
1454 | 			    break;	/** switch **/
1455 | 	} /** switch **/
1456 | 
1457 | 	/**
1458 | 	 **  Add a single character to the error string
1459 | 	 **/
1460 | 	if( ++len >= strsize - 5) {	/** 5 Bytes for safety		     **/
1461 | 	    if( NULL == (error_line = (char *) realloc( error_line,
1462 | 		strsize += ERR_LINELEN))) {
1463 | 		ErrorLogger( ERR_ALLOC, LOC, NULL);
1464 | 		return( NULL);
1465 | 	    }
1466 | 	    s = error_line + len - 1;
1467 | 	}
1468 | 
1469 | 	*s++ = *ErrMsgs++;
1470 | 	backslash = 0;
1471 | 				
1472 |     } /** while( *ErrMsgs) **/
1473 | 
1474 |     /**
1475 |      **  Success. Return a pointer to the newly created string
1476 |      **/
1477 |     *s++ = '\0';
1478 |     return( error_line);
1479 | 
1480 | } /** End of 'ErrorString' **/
1481 | 
1482 | /*++++
1483 |  ** ** Function-Header ***************************************************** **
1484 |  ** 									     **
1485 |  **   Function:		add_param					     **
1486 |  ** 									     **
1487 |  **   Description:	Put an argument to the error string		     **
1488 |  ** 									     **
1489 |  **   First Edition:	1995/08/06					     **
1490 |  ** 									     **
1491 |  **   Parameters:	char		**Control	Parameter control    **
1492 |  **			char		**Target	Target to print to   **
1493 |  **			int		 *Length	Current length of the**
1494 |  **							output string	     **
1495 |  **			int		  argc		Number of arguments  **
1496 |  **			char		**argv		Argument array	     **
1497 |  ** 									     **
1498 |  **   Result:		-						     **
1499 |  ** 									     **
1500 |  **   Attached Globals:	-						     **
1501 |  **									     **
1502 |  ** ************************************************************************ **
1503 |  ++++*/
1504 | 
1505 | static	void	add_param(	char		**Control,
1506 | 				char		**Target,
1507 | 				int		 *Length,
1508 | 				int		  argc,
1509 | 				char		**argv)
1510 | {
1511 |     char	*s;			/** Scan pointer fot the ctrl field  **/
1512 |     int		index, last = 0;	/** parameter index		     **/
1513 |     int		len = 0;		/** Parameter string length	     **/
1514 | 
1515 |     /**
1516 |      **  Copy the current control field into the buffer
1517 |      **/
1518 | 
1519 |     for( s = buffer; **Control; (*Control)++ ) {
1520 | 
1521 | 	if( **Control == '*') {
1522 | 	    last = argc;
1523 | 	    continue;
1524 | 	} else if( **Control < '0' || **Control > '9')
1525 | 	    break;
1526 | 
1527 | 	*s++ = **Control;
1528 |     }
1529 | 
1530 |     *s = '\0';
1531 | 
1532 |     /**
1533 |      **  Has something been found ? If not, print a '$'
1534 |      **/
1535 |     if( s == buffer && !last) {
1536 | 
1537 | 	if( ++(*Length) >= strsize) {
1538 | 	    if( NULL == (error_line = (char*) realloc( error_line,
1539 | 		strsize += ERR_LINELEN))) {
1540 | 		ErrorLogger( ERR_ALLOC, LOC, NULL);
1541 | 		return;
1542 | 	    }
1543 | 	    *Target = error_line + *Length - 1;
1544 | 	}
1545 | 
1546 | 	*(*Target++) = '$';
1547 | 
1548 |     } else {
1549 | 
1550 | 	/**
1551 | 	 **  Something has been found. Form the parameter index at first
1552 | 	 **/
1553 | 	if( s == buffer)
1554 | 	    index = 0;
1555 | 	else
1556 | 	    index = atoi( buffer) - 1;
1557 | 
1558 | 	if( !last)
1559 | 	    last = index + 1;
1560 | 	if( last > argc)
1561 | 	    last = argc;
1562 | 
1563 | 	/**
1564 | 	 **  Spool them all out
1565 | 	 **/
1566 | 	while( index < last) {
1567 | 
1568 | 	    len = strlen( argv[ index]);
1569 | 
1570 | 	    while(( *Length + len + 1) >= strsize - 5) {
1571 | 		if( NULL == (error_line = (char*) realloc( error_line,
1572 | 		    strsize += ERR_LINELEN))) {
1573 | 		    ErrorLogger( ERR_ALLOC, LOC, NULL);
1574 | 		    return;
1575 | 		}
1576 | 		*Target = error_line + *Length;
1577 | 	    }
1578 | 
1579 | 	    strcpy( *Target, argv[ index]);
1580 | 	    *Target += len;
1581 | 	    *Length += len;
1582 | 
1583 | 	    index++;
1584 | 
1585 | 	} /** while **/
1586 |     } /** if **/
1587 | 
1588 | } /** End of 'add_param' **/