modules/er/er.c

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

FUNCTIONS

This source file includes following functions.
  1. NOERR
  2. er_msgsel
  3. er_forkexec
  4. er_logtopath
  5. er_getmsg_parts
  6. er_format_line
  7. er_logit
  8. ER_is_traced
  9. ER_is_errorlogged
  10. er_get_printmode
  11. ER_perror
  12. ER_asp_va
  13. ER_inf_va
  14. ER_dbg_va
  15. ER_init

   1 /***************************************
   2   $Revision: 1.22 $
   3 
   4   Error reporting (er) er.c - library of functions to uniformly report errors.
   5 
   6   Status: NOT REVUED, PARTLY TESTED
   7 
   8   NOTE: MALLOC ALERT!!! THE REPORTING FUNCTIONS MAY NOT USE DYNAMIC MEMORY!!!
   9   for one: they wouldn't work if we run out of memory...
  10   for two: the memory wrappers may have logging enabled, and it would loop.
  11 
  12   Design and implementation by: Marek Bukowy
  13 
  14   ******************/ /******************
  15   Copyright (c) 1999,2000                             RIPE NCC
  16  
  17   All Rights Reserved
  18   
  19   Permission to use, copy, modify, and distribute this software and its
  20   documentation for any purpose and without fee is hereby granted,
  21   provided that the above copyright notice appear in all copies and that
  22   both that copyright notice and this permission notice appear in
  23   supporting documentation, and that the name of the author not be
  24   used in advertising or publicity pertaining to distribution of the
  25   software without specific, written prior permission.
  26   
  27   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  28   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  29   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  30   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  31   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  32   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33   ***************************************/
  34 
  35 #define ER_IMPL
  36 #include "erroutines.h"
  37 #include <pthread.h>
  38 #include <time.h>
  39 
  40 #ifdef _LINUX
  41 #include <sys/time.h>
  42 #include <unistd.h>
  43 #endif
  44 
  45 #include <sys/types.h>
  46 #include <sys/stat.h>
  47 #include <fcntl.h>
  48 
  49 #include "er_macro.h"
  50 
  51 int NOERR(er_ret_t a) 
     /* [<][>][^][v][top][bottom][index][help] */
  52 {
  53   return (    ((a & 0xFFFF) == 0 )          /* the error part is 0 */
  54               && ((a & 0xFFFF0000) != 0) ); /* the facility is non-zero */
  55 }
  56 
  57 
  58 int er_msgsel( er_filter_t *filtptr, 
     /* [<][>][^][v][top][bottom][index][help] */
  59                er_fac_code_t facwhere, 
  60                er_mask_t asp, 
  61                er_ret_t errcode)
  62 {
  63   if( ! MA_isset( filtptr->fac_mask, facwhere) ) {
  64         return 0;
  65   }
  66   
  67   /* check aspect only for DEBUG and INFO messages */
  68   if( ( errcode == ER_SEV_D || errcode == ER_SEV_I )
  69       && ! (asp & filtptr->asp_mask) ) {
  70     return 0;
  71   }
  72   
  73   if(    (errcode & 0xff000000) < filtptr->sev_min 
  74       || (errcode & 0xff000000) > filtptr->sev_max ) {
  75     return 0;
  76   }
  77 
  78   if(    filtptr->thr_id != 0 
  79       && filtptr->thr_id != pthread_self() ) {
  80     return 0;
  81   }
  82 
  83   return 1;
  84 }
  85 
  86 
  87 /* fork & exec a program specified with argv, the print msg
  88    on its stdin and exit. No redirection of stdout/stderr is done.
  89 
  90    MT-note: Solaris fork1() duplicates only the calling thread.
  91    So does Posix fork().
  92  */
  93 er_forkexec(char **argv, char *msg, int usepath)
     /* [<][>][^][v][top][bottom][index][help] */
  94 {
  95   int PipeEnds[2];
  96   int status, cpid;
  97  
  98   pipe(PipeEnds);              
  99   
 100 #define PIP_WR 1
 101 #define PIP_RD 0
 102 
 103 #ifdef _POSIX_PTHREAD_SEMANTICS 
 104 #define fork1 fork
 105 #endif
 106 
 107   if((cpid=fork1()) == 0)               /* child */
 108     {       
 109       dup2( PipeEnds[PIP_RD], 0 ); 
 110       close( PipeEnds[PIP_WR] );        /* pipe input */
 111       if( usepath ) {
 112         execvp(argv[0], argv);
 113       }
 114       else {
 115         execv(argv[0], argv);
 116       }
 117       perror("Exec failed: ");
 118       exit(-1);
 119     }
 120   close( PipeEnds[PIP_RD] );
 121   
 122   write( PipeEnds[PIP_WR], msg, strlen(msg) );
 123   close( PipeEnds[PIP_WR] );
 124 
 125   wait(&status);
 126 }
 127 
 128 static
 129 void
 130 er_logtopath(er_path_t *pathptr, char *form, char *msg)
     /* [<][>][^][v][top][bottom][index][help] */
 131 { 
 132   
 133   char fullline[ER_MSGLEN+ER_ERRLEN+4];
 134 
 135   /* MUTEX :
 136 
 137      So, while the most of the work is done composing the message
 138      according to the format set in the path descriptor (mode),
 139      the output should also be locked.
 140 
 141      here the mutex associated with the path should be set.
 142      However, another mutex should be already used to protect other threads 
 143      from reading the path description while it is modified by the master
 144      thread. An RW lock can be used for this.
 145           
 146      Fortunately, fputs is MT-Safe in Solaris.
 147   */
 148  
 149   int fd;
 150 
 151   /* bound checking done already for form & msg */
 152   strcpy(fullline, form);
 153   strcat(fullline, msg);
 154   strcat(fullline, "\n");
 155 
 156   switch(pathptr->type) {
 157   case ER_PATH_SOCK:
 158     fd = pathptr->descr.sock.fd;
 159     if( write(fd, fullline, strlen(fullline)) == -1 ) {
 160       perror("ER logging ");
 161     }    
 162     break;
 163   case ER_PATH_NAME:
 164     {
 165       char *filename;
 166       char constructed[128], datestr[10];
 167       struct timeval tval;
 168       struct tm tmstr;
 169 
 170       if( pathptr->descr.name.date == 0 ) {
 171         filename = pathptr->descr.name.filename;
 172       }
 173       else {  
 174         /* construct the filename for the paths with DATE option */
 175         strcpy( constructed, pathptr->descr.name.filename );
 176 
 177         gettimeofday(&tval, NULL);
 178         localtime_r( & tval.tv_sec,   &tmstr);
 179         strftime(datestr, 10, ".%Y%m%d", &tmstr);
 180 
 181         strcat( constructed, datestr );
 182         filename = constructed;
 183       } 
 184       fd=open(filename, O_WRONLY|O_APPEND|O_CREAT, 0755 );
 185       if( fd > 0 ) {
 186         /* XXX lock ? According to SK, not needed as long as it's on one
 187          machine - the 'append' mode will make sure things are not garbled.
 188         */
 189         if(   write(fd, fullline, strlen(fullline)) == -1 ) {
 190           perror("ER logging ");
 191         }    
 192         /* XXX unlock ? */
 193         close(fd);
 194       }
 195       else {
 196         fprintf(stderr, "ER: cannot open log file %s ",  
 197                 pathptr->descr.name.filename);
 198         perror("");
 199       }
 200     }
 201     break;
 202     
 203   case ER_PATH_EXEC:
 204       er_forkexec(pathptr->descr.exec.argv, 
 205                   fullline, 
 206                   pathptr->descr.exec.usepath );
 207       break;
 208   default:
 209     die; /* not implemented */
 210   }   
 211 }
 212 
 213 void
 214 er_getmsg_parts(char *buf, int buflen, char *fmttxt, va_list args)
     /* [<][>][^][v][top][bottom][index][help] */
 215 {
 216   /* build the error message using vsnprintf */  
 217   vsnprintf(buf, buflen, fmttxt, args);
 218 }
 219 
 220 
 221 
 222 /* TWO CONSTANTS DEFINE THE LENGTH OF STRINGS HERE:
 223    ER_MSGLEN - max length of the line to be logged
 224    ER_ERRLEN - max length of the error message
 225 */
 226 char *er_format_line(char *erbuf, er_fac_code_t  facwhere, 
     /* [<][>][^][v][top][bottom][index][help] */
 227                      er_mask_t asp, int mode,  int errcode, 
 228                      char *tmbuf)
 229 {
 230 int fac, err, sev;
 231 int facidx, erridx;
 232 char thr_str[10], *ermne, *txtlong="";
 233 
 234 /* init to "" */
 235 erbuf[0] = 0;
 236 ermne = "";
 237 
 238 sev = ( errcode & 0xff000000 );         /* not shifted */
 239 fac = ( errcode & 0x00ff0000 ) >> 16;
 240 err = ( errcode & 0x0000ffff );         /* not shifted */
 241 
 242 /* take the overridden value (facwhere) in case of doubt */ 
 243  if(facwhere != fac) {
 244    fac = facwhere;
 245  }
 246 
 247   for (facidx=0; facidx<FAC_LAST; facidx++) {
 248     if( er_fac_err[facidx].code == fac ) {
 249       break;
 250     }
 251   }
 252 
 253   /* now, if we got to the last one and it's not the right one, 
 254      the system is not configured properly */
 255   if(facidx==FAC_LAST) {
 256      assert( er_fac_err[facidx].code == fac );  /* just bail out. */
 257   }
 258 
 259   /* still alive ? OK, build the message ...*/
 260 
 261   /* ... using facidx/erridx if it's not a DEBUG or INFO */
 262   switch( sev ) {
 263     case ER_SEV_D:
 264         ermne = "DEBUG";
 265         break;
 266     case ER_SEV_I:
 267         ermne = "INFO";
 268         break;
 269     default:
 270     /* OK, go to the module table. bail out if not initialized */
 271     assert( er_fac_err[facidx].errs != NULL );
 272 
 273     for(erridx=0; er_fac_err[facidx].errs[erridx].code != -1; erridx++) {
 274       if( er_fac_err[facidx].errs[erridx].code == errcode ) {
 275         /* FOUND! now set the error message format using facidx and erridx */
 276 
 277         /* long error message without arguments */
 278         txtlong = er_fac_err[facidx].errs[erridx].text;
 279         
 280         /* set the mnemonic pointer if necessary */ 
 281         if( mode & ER_M_MNEMONIC ) {
 282           ermne = er_fac_err[facidx].errs[erridx].mnem;
 283         }
 284         break;
 285       }
 286     }
 287     /*  return ""; */
 288     /* no, do not return: bail out if the code is not defined */
 289     assert( er_fac_err[facidx].errs[erridx].code != -1 );
 290   }
 291 
 292   
 293   
 294   sprintf(thr_str, "%d", pthread_self() );
 295 
 296   /* build the actual log message */
 297   snprintf(erbuf, ER_MSGLEN, "%s %s-%s/%s %s-%s-%s %s ",
 298            ( mode & ER_M_DATETIME ) ? tmbuf : "",
 299            (mode & ER_M_PROGNAME) ? er_progname : "",
 300            (mode & ER_M_PIDFULL)  ? er_pid : "",
 301            (mode & ER_M_THR_ID )  ? thr_str : "",
 302            (mode & ER_M_FACSYMB)  ? er_getfacsym(facwhere) : "",
 303            er_getsevsym(sev, mode),
 304            (mode & ER_M_MNEMONIC) ? ermne : "",
 305            (mode & ER_M_TEXTLONG) ? txtlong : ""
 306            );   
 307   return erbuf;
 308 }
 309 
 310 void er_logit(er_fac_code_t  facwhere, er_mask_t asp, int errcode, char *msg)
     /* [<][>][^][v][top][bottom][index][help] */
 311 {
 312   char  formbuf[ER_MSGLEN], tmbuf[32];
 313   struct timeval tval;
 314   struct tm tmstr;
 315 
 316   
 317 
 318   /*er_pathlist_mutex;*/
 319 
 320   {
 321     GList *pitem, *fitem;
 322       
 323     for( pitem = g_list_first(er_pathlist);
 324          pitem != NULL;
 325          pitem = g_list_next(pitem)) {
 326         
 327       er_path_t *pathptr = (er_path_t *)pitem->data;
 328 
 329         
 330       if( pathptr->active ) {
 331 
 332         for( fitem = g_list_first(pathptr->filters);
 333              fitem != NULL;
 334              fitem = g_list_next(fitem)) {
 335           
 336           er_filter_t *filtptr = (er_filter_t *) fitem->data;
 337 
 338           
 339           if( er_msgsel( filtptr, facwhere, asp, errcode) ) {
 340             if ( pathptr->format & ER_M_DATETIME ) {
 341               gettimeofday(&tval, NULL);
 342               
 343               localtime_r( & tval.tv_sec, & tmstr);
 344 
 345               strftime(tmbuf, sizeof(tmbuf), "%Y%m%d %H:%M:%S", &tmstr);
 346             } else {
 347               tmbuf[0]=0;
 348             }
 349             
 350             er_format_line( formbuf, 
 351                             facwhere, asp, pathptr->format, errcode, tmbuf);
 352             
 353             er_logtopath( pathptr, formbuf, msg );
 354             break; /* go to next path */
 355           }
 356         }
 357       }
 358     }
 359   }
 360 }
 361 
 362 /* check if anyone traces this particular aspect for this facility,
 363    whether on DEBUG or INFO level */
 364 int ER_is_traced(er_fac_code_t  facwhere, er_mask_t asp) 
     /* [<][>][^][v][top][bottom][index][help] */
 365 {
 366   return (er_asparray[facwhere] & asp );
 367 }
 368 /* check if anyone traces this particular error for this facility */
 369 int ER_is_errorlogged(er_fac_code_t  facwhere, int errcode)
     /* [<][>][^][v][top][bottom][index][help] */
 370 {
 371 int i = 1;
 372 
 373  return i;
 374 }
 375 
 376 int er_get_printmode(er_path_t *pathstruct) 
     /* [<][>][^][v][top][bottom][index][help] */
 377 {
 378   return pathstruct->format;
 379 }
 380 
 381 void ER_perror(er_fac_code_t  facwhere, int errcode, char *format, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 382 {
 383   char  erbuf[ER_MSGLEN];
 384   va_list ap;
 385 
 386   if( ER_is_errorlogged( facwhere, errcode ) ) {      /* uses pathlist mutex */
 387 
 388     /* now, this takes most time: */
 389     va_start(ap, format);
 390     er_getmsg_parts(erbuf, sizeof(erbuf), format, ap );
 391     va_end(ap);
 392     
 393     /* actually, here will be a loop once there are more paths possible. */
 394     er_logit(facwhere, 
 395            0,                          /* empty aspect mask for errors */
 396            errcode, 
 397            erbuf);                              /* empty debug message */
 398   }
 399 }
 400 
 401 void ER_asp_va(er_fac_code_t  facwhere, int sev,  er_mask_t asp, char *txt, 
     /* [<][>][^][v][top][bottom][index][help] */
 402                 va_list args)
 403 {
 404     char    erbuf[ER_MSGLEN];
 405 
 406     er_getmsg_parts(erbuf, sizeof(erbuf), txt, args );
 407     er_logit(facwhere, asp, sev, erbuf);
 408 }
 409 
 410 void ER_inf_va(er_fac_code_t  facwhere, er_mask_t asp, char *txt, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 411 {
 412     va_list   ap;
 413     va_start(ap, txt);
 414     ER_asp_va( facwhere, ER_SEV_I, asp, txt, ap );
 415     va_end(ap);
 416 }
 417 
 418 
 419 void ER_dbg_va(er_fac_code_t  facwhere, er_mask_t asp, char *txt, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 420 {
 421   char    erbuf[ER_MSGLEN];
 422   va_list   ap;
 423 
 424   if( ER_is_traced( facwhere, asp ) ) {
 425     
 426     va_start(ap, txt);
 427     er_getmsg_parts(erbuf, sizeof(erbuf), txt, ap );
 428     va_end(ap);
 429     
 430     er_logit(facwhere, asp,  ER_SEV_D, erbuf);
 431   }
 432 }
 433 
 434 
 435 /* Set GLOBAL VARIABLES == can be done only by the master thread */
 436 void ER_init(char *progname, int processdefs)
     /* [<][>][^][v][top][bottom][index][help] */
 437 {
 438                        
 439   strncpy(er_progname, progname, 31);
 440   er_progname[31] = 0;
 441 
 442   snprintf(er_pid, 10, "%d", getpid());
 443 
 444   /* now error definitions: first predefine macros */
 445   ER_macro_predef();
 446   /* then override them */
 447   ER_proc_ca_macro();
 448 
 449   if( processdefs ) {
 450     /* now process the definitions if allowed */
 451     ER_proc_ca_err();
 452   }
 453     
 454 }

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