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 | }