Source File modules/er/er.c

    1    | /***************************************
    2    |   $Revision: 1.8 $
    3    |
    4    |   Error reporting (er) er.c - library of functions to uniformly report errors.
    5    |
    6    |   Status: NOT REVUED, TESTED,
    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   |
    34   | char *er_getsev( int sev, int mode )
    35   | {
    36   | int i;
    37   |
    38   |   for(i=0; er_level_a[i].sev != 0; i++) {
    39   | 	if (er_level_a[i].sev == sev)  {
    40   | 	    break;
    41   | 	}
    42   |   }
    43   |
    44   |   switch( mode & 0x03 ) {
    45   | 	case ER_M_SEVNONE:	/* no severity indication */
    46   | 		return "";	/* "" goes to program text, so returning a
    47   | 				  pointer to it is OK */
    48   | 	case ER_M_SEVCHAR:	/* one-letter severity indication */
    49   | 		return er_level_a[i].chr;
    50   | 	case ER_M_SEVLONG: 	/* long severity indication */
    51   | 		return er_level_a[i].txt;
    52   |   }
    53   |   return "";
    54   | }
    55   |
    56   | char *er_getfacsym(int faccode)
    57   | {
    58   | int facidx;
    59   |
    60   |   if( faccode != FAC_NONE  )  {
    61   |     for (facidx=0; facidx<FAC_LAST; facidx++) {
    62   |       if( er_main_err[facidx].code == faccode ) {
    63   |         break;
    64   |       }
    65   |     }
    66   |     return  er_main_err[facidx].name;
    67   |   }
    68   |   else	return "";
    69   | }
    70   |
    71   | /* TWO CONSTANTS DEFINE THE LENGTH OF STRINGS HERE:
    72   |    ER_MSGLEN - max length of the line to be logged
    73   |    ER_ERRLEN - max length of the error message
    74   | */
    75   | char *er_getmsg_parts(int facwhere, int errcode, int mode,
    76   | 			char *buf, char *fmttxt, va_list args)
    77   | {
    78   | int fac, err, sev;
    79   | int facidx, erridx;
    80   | char erbuf[ER_ERRLEN], thr_str[10], *ermne;
    81   |
    82   | /* init to "" */
    83   | erbuf[0] = 0;
    84   | ermne = "";
    85   |
    86   | sev = ( errcode & 0xff000000 );		/* not shifted */
    87   | fac = ( errcode & 0x00ff0000 ) >> 16;
    88   | err = ( errcode & 0x0000ffff );		/* not shifted */
    89   |
    90   |   for (facidx=0; facidx<FAC_LAST; facidx++) {
    91   |     if( er_main_err[facidx].code == fac ) {
    92   |       break;
    93   |     }
    94   |   }
    95   |
    96   |   /* now, if we got to the last one and it's not the right one,
    97   |      the system is not configured properly */
    98   |   if(facidx==FAC_LAST) {
    99   |      assert( er_main_err[facidx].code == fac );	/* just bail out. */
    100  |   }
    101  |
    102  |   /* still alive ? OK, build the message ...*/
    103  |
    104  |   /* ... using facidx/erridx if it's not a DEBUG */
    105  |   if( sev != ER_SEV_D ) {
    106  |     /* OK, go to the module table. bail out if not initialized */
    107  |     assert( er_main_err[facidx].errs != NULL );
    108  |
    109  |     for(erridx=0; er_main_err[facidx].errs[erridx].code != -1; erridx++) {
    110  |       if( er_main_err[facidx].errs[erridx].code == errcode ) {
    111  |        	/* FOUND! now set the error message format using facidx and erridx */
    112  |
    113  |     	/* build error message with arguments */
    114  |     	if( mode & ER_M_TEXTLONG ) {
    115  | 	  fmttxt = er_main_err[facidx].errs[erridx].text;
    116  |     	}
    117  | 	/* set the mnemonic pointer if necessary */
    118  | 	if( mode & ER_M_MNEMONIC ) {
    119  | 	  ermne = er_main_err[facidx].errs[erridx].mnem;
    120  |         }
    121  | 	break;
    122  |       }
    123  |     }
    124  |     /*	return ""; */
    125  |     /* no, do not return: bail out if the code is not defined */
    126  |     assert( er_main_err[facidx].errs[erridx].code != -1 );
    127  |   }
    128  |   else {
    129  |     ermne = "DEBUG";
    130  |   }
    131  |
    132  |   /* build the error message using vsnprintf */
    133  |   vsnprintf(erbuf, ER_ERRLEN, fmttxt, args);
    134  |
    135  |   sprintf(thr_str, "%d", pthread_self() );
    136  |
    137  |   /* build the actual log message */
    138  |   snprintf(buf, ER_MSGLEN, "%s-%s/%s %s-%s-%s %s",
    139  | 	   (mode & ER_M_PROGNAME) ? er_progname : "",
    140  | 	   (mode & ER_M_PIDFULL)  ? er_pid : "",
    141  | 	   (mode & ER_M_THR_ID )  ? thr_str : "",
    142  | 	   (mode & ER_M_FACSYMB)  ? er_getfacsym(facwhere) : "",
    143  | 	   er_getsev(sev, mode),
    144  | 	   ermne,
    145  | 	   erbuf
    146  | 	   );
    147  |   return buf;
    148  | }
    149  |
    150  | void ER_setpath(er_path_t *newset)
    151  | {
    152  |   /* initialise the mutex if not yet initialised */
    153  |
    154  |   if( er_pathlist_mutex_initialised == 0 ) {
    155  |     pthread_mutex_init( &er_pathlist_mutex, NULL );
    156  |   }
    157  |
    158  |   pthread_mutex_lock( &er_pathlist_mutex );
    159  |   memcpy( & er_provisional_struct, newset, sizeof(er_path_t));
    160  |   pthread_mutex_unlock( &er_pathlist_mutex );
    161  | }
    162  |
    163  | void er_logit(int facwhere, er_mask_t asp, int mode, int errcode, char *msg)
    164  | {
    165  |   char 	buf[ER_MSGLEN], tmbuf[32];
    166  |   struct timeval tval;
    167  |   struct tm tmstr;
    168  |
    169  |   if ( mode & ER_M_DATETIME ) {
    170  |     gettimeofday(&tval, NULL);
    171  |     localtime_r( & tval.tv_sec, & tmstr);
    172  |
    173  |     /*    strcpy(tmbuf, ctime(&tm)+11); */
    174  |     sprintf(tmbuf, "%02d:%02d:%02d",
    175  | 	    tmstr.tm_hour, tmstr.tm_min, tmstr.tm_sec);
    176  |   } else {
    177  |     tmbuf[0]=0;
    178  |   }
    179  |
    180  |   snprintf(buf, ER_MSGLEN, "%s %s\n", tmbuf, msg );
    181  |   /* OK, now dispatch the message to all different paths */
    182  |
    183  |   /* MUTEX :
    184  |
    185  |      So, while the most of the work is done composing the message
    186  |      according to the format set in the path descriptor (mode),
    187  |      the output should also be locked.
    188  |
    189  |      here the mutex associated with the path should be set.
    190  |      However, another mutex should be already used to protect other threads
    191  |      from reading the path description while it is modified by the master
    192  |      thread. An RW lock can be used for this.
    193  |
    194  |      Fortunately, fputs is MT-Safe in Solaris.
    195  |   */
    196  |
    197  |
    198  |   /* for now we have at most one :-) */
    199  |   if(  er_provisional_struct.fdes == NULL ) {
    200  |     fputs(buf,stderr);
    201  |   }
    202  |   else {
    203  |     /* someone has really set something! */
    204  |     if( errcode >= er_provisional_struct.sev
    205  | 	|| asp & er_provisional_struct.asp
    206  | 	)
    207  |       {
    208  | 	fputs(buf, er_provisional_struct.fdes);
    209  |       }
    210  |   }
    211  |
    212  |
    213  |
    214  | }
    215  |
    216  |
    217  | int ER_is_traced(int facwhere, er_mask_t asp)
    218  | {
    219  | int i;
    220  |
    221  |   /* pthread_mutex_lock( &er_pathlist_mutex ); */
    222  |   i = er_provisional_struct.asp;
    223  |   /* pthread_mutex_unlock( &er_pathlist_mutex ); */
    224  |
    225  |   i &= asp;
    226  |   return i;
    227  | }
    228  |
    229  | int ER_anybody_wants( int facwhere, int errcode, er_mask_t asp )
    230  | {
    231  | int i;
    232  |
    233  |   pthread_mutex_lock( &er_pathlist_mutex );
    234  |   i = ( errcode >= er_provisional_struct.sev );
    235  |   pthread_mutex_unlock( &er_pathlist_mutex );
    236  |
    237  |   return i;
    238  | }
    239  |
    240  | int er_get_printmode(er_path_t *pathstruct)
    241  | {
    242  | int i;
    243  |
    244  |   pthread_mutex_lock( &er_pathlist_mutex );
    245  |   if(  pathstruct->fdes == NULL ) {
    246  |     /* default mode */
    247  |     i = ER_M_DEFAULT;
    248  |   }
    249  |   else {
    250  |     i = pathstruct->mode;
    251  |   }
    252  |   pthread_mutex_unlock( &er_pathlist_mutex );
    253  |
    254  |   return i;
    255  | }
    256  |
    257  | void ER_perror(int facwhere, int errcode, ...)
    258  | {
    259  |   char 	erbuf[ER_MSGLEN];
    260  |   int     pmode;
    261  |   va_list ap;
    262  |
    263  |   if( ER_anybody_wants( facwhere, errcode, 0 ) ) {      /* uses pathlist mutex */
    264  |
    265  |     pmode = er_get_printmode( & er_provisional_struct );/* uses pathlist mutex */
    266  |
    267  |     /* now, this takes most time: */
    268  |     va_start(ap, errcode);
    269  |     er_getmsg_parts(facwhere, errcode, pmode, erbuf, NULL, ap );
    270  |     va_end(ap);
    271  |
    272  |     /* actually, here will be a loop once there are more paths possible. */
    273  |     er_logit(facwhere,
    274  | 	   0,			       /* empty aspect mask for errors */
    275  | 	   pmode,
    276  | 	   errcode,
    277  | 	   erbuf);				/* empty debug message */
    278  |   }
    279  | }
    280  |
    281  | void ER_dbg_va( int facwhere, er_mask_t asp, char *txt, ...)
    282  | {
    283  |   char    erbuf[ER_MSGLEN];
    284  |   int pmode;
    285  |   va_list   ap;
    286  |
    287  |   if( ER_is_traced( facwhere, asp ) ) {
    288  |
    289  |     pmode = er_get_printmode( & er_provisional_struct );
    290  |
    291  |     va_start(ap, txt);
    292  |     er_getmsg_parts(facwhere, ER_SEV_D, pmode, erbuf, txt, ap );
    293  |     va_end(ap);
    294  |
    295  |     er_logit(facwhere, asp, pmode, ER_SEV_D, erbuf);
    296  |   }
    297  | }
    298  |
    299  |
    300  | /* Set GLOBAL VARIABLES == can be done only by the master thread */
    301  | void ER_init(int argc, char **argv)
    302  | {
    303  | char *er_slash;
    304  |
    305  |   er_slash = rindex(argv[0],'/');
    306  |   strncpy(er_progname, (er_slash != NULL) ? er_slash+1 : argv[0], 31);
    307  |   er_progname[31] = 0;
    308  |
    309  |   snprintf(er_pid, 10, "%d", getpid());
    310  |
    311  | }