## 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.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)
         /* [<][>][^][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
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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 )
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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, ...)
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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, ...)
         /* [<][>][^][v][top][bottom][index][help] */
     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, ...)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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 }

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