1 | /***************************************
2 | $Revision: 1.13 $
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)
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 )
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)
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,
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)
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)
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 |
185 | ctime_r(& tval.tv_sec, tmbuf);
186 | /* truncate before 2000 */
187 | tmbuf[19]=0;
188 | /* localtime_r( & tval.tv_sec, & tmstr);
189 | sprintf(tmbuf, "%02d:%02d:%02d",
190 | tmstr.tm_hour, tmstr.tm_min, tmstr.tm_sec); */
191 |
192 | } else {
193 | tmbuf[0]=0;
194 | }
195 |
196 | snprintf(buf, ER_MSGLEN, "%s %s\n", tmbuf, msg );
197 | /* OK, now dispatch the message to all different paths */
198 |
199 | /* MUTEX :
200 |
201 | So, while the most of the work is done composing the message
202 | according to the format set in the path descriptor (mode),
203 | the output should also be locked.
204 |
205 | here the mutex associated with the path should be set.
206 | However, another mutex should be already used to protect other threads
207 | from reading the path description while it is modified by the master
208 | thread. An RW lock can be used for this.
209 |
210 | Fortunately, fputs is MT-Safe in Solaris.
211 | */
212 |
213 |
214 | /* for now we have at most one :-) */
215 | if( er_provisional_struct.fdes == NULL ) {
216 | fputs(buf,stderr);
217 | }
218 | else {
219 | /* someone has really set something! */
220 | if( errcode >= er_provisional_struct.sev
221 | || ER_is_traced(facwhere, asp) ) {
222 |
223 | fputs(buf, er_provisional_struct.fdes);
224 | }
225 | }
226 |
227 |
228 |
229 | }
230 |
231 |
232 | int ER_is_traced(int facwhere, er_mask_t asp)
233 | {
234 | int ik = 0;
235 |
236 | if( er_provisional_struct.fac == 0
237 | || er_provisional_struct.fac == facwhere ) {
238 | /* pthread_mutex_lock( &er_pathlist_mutex ); */
239 | ik = er_provisional_struct.asp & asp;
240 | /* pthread_mutex_unlock( &er_pathlist_mutex ); */
241 | }
242 |
243 | return (ik);
244 | }
245 |
246 | int ER_anybody_wants( int facwhere, int errcode, er_mask_t asp )
247 | {
248 | int i;
249 |
250 | pthread_mutex_lock( &er_pathlist_mutex );
251 | i = ( errcode >= er_provisional_struct.sev );
252 | pthread_mutex_unlock( &er_pathlist_mutex );
253 |
254 | return i;
255 | }
256 |
257 | int er_get_printmode(er_path_t *pathstruct)
258 | {
259 | int i;
260 |
261 | pthread_mutex_lock( &er_pathlist_mutex );
262 | if( pathstruct->fdes == NULL ) {
263 | /* default mode */
264 | i = ER_M_DEFAULT;
265 | }
266 | else {
267 | i = pathstruct->mode;
268 | }
269 | pthread_mutex_unlock( &er_pathlist_mutex );
270 |
271 | return i;
272 | }
273 |
274 | void ER_perror(int facwhere, int errcode, char *format, ...)
275 | {
276 | char erbuf[ER_MSGLEN];
277 | int pmode;
278 | va_list ap;
279 |
280 | if( ER_anybody_wants( facwhere, errcode, 0 ) ) { /* uses pathlist mutex */
281 |
282 | pmode = er_get_printmode( & er_provisional_struct );/* uses pathlist mutex */
283 |
284 | /* now, this takes most time: */
285 | va_start(ap, format);
286 | er_getmsg_parts(facwhere, errcode, pmode, erbuf, format, ap );
287 | va_end(ap);
288 |
289 | /* actually, here will be a loop once there are more paths possible. */
290 | er_logit(facwhere,
291 | 0, /* empty aspect mask for errors */
292 | pmode,
293 | errcode,
294 | erbuf); /* empty debug message */
295 | }
296 | }
297 |
298 |
299 | void ER_asp_va( int facwhere, int sev, er_mask_t asp, char *txt,
300 | va_list args)
301 | {
302 | int pmode;
303 | char erbuf[ER_MSGLEN];
304 |
305 | pmode = er_get_printmode( & er_provisional_struct );
306 | er_getmsg_parts(facwhere, sev, pmode, erbuf, txt, args );
307 | er_logit(facwhere, asp, pmode, sev, erbuf);
308 | }
309 |
310 | void ER_inf_va( int facwhere, er_mask_t asp, char *txt, ...)
311 | {
312 | va_list ap;
313 | va_start(ap, txt);
314 | ER_asp_va( facwhere, ER_SEV_I, asp, txt, ap );
315 | va_end(ap);
316 | }
317 |
318 |
319 | void ER_dbg_va( int facwhere, er_mask_t asp, char *txt, ...)
320 | {
321 | char erbuf[ER_MSGLEN];
322 | int pmode;
323 | va_list ap;
324 |
325 | if( ER_is_traced( facwhere, asp ) ) {
326 |
327 | pmode = er_get_printmode( & er_provisional_struct );
328 |
329 | va_start(ap, txt);
330 | er_getmsg_parts(facwhere, ER_SEV_D, pmode, erbuf, txt, ap );
331 | va_end(ap);
332 |
333 | er_logit(facwhere, asp, pmode, ER_SEV_D, erbuf);
334 | }
335 | }
336 |
337 |
338 | /* Set GLOBAL VARIABLES == can be done only by the master thread */
339 | void ER_init(int argc, char **argv)
340 | {
341 | char *er_slash;
342 |
343 | er_slash = rindex(argv[0],'/');
344 | strncpy(er_progname, (er_slash != NULL) ? er_slash+1 : argv[0], 31);
345 | er_progname[31] = 0;
346 |
347 | snprintf(er_pid, 10, "%d", getpid());
348 |
349 | }