modules/er/er.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- NOERR
- er_getsev
- er_getfacsym
- er_getmsg_parts
- ER_setpath
- er_logit
- ER_is_traced
- ER_anybody_wants
- er_get_printmode
- ER_perror
- ER_asp_va
- ER_inf_va
- ER_dbg_va
- ER_init
1 /***************************************
2 $Revision: 1.12 $
3
4 Error reporting (er) er.c - library of functions to uniformly report errors.
5
6 Status: NOT REVUED, TESTED, PROVISIONAL
7
8 Design and implementation by: Marek Bukowy
9
10 ******************/ /******************
11 Copyright (c) 1999 RIPE NCC
12
13 All Rights Reserved
14
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of the author not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22
23 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
25 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
26 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
28 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 ***************************************/
30
31 #define ER_IMPL
32 #include "erroutines.h"
33 #include <pthread.h>
34 #include <time.h>
35
36
37 int NOERR(er_ret_t a)
/* [<][>][^][v][top][bottom][index][help] */
38 {
39 return ( ((a & 0xFFFF) == 0 ) /* the error part is 0 */
40 && ((a & 0xFFFF0000) != 0) ); /* the facility is non-zero */
41 }
42
43 char *er_getsev( int sev, int mode )
/* [<][>][^][v][top][bottom][index][help] */
44 {
45 int i;
46
47 for(i=0; er_level_a[i].sev != 0; i++) {
48 if (er_level_a[i].sev == sev) {
49 break;
50 }
51 }
52
53 switch( mode & 0x03 ) {
54 case ER_M_SEVCHAR: /* one-letter severity indication */
55 return er_level_a[i].chr;
56 case ER_M_SEVLONG: /* long severity indication */
57 return er_level_a[i].txt;
58 }
59
60 /* no severity indication */
61 return ""; /* "" goes to program text, so returning a
62 pointer to it is OK */
63 }
64
65 char *er_getfacsym(int faccode)
/* [<][>][^][v][top][bottom][index][help] */
66 {
67 int facidx;
68
69 if( faccode != FAC_NONE ) {
70 for (facidx=0; facidx<FAC_LAST; facidx++) {
71 if( er_main_err[facidx].code == faccode ) {
72 break;
73 }
74 }
75 return er_main_err[facidx].name;
76 }
77 else return "";
78 }
79
80 /* TWO CONSTANTS DEFINE THE LENGTH OF STRINGS HERE:
81 ER_MSGLEN - max length of the line to be logged
82 ER_ERRLEN - max length of the error message
83 */
84 char *er_getmsg_parts(int facwhere, int errcode, int mode,
/* [<][>][^][v][top][bottom][index][help] */
85 char *buf, char *fmttxt, va_list args)
86 {
87 int fac, err, sev;
88 int facidx, erridx;
89 char erbuf[ER_ERRLEN], thr_str[10], *ermne, *txtlong="";
90
91 /* init to "" */
92 erbuf[0] = 0;
93 ermne = "";
94
95 sev = ( errcode & 0xff000000 ); /* not shifted */
96 fac = ( errcode & 0x00ff0000 ) >> 16;
97 err = ( errcode & 0x0000ffff ); /* not shifted */
98
99 for (facidx=0; facidx<FAC_LAST; facidx++) {
100 if( er_main_err[facidx].code == fac ) {
101 break;
102 }
103 }
104
105 /* now, if we got to the last one and it's not the right one,
106 the system is not configured properly */
107 if(facidx==FAC_LAST) {
108 assert( er_main_err[facidx].code == fac ); /* just bail out. */
109 }
110
111 /* still alive ? OK, build the message ...*/
112
113 /* ... using facidx/erridx if it's not a DEBUG or INFO */
114 switch( sev ) {
115 case ER_SEV_D:
116 ermne = "DEBUG";
117 break;
118 case ER_SEV_I:
119 ermne = "INFO";
120 break;
121 default:
122 /* OK, go to the module table. bail out if not initialized */
123 assert( er_main_err[facidx].errs != NULL );
124
125 for(erridx=0; er_main_err[facidx].errs[erridx].code != -1; erridx++) {
126 if( er_main_err[facidx].errs[erridx].code == errcode ) {
127 /* FOUND! now set the error message format using facidx and erridx */
128
129 /* long error message without arguments */
130 txtlong = er_main_err[facidx].errs[erridx].text;
131
132 /* set the mnemonic pointer if necessary */
133 if( mode & ER_M_MNEMONIC ) {
134 ermne = er_main_err[facidx].errs[erridx].mnem;
135 }
136 break;
137 }
138 }
139 /* return ""; */
140 /* no, do not return: bail out if the code is not defined */
141 assert( er_main_err[facidx].errs[erridx].code != -1 );
142 }
143
144 /* build the error message using vsnprintf */
145 vsnprintf(erbuf, ER_ERRLEN, fmttxt, args);
146
147 sprintf(thr_str, "%d", pthread_self() );
148
149 /* build the actual log message */
150 snprintf(buf, ER_MSGLEN, "%s-%s/%s %s-%s-%s %s %s",
151 (mode & ER_M_PROGNAME) ? er_progname : "",
152 (mode & ER_M_PIDFULL) ? er_pid : "",
153 (mode & ER_M_THR_ID ) ? thr_str : "",
154 (mode & ER_M_FACSYMB) ? er_getfacsym(facwhere) : "",
155 er_getsev(sev, mode),
156 (mode & ER_M_MNEMONIC) ? ermne : "",
157 (mode & ER_M_TEXTLONG) ? txtlong : "",
158 erbuf
159 );
160 return buf;
161 }
162
163 void ER_setpath(er_path_t *newset)
/* [<][>][^][v][top][bottom][index][help] */
164 {
165 /* initialise the mutex if not yet initialised */
166
167 if( er_pathlist_mutex_initialised == 0 ) {
168 pthread_mutex_init( &er_pathlist_mutex, NULL );
169 }
170
171 pthread_mutex_lock( &er_pathlist_mutex );
172 memcpy( & er_provisional_struct, newset, sizeof(er_path_t));
173 pthread_mutex_unlock( &er_pathlist_mutex );
174 }
175
176 void er_logit(int facwhere, er_mask_t asp, int mode, int errcode, char *msg)
/* [<][>][^][v][top][bottom][index][help] */
177 {
178 char buf[ER_MSGLEN], tmbuf[32];
179 struct timeval tval;
180 struct tm tmstr;
181
182 if ( mode & ER_M_DATETIME ) {
183 gettimeofday(&tval, NULL);
184 localtime_r( & tval.tv_sec, & tmstr);
185
186 /* strcpy(tmbuf, ctime(&tm)+11); */
187 sprintf(tmbuf, "%02d:%02d:%02d",
188 tmstr.tm_hour, tmstr.tm_min, tmstr.tm_sec);
189 } else {
190 tmbuf[0]=0;
191 }
192
193 snprintf(buf, ER_MSGLEN, "%s %s\n", tmbuf, msg );
194 /* OK, now dispatch the message to all different paths */
195
196 /* MUTEX :
197
198 So, while the most of the work is done composing the message
199 according to the format set in the path descriptor (mode),
200 the output should also be locked.
201
202 here the mutex associated with the path should be set.
203 However, another mutex should be already used to protect other threads
204 from reading the path description while it is modified by the master
205 thread. An RW lock can be used for this.
206
207 Fortunately, fputs is MT-Safe in Solaris.
208 */
209
210
211 /* for now we have at most one :-) */
212 if( er_provisional_struct.fdes == NULL ) {
213 fputs(buf,stderr);
214 }
215 else {
216 /* someone has really set something! */
217 if( errcode >= er_provisional_struct.sev
218 || ER_is_traced(facwhere, asp) ) {
219
220 fputs(buf, er_provisional_struct.fdes);
221 }
222 }
223
224
225
226 }
227
228
229 int ER_is_traced(int facwhere, er_mask_t asp)
/* [<][>][^][v][top][bottom][index][help] */
230 {
231 int ik = 0;
232
233 if( er_provisional_struct.fac == 0
234 || er_provisional_struct.fac == facwhere ) {
235 /* pthread_mutex_lock( &er_pathlist_mutex ); */
236 ik = er_provisional_struct.asp & asp;
237 /* pthread_mutex_unlock( &er_pathlist_mutex ); */
238 }
239
240 return (ik);
241 }
242
243 int ER_anybody_wants( int facwhere, int errcode, er_mask_t asp )
/* [<][>][^][v][top][bottom][index][help] */
244 {
245 int i;
246
247 pthread_mutex_lock( &er_pathlist_mutex );
248 i = ( errcode >= er_provisional_struct.sev );
249 pthread_mutex_unlock( &er_pathlist_mutex );
250
251 return i;
252 }
253
254 int er_get_printmode(er_path_t *pathstruct)
/* [<][>][^][v][top][bottom][index][help] */
255 {
256 int i;
257
258 pthread_mutex_lock( &er_pathlist_mutex );
259 if( pathstruct->fdes == NULL ) {
260 /* default mode */
261 i = ER_M_DEFAULT;
262 }
263 else {
264 i = pathstruct->mode;
265 }
266 pthread_mutex_unlock( &er_pathlist_mutex );
267
268 return i;
269 }
270
271 void ER_perror(int facwhere, int errcode, char *format, ...)
/* [<][>][^][v][top][bottom][index][help] */
272 {
273 char erbuf[ER_MSGLEN];
274 int pmode;
275 va_list ap;
276
277 if( ER_anybody_wants( facwhere, errcode, 0 ) ) { /* uses pathlist mutex */
278
279 pmode = er_get_printmode( & er_provisional_struct );/* uses pathlist mutex */
280
281 /* now, this takes most time: */
282 va_start(ap, format);
283 er_getmsg_parts(facwhere, errcode, pmode, erbuf, format, ap );
284 va_end(ap);
285
286 /* actually, here will be a loop once there are more paths possible. */
287 er_logit(facwhere,
288 0, /* empty aspect mask for errors */
289 pmode,
290 errcode,
291 erbuf); /* empty debug message */
292 }
293 }
294
295
296 void ER_asp_va( int facwhere, int sev, er_mask_t asp, char *txt,
/* [<][>][^][v][top][bottom][index][help] */
297 va_list args)
298 {
299 int pmode;
300 char erbuf[ER_MSGLEN];
301
302 pmode = er_get_printmode( & er_provisional_struct );
303 er_getmsg_parts(facwhere, sev, pmode, erbuf, txt, args );
304 er_logit(facwhere, asp, pmode, sev, erbuf);
305 }
306
307 void ER_inf_va( int facwhere, er_mask_t asp, char *txt, ...)
/* [<][>][^][v][top][bottom][index][help] */
308 {
309 va_list ap;
310 va_start(ap, txt);
311 ER_asp_va( facwhere, ER_SEV_I, asp, txt, ap );
312 va_end(ap);
313 }
314
315
316 void ER_dbg_va( int facwhere, er_mask_t asp, char *txt, ...)
/* [<][>][^][v][top][bottom][index][help] */
317 {
318 char erbuf[ER_MSGLEN];
319 int pmode;
320 va_list ap;
321
322 if( ER_is_traced( facwhere, asp ) ) {
323
324 pmode = er_get_printmode( & er_provisional_struct );
325
326 va_start(ap, txt);
327 er_getmsg_parts(facwhere, ER_SEV_D, pmode, erbuf, txt, ap );
328 va_end(ap);
329
330 er_logit(facwhere, asp, pmode, ER_SEV_D, erbuf);
331 }
332 }
333
334
335 /* Set GLOBAL VARIABLES == can be done only by the master thread */
336 void ER_init(int argc, char **argv)
/* [<][>][^][v][top][bottom][index][help] */
337 {
338 char *er_slash;
339
340 er_slash = rindex(argv[0],'/');
341 strncpy(er_progname, (er_slash != NULL) ? er_slash+1 : argv[0], 31);
342 er_progname[31] = 0;
343
344 snprintf(er_pid, 10, "%d", getpid());
345
346 }