Source File modules/er/er.c

    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)
    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  |     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)
    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 )
    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)
    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, ...)
    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,
    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, ...)
    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, ...)
    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)
    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  | }