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