## 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] */