modules/er/er.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. NOERR
  2. er_getsev
  3. er_getfacsym
  4. er_getmsg_parts
  5. ER_setpath
  6. er_logit
  7. ER_is_traced
  8. ER_anybody_wants
  9. er_get_printmode
  10. ER_perror
  11. ER_asp_va
  12. ER_inf_va
  13. ER_dbg_va
  14. 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 }

/* [<][>][^][v][top][bottom][index][help] */