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: ef795b8bb070a4d4366a7a7a868bc4758baa2838 $";
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, "Parameter error concerning '$1'" },
252     { ERR_USAGE,	WGHT_ERROR, "Usage is '$*'" },
253     { ERR_ARGSTOLONG,	WGHT_ERROR, "'$1': Arguments too 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 LOADEDMODULES 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 
Module_Tracing(int result,int argc,char ** argv)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 
Module_Verbosity(int argc,char ** argv)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 
Print_Tracing(char * buffer,int result,int argc,char ** argv)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 
save_error_state(int reset)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 
Enable_Error(void)541 void Enable_Error(void) {
542 	save_error_state(0);
543 	quiet_on_error = 0;
544 }
545 
Disable_Error(void)546 void Disable_Error(void) {
547 	save_error_state(0);
548 	quiet_on_error = 1;
549 }
550 
Restore_Error(void)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 
Module_Error(ErrType error_type,char * module,int lineno,...)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 **) module_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(!(argv = (char **) module_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 
ErrorLookup(ErrType error_type)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 
MeasLookup(ErrWeights weigth)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 
FlushError(ErrType Type,char * module,int lineno,ErrWeights Weight,char * WeightMsg,char * ErrMsgs,int argc,char ** argv)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 = xstrtok( facilities, ":");
934 	 fac;
935 	 fac = xstrtok( (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 	/* error output to stderr too if an error or verbose */
961 	    if (Type >= NO_ERR_VERBOSE)
962 		fprintf( stderr, "%s", errmsg_buffer);
963 
964 	/* now send to syslog */
965 	    if( CheckFacility( fac, &syslog_fac, &syslog_lvl)) {
966 		openlog( "modulecmd", LOG_PID, syslog_fac);
967 		setlogmask( LOG_UPTO( syslog_lvl));
968 		syslog( (syslog_fac | syslog_lvl), "%s", errmsg_buffer);
969 		closelog();
970 
971 	    /**
972 	     **  Invalid facilities ... take care not to end up in
973 	     **  infinite loops
974 	     **/
975 	    } else if( Type == ERR_INVFAC ||
976 	               OK == ErrorLogger( ERR_INVFAC, LOC, fac, NULL))
977 		continue;
978 
979 #else
980 #  ifdef	SYSLOG_DIR
981 	    /* this is an intentional memory leak */
982 	    buffer = stringer(NULL,0, SYSLOG_DIR, "/", fac);
983 	    fac = buffer;
984 #  endif
985 #endif
986 	}
987 
988 	/**
989 	 **  Custom files ...
990 	 **  This may result from the syslog part above
991 	 **/
992 	if( '.' == *fac || '/' == *fac) {
993 	    if((FILE *) NULL == (facfp = fopen( fac, "a"))) {
994 
995 		if( WGHT_PANIC == Weight)	/** Avoid endless loops!     **/
996 		    goto unwind2;
997 
998 		/**
999 		 **  Invalid facilities ... take care not to end up in
1000 		 **  infinite loops
1001 		 **/
1002 		if( Type == ERR_INVFAC ||
1003 		    OK == ErrorLogger( ERR_INVFAC, LOC, fac, NULL))
1004 		    continue;
1005 		else
1006 		    goto unwind2;
1007 	    }
1008 
1009 	    fprintf( facfp, "%s", errmsg_buffer);
1010 
1011 	    if( EOF == fclose( facfp))
1012 		if( OK != ErrorLogger( ERR_CLOSE, LOC, fac, NULL))
1013 		    goto unwind2;
1014 
1015 	}
1016     } /** for **/
1017 
1018     /**
1019      **  Return on success
1020      **/
1021     null_free((void *) &errmsg_buffer);
1022     if( fac_alloc)
1023 	null_free((void *) &facilities);
1024 success0:
1025     return( 1);				/** -------- EXIT (SUCCESS) -------> **/
1026 
1027 unwind2:
1028     null_free((void *) &errmsg_buffer);
1029 unwind1:
1030     if( fac_alloc)
1031 	null_free((void *) &facilities);
1032 unwind0:
1033     return( 0);				/** -------- EXIT (FAILURE) -------> **/
1034 
1035 } /** End of 'FlushError' **/
1036 
1037 /*++++
1038  ** ** Function-Header ***************************************************** **
1039  ** 									     **
1040  **   Function:		GetFacility					     **
1041  ** 									     **
1042  **   Description:	Get the log facility according to the passed error   **
1043  **			weight						     **
1044  ** 									     **
1045  **   First Edition:	1995/12/21					     **
1046  ** 									     **
1047  **   Parameters:	ErrWeights	  Weight	Error Weight	     **
1048  ** 									     **
1049  **   Result:		char*	NULL		No facility found	     **
1050  **				Otherwise	Pointer to the colon separa- **
1051  **						ted facility string	     **
1052  ** 									     **
1053  ** ************************************************************************ **
1054  ++++*/
1055 
GetFacility(ErrWeights Weight)1056 static	char	*GetFacility(	ErrWeights	  Weight)
1057 {
1058     ErrFacilities	*facility;
1059 
1060     /**
1061      **  Get the facility table entry at first
1062      **/
1063     if( !(facility = GetFacility_sub( Weight)))
1064 	return((char *) NULL);
1065 
1066     /**
1067      **  Now we've got two possibilities:
1068      **      First of all there may be a custom facilitiy defined
1069      **	     Otherwise the default facility is to be returned now
1070      **/
1071     return( facility->facility ? facility->facility : facility->def_facility);
1072 
1073 } /** End of 'GetFacility' **/
1074 
GetFacility_sub(ErrWeights Weight)1075 static	ErrFacilities	*GetFacility_sub(	ErrWeights	  Weight)
1076 {
1077     ErrFacilities	*low, *mid, *high, *save;
1078     char		buffer[ 20];
1079 
1080     /**
1081      **  Binary search for the passed facility in the Facilities table.
1082      **  This requires the table to be sorted on ascending error weight
1083      **/
1084     low = Facilities;
1085     high = Facilities + (sizeof( Facilities) / sizeof( Facilities[0]));
1086     save = (ErrFacilities *) NULL;
1087     mid = (ErrFacilities *) NULL;
1088 
1089     while( low < high) {
1090 	save = mid;
1091 	mid = low + ((high - low) / 2);
1092 	if( save == mid)
1093 	    low = mid = high;			/** Just to be sure ...	     **/
1094 
1095 	if( mid->Weight > Weight)
1096 	    high = mid;
1097 	else if( mid->Weight < Weight)
1098 	    low = mid;
1099 	else
1100 	    break;	/** found! **/
1101     }
1102 
1103     /**
1104      **  We have to check, if we've found something or if there's an internal
1105      **  error (wrong weight)
1106      **/
1107     if( mid->Weight != Weight) {
1108 	if( OK == ErrorLogger( ERR_INVWGHT, LOC, (sprintf( buffer, "%d",
1109 	    Weight), buffer), NULL))
1110 	    return( NULL);
1111     }
1112 
1113     return( mid);
1114 
1115 } /** End of 'GetFacility_sub' **/
1116 
1117 /*++++
1118  ** ** Function-Header ***************************************************** **
1119  ** 									     **
1120  **   Function:		CheckFacility					     **
1121  ** 									     **
1122  **   Description:	Check the passwd string to be a valid combination    **
1123  **			of       <syslog_facility>.<syslog_level>	     **
1124  ** 									     **
1125  **   First Edition:	1995/12/21					     **
1126  ** 									     **
1127  **   Parameters:	char	*string		Input facility string	     **
1128  **			int	*facility	Buffer for the real facility **
1129  **			int	*level		Buffer for the real level    **
1130  ** 									     **
1131  **   Result:		int	1		Success			     **
1132  **				0		Failure. String not valid    **
1133  ** 									     **
1134  ** ************************************************************************ **
1135  ++++*/
1136 
CheckFacility(char * string,int * facility,int * level)1137 int	CheckFacility(	char *string, int *facility, int *level)
1138 {
1139     char *s, *buf;
1140     int x;
1141 
1142     /**
1143      **  We do not want to change the strings ... so allocate a buffer here
1144      **/
1145     if((char *) NULL == (buf = stringer(NULL,0, string,NULL)))
1146 	if( OK == ErrorLogger( ERR_STRING, LOC, NULL))
1147 	    goto unwind0;
1148 
1149     /**
1150      **  We cannot use strtok here, because there's one initialized in an
1151      **  outer loop!
1152      **/
1153     for( s=buf; s && *s && *s != '.'; s++);
1154     if( !s || !*s)
1155 	goto unwind1;
1156     *s = '\0';
1157 
1158     /**
1159      **  This should be the facility
1160      **/
1161     if( -1 == (x = scan_facility( buf, facility_names,
1162 	    (sizeof( facility_names) / sizeof( facility_names[0])) )))
1163 	goto unwind1;
1164     *facility = x;
1165 
1166     /**
1167      **  This should be the level
1168      **/
1169     if( -1 == (x = scan_facility( ++s, level_names,
1170 	    (sizeof( level_names) / sizeof( level_names[0])) )))
1171 	goto unwind1;
1172     *level = x;
1173 
1174     /**
1175      **  Success
1176      **/
1177     null_free((void *) &buf);
1178     return( 1);				/** -------- EXIT (SUCCESS) -------> **/
1179 
1180 unwind1:
1181     null_free((void *) &buf);
1182 unwind0:
1183     return( 0);				/** -------- EXIT (FAILURE) -------> **/
1184 
1185 } /** End of 'CheckFacility' **/
1186 
1187 /*++++
1188  ** ** Function-Header ***************************************************** **
1189  ** 									     **
1190  **   Function:		scan_facility					     **
1191  ** 									     **
1192  **   Description:	Scan the passed facility names table for the given   **
1193  **			string and pass back the assigned token		     **
1194  ** 									     **
1195  **   First Edition:	1995/12/21					     **
1196  ** 									     **
1197  **   Parameters:	char		*s	String to be checked	     **
1198  **			FacilityNames	*table	Table of valid names and     **
1199  **						tokens			     **
1200  **			int		 size	Size of the table	     **
1201  ** 									     **
1202  **   Result:		int	-1		name not found in the table  **
1203  **				Otherwise	Assigned token		     **
1204  ** 									     **
1205  ** ************************************************************************ **
1206  ++++*/
1207 
scan_facility(char * s,FacilityNames * table,int size)1208 static	int	scan_facility( char *s, FacilityNames *table, int size)
1209 {
1210     FacilityNames *low, *mid, *high, *save;
1211 
1212     low = table;
1213     high = table + size;
1214     save = (FacilityNames *) NULL;
1215     mid = (FacilityNames *) NULL;
1216 
1217     while( low < high) {
1218 	int x;			/** Have to use this, because strcmp will    **/
1219 				/** not return -1 and 1 on Solaris 2.x	     **/
1220 	save = mid;
1221 	mid = low + ((high - low) / 2);
1222 	if( save == mid)
1223 	    low = mid = high;			/** To prevent endless loops **/
1224 
1225 	if (mid == high)
1226 		return -1;
1227 	x = strcmp( mid->name, s);
1228 
1229 	if( x < 0 )
1230 	    low = mid;
1231 	else if( x > 0)
1232 	    high = mid;
1233 	else
1234 	    return( mid->token);
1235 
1236     } /** while **/
1237 
1238     return( !strcmp( mid->name, s) ? mid->token : -1 );
1239 
1240 } /** End of 'scan_facility' **/
1241 
1242 /*++++
1243  ** ** Function-Header ***************************************************** **
1244  ** 									     **
1245  **   Function:		GetFacilityPtr					     **
1246  ** 									     **
1247  **   Description:	Scan the passed facility names table for the given   **
1248  **			string and pass back the assigned token		     **
1249  ** 									     **
1250  **   First Edition:	1995/12/21					     **
1251  ** 									     **
1252  **   Parameters:	char	*facility	Name of the facility	     **
1253  ** 									     **
1254  **   Result:		char**	NULL		Invalid facility name	     **
1255  **				Otherwise	Pointer to the facilty string**
1256  **						reference		     **
1257  ** 									     **
1258  ** ************************************************************************ **
1259  ++++*/
1260 
GetFacilityPtr(char * facility)1261 char	**GetFacilityPtr( char *facility)
1262 {
1263     int		 	 i, len;
1264     ErrMeasr		*measptr;
1265     char		*buf, *s, *t;
1266     ErrFacilities	*facptr;
1267 
1268     /**
1269      **  Try to figure out the error weight at first
1270      **  Need the given weight in upper case for this
1271      **/
1272     len = strlen( facility);
1273 
1274     if((char *) NULL == (buf = stringer(NULL, 0, facility, NULL)))
1275 	if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL))
1276 	    goto unwind0;
1277 
1278     for( t = buf; *t; ++t) *t = toupper(*t);
1279 
1280     /**
1281      **  Now look up the measurements table for the uppercase weight
1282      **/
1283     i = sizeof( Measurements) / sizeof( Measurements[ 0]);
1284     measptr = Measurements;
1285 
1286     while( i) {
1287 	if( !strncmp( measptr->message, buf, len))
1288 	    break;
1289 	i--; measptr++;
1290     }
1291 
1292     null_free((void *) &buf);
1293 
1294     if( !i) 					/** not found		     **/
1295 	goto unwind0;
1296 
1297     /**
1298      **  Now get the facility table entry
1299      **/
1300 
1301     if((ErrFacilities *) NULL == (facptr = GetFacility_sub(
1302 	measptr->error_weight))) {
1303 	ErrorLogger( ERR_INVWGHT_WARN, LOC, facility, NULL);
1304 	goto unwind0;
1305     }
1306 
1307     /**
1308      **  Got it ... return the desired pointer
1309      **/
1310     return( &facptr->facility);		/** -------- EXIT (RESULT)  -------> **/
1311 
1312 unwind0:
1313     return((char **) NULL);		/** -------- EXIT (FAILURE) -------> **/
1314 
1315 } /** End of 'GetFacilityPtr' **/
1316 
1317 /*++++
1318  ** ** Function-Header ***************************************************** **
1319  ** 									     **
1320  **   Function:		PrintError					     **
1321  ** 									     **
1322  **   Description:	Print the error message				     **
1323  ** 									     **
1324  **   First Edition:	1995/08/06					     **
1325  ** 									     **
1326  **   Parameters:	char             *errbuffer	Buffer to hold the   **
1327  **							error messge	     **
1328  **			ErrType		  Type		Error type as passed **
1329  **			char		 *module	Module name	     **
1330  **			int		  lineno	Line number	     **
1331  **		  	ErrWeights	  Weight	Error Weight	     **
1332  **			char		 *WeightMsg	Printable Weight     **
1333  **			char		 *ErrMsgs	Error message	     **
1334  **			int		  argc		Number of arguments  **
1335  **			char		**argv		Argument array	     **
1336  ** 									     **
1337  **   Result:		int	1		Everything OK		     **
1338  **				0		Error occured while printing **
1339  ** 									     **
1340  **   Notes:	According to the error type, the passed module and line num- **
1341  **		ber will be handled as a module-file related one or depending**
1342  **		on the packages source code:				     **
1343  **									     **
1344  **		src -> ERR_IN_MODULEFILE -> modulefile -> ERR_INTERNAL -> src**
1345  ** 									     **
1346  ** ************************************************************************ **
1347  ++++*/
1348 
PrintError(char * errbuffer,ErrType Type,char * module,int lineno,ErrWeights Weight,char * WeightMsg,char * ErrMsgs,int argc,char ** argv)1349 static	int	PrintError(	char 		 *errbuffer,
1350 				ErrType		  Type,
1351 				char		 *module,
1352 				int		  lineno,
1353 				ErrWeights	  Weight,
1354 				char		 *WeightMsg,
1355 				char		 *ErrMsgs,
1356 				int		  argc,
1357 				char		**argv)
1358 {
1359     char	*error_string;
1360 
1361     /**
1362      **  Build the error string at first. Note - we cannot alloc memory any
1363      **  more!
1364      **/
1365     if( ERR_ALLOC == Type)
1366 	error_string = ErrMsgs;
1367     else
1368 	if( NULL == (error_string = ErrorString( ErrMsgs, argc, argv)))
1369 	    return( 0);
1370 
1371     /**
1372      **  Print
1373      **/
1374 
1375     if( ERR_INTERNAL > Type && ERR_IN_MODULEFILE < Type &&
1376 	linenum && g_current_module )
1377 
1378 	sprintf( errbuffer, "%s(%s):%s:%d: %s\n", g_current_module,
1379 	    (sprintf( buffer, "%d", linenum), buffer),
1380 	    WeightMsg, Type, (error_string ? error_string : "") );
1381     else
1382 
1383 	sprintf( errbuffer, "%s(%s):%s:%d: %s\n", (module ? module : "??"),
1384 	    ( lineno ? (sprintf( buffer, "%d", lineno), buffer) : "??" ),
1385 	    WeightMsg, Type, (error_string ? error_string : "") );
1386 
1387     /**
1388      **  Success
1389      **/
1390     return( 1);
1391 
1392 } /** End of 'PrintError' **/
1393 
1394 /*++++
1395  ** ** Function-Header ***************************************************** **
1396  ** 									     **
1397  **   Function:		ErrorString					     **
1398  ** 									     **
1399  **   Description:	Print the error message				     **
1400  ** 									     **
1401  **   First Edition:	1995/08/06					     **
1402  ** 									     **
1403  **   Parameters:	char		 *ErrMsgs	Error message	     **
1404  **			int		  argc		Number of arguments  **
1405  **			char		**argv		Argument array	     **
1406  ** 									     **
1407  **   Result:		char*	NULL		Parse or alloc error	     **
1408  **				else		Pointer to the error string  **
1409  ** 									     **
1410  **   Attached Globals:	-						     **
1411  **									     **
1412  ** ************************************************************************ **
1413  ++++*/
1414 
ErrorString(char * ErrMsgs,int argc,char ** argv)1415 static	char	*ErrorString(	char		 *ErrMsgs,
1416 				int		  argc,
1417 				char		**argv)
1418 {
1419     char	*s;			/** Insertion pointer		     **/
1420     int		len = 0;		/** Current length		     **/
1421     int		backslash = 0;		/** backslash found ?		     **/
1422 
1423     if( !ErrMsgs)
1424 	return( NULL);
1425 
1426     /**
1427      **  Allocate memory if neccessary
1428      **/
1429     if( !error_line)
1430 	if((char *) NULL ==(error_line = stringer(NULL,strsize = ERR_LINELEN,
1431 		NULL))){
1432 	    ErrorLogger( ERR_STRING, LOC, NULL);
1433 	    return( NULL);
1434 	}
1435 
1436     s = error_line;
1437 
1438     /**
1439      **  Scan the error strings to be printed
1440      **/
1441     while( *ErrMsgs) {
1442 
1443 	/**
1444 	 **  Check for special characters
1445 	 **/
1446 	switch( *ErrMsgs) {
1447 	    case '\\':	if( !backslash) {
1448 				backslash = 1;
1449 				ErrMsgs++;
1450 				continue;	/** while( *ErrMsgs) **/
1451 			    }
1452 			    break;	/** switch **/
1453 
1454 	    case '$':	if( !backslash) {
1455 				ErrMsgs++;
1456 				add_param( &ErrMsgs, &s, &len, argc, argv);
1457 				error_line = s - len;
1458 				continue;	/** while( *ErrMsgs) **/
1459 			    }
1460 			    break;	/** switch **/
1461 	} /** switch **/
1462 
1463 	/**
1464 	 **  Add a single character to the error string
1465 	 **/
1466 	if( ++len >= strsize - 5) {	/** 5 Bytes for safety		     **/
1467 	    if(!(error_line = (char *) module_realloc( error_line,
1468 		strsize += ERR_LINELEN))) {
1469 		ErrorLogger( ERR_ALLOC, LOC, NULL);
1470 		return( NULL);
1471 	    }
1472 	    s = error_line + len - 1;
1473 	}
1474 
1475 	*s++ = *ErrMsgs++;
1476 	backslash = 0;
1477 
1478     } /** while( *ErrMsgs) **/
1479 
1480     /**
1481      **  Success. Return a pointer to the newly created string
1482      **/
1483     *s++ = '\0';
1484     return( error_line);
1485 
1486 } /** End of 'ErrorString' **/
1487 
1488 /*++++
1489  ** ** Function-Header ***************************************************** **
1490  ** 									     **
1491  **   Function:		add_param					     **
1492  ** 									     **
1493  **   Description:	Put an argument to the error string		     **
1494  ** 									     **
1495  **   First Edition:	1995/08/06					     **
1496  ** 									     **
1497  **   Parameters:	char		**Control	Parameter control    **
1498  **			char		**Target	Target to print to   **
1499  **			int		 *Length	Current length of the**
1500  **							output string	     **
1501  **			int		  argc		Number of arguments  **
1502  **			char		**argv		Argument array	     **
1503  ** 									     **
1504  **   Result:		-						     **
1505  ** 									     **
1506  **   Attached Globals:	-						     **
1507  **									     **
1508  ** ************************************************************************ **
1509  ++++*/
1510 
add_param(char ** Control,char ** Target,int * Length,int argc,char ** argv)1511 static	void	add_param(	char		**Control,
1512 				char		**Target,
1513 				int		 *Length,
1514 				int		  argc,
1515 				char		**argv)
1516 {
1517     char	*s;			/** Scan pointer fot the ctrl field  **/
1518     int		index, last = 0;	/** parameter index		     **/
1519     int		len = 0;		/** Parameter string length	     **/
1520 
1521     /**
1522      **  Copy the current control field into the buffer
1523      **/
1524 
1525     for( s = buffer; **Control; (*Control)++ ) {
1526 
1527 	if( **Control == '*') {
1528 	    last = argc;
1529 	    continue;
1530 	} else if( **Control < '0' || **Control > '9')
1531 	    break;
1532 
1533 	*s++ = **Control;
1534     }
1535 
1536     *s = '\0';
1537 
1538     /**
1539      **  Has something been found ? If not, print a '$'
1540      **/
1541     if( s == buffer && !last) {
1542 
1543 	if( ++(*Length) >= strsize) {
1544 	    if(!(error_line = (char*) module_realloc( error_line,
1545 		strsize += ERR_LINELEN))) {
1546 		ErrorLogger( ERR_ALLOC, LOC, NULL);
1547 		return;
1548 	    }
1549 	    *Target = error_line + *Length - 1;
1550 	}
1551 
1552 	*(*Target++) = '$';
1553 
1554     } else {
1555 
1556 	/**
1557 	 **  Something has been found. Form the parameter index at first
1558 	 **/
1559 	if( s == buffer)
1560 	    index = 0;
1561 	else
1562 	    index = atoi( buffer) - 1;
1563 
1564 	if( !last)
1565 	    last = index + 1;
1566 	if( last > argc)
1567 	    last = argc;
1568 
1569 	/**
1570 	 **  Spool them all out
1571 	 **/
1572 	while( index < last) {
1573 
1574 	    len = strlen( argv[ index]);
1575 
1576 	    while(( *Length + len + 1) >= strsize - 5) {
1577 		if(!(error_line = (char*) module_realloc( error_line,
1578 		    strsize += ERR_LINELEN))) {
1579 		    ErrorLogger( ERR_ALLOC, LOC, NULL);
1580 		    return;
1581 		}
1582 		*Target = error_line + *Length;
1583 	    }
1584 
1585 	    strcpy( *Target, argv[ index]);
1586 	    *Target += len;
1587 	    *Length += len;
1588 
1589 	    index++;
1590 
1591 	} /** while **/
1592     } /** if **/
1593 
1594 } /** End of 'add_param' **/
1595