Back to index

nagios-plugins  1.4.16
Classes | Defines | Functions | Variables
fetchlog.c File Reference
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>

Go to the source code of this file.

Classes

struct  bookmark

Defines

#define LINELEN   160 /* max length of a logfile line we will read */
#define MIN_FIRSTCOL   1 /* Min first col for fetching */
#define MAX_LASTCOL   LINELEN /* Max last col for fetching */
#define MIN_COLS   20 /* Min no of cols to fetch */
#define MIN_FETCHLEN   50 /* Min length of fetched data */
#define MAX_FETCHLEN   2000 /* Max length of fetched data */
#define OK_MESSAGE   "OK: no messages"
#define ERR_MESSAGE   "ERROR: fetchlog: "
#define FETCH_FILE_SUFFIX   "XXXXXX"
#define CONV_NONE   0
#define CONV_BRACKET   1
#define CONV_PERCENT   2
#define CONV_NEWLINE   4
#define CONV_OKMSG   8
#define CONV_SHELL   16
#define CONV_ALL   (CONV_BRACKET|CONV_PERCENT|CONV_NEWLINE|CONV_OKMSG|CONV_SHELL )
#define RET_OK   0 /* ok, no messages ok */
#define RET_ERROR   1 /* internal error warn */
#define RET_NEWMSG   2 /* logfile has new messages critical */
#define RET_PARAM   3 /* wrong parameter, print help */
#define FL_VERSION   FETCHLOG_VERSION_NO

Functions

void usage (void)
int fetch_logfile (char *logfilename, char *bookmarkfile, int updbm_flag)
int read_bookmark (char *bmfile, bookmark *bm)
int write_bookmark (char *bmfile, bookmark *bm)
int copyline (int opos, char *obuf, char *ipt, int illen)
int check_farg (char *farg, int *conv)
void perr (char *msg1, char *msg2, int err)
int main (int argc, char **argv)

Variables

int firstcol_G = MIN_FIRSTCOL
int lastcol_G = MAX_LASTCOL
int fetchlen_G = MAX_FETCHLEN
int conv_G = CONV_NONE

Class Documentation

struct bookmark

Definition at line 97 of file fetchlog.c.

Class Members
long last
char line
long linelen
time_t mtime
long start

Define Documentation

Definition at line 70 of file fetchlog.c.

#define CONV_BRACKET   1

Definition at line 65 of file fetchlog.c.

#define CONV_NEWLINE   4

Definition at line 67 of file fetchlog.c.

#define CONV_NONE   0

Definition at line 64 of file fetchlog.c.

#define CONV_OKMSG   8

Definition at line 68 of file fetchlog.c.

#define CONV_PERCENT   2

Definition at line 66 of file fetchlog.c.

#define CONV_SHELL   16

Definition at line 69 of file fetchlog.c.

#define ERR_MESSAGE   "ERROR: fetchlog: "

Definition at line 58 of file fetchlog.c.

#define FETCH_FILE_SUFFIX   "XXXXXX"

Definition at line 61 of file fetchlog.c.

#define FL_VERSION   FETCHLOG_VERSION_NO

Definition at line 91 of file fetchlog.c.

#define LINELEN   160 /* max length of a logfile line we will read */

Definition at line 49 of file fetchlog.c.

#define MAX_FETCHLEN   2000 /* Max length of fetched data */

Definition at line 55 of file fetchlog.c.

#define MAX_LASTCOL   LINELEN /* Max last col for fetching */

Definition at line 52 of file fetchlog.c.

#define MIN_COLS   20 /* Min no of cols to fetch */

Definition at line 53 of file fetchlog.c.

#define MIN_FETCHLEN   50 /* Min length of fetched data */

Definition at line 54 of file fetchlog.c.

#define MIN_FIRSTCOL   1 /* Min first col for fetching */

Definition at line 51 of file fetchlog.c.

#define OK_MESSAGE   "OK: no messages"

Definition at line 57 of file fetchlog.c.

#define RET_ERROR   1 /* internal error warn */

Definition at line 82 of file fetchlog.c.

#define RET_NEWMSG   2 /* logfile has new messages critical */

Definition at line 83 of file fetchlog.c.

#define RET_OK   0 /* ok, no messages ok */

Definition at line 81 of file fetchlog.c.

#define RET_PARAM   3 /* wrong parameter, print help */

Definition at line 84 of file fetchlog.c.


Function Documentation

int check_farg ( char *  farg,
int *  conv 
)

Definition at line 577 of file fetchlog.c.

                                        {
    char *pt = farg;
    int numdig = 0;
    int numc = 0;

    *conv = 0;

    for( numdig=0 ; *pt; pt++ ) {
       if( isdigit( (int) *pt ) ) numdig++;
       else if( *pt==':' ) break;
       else return 1;
    }
    if( numdig <1 || numdig > 3 ) return 1;

    for( pt++,numdig=0 ; *pt; pt++ ) {
       if( isdigit( (int) *pt ) ) numdig++;
       else if( *pt==':' ) break;
       else return 1;
    }
    if( numdig <1 || numdig > 3 ) return 1;

    for( pt++,numdig=0 ; *pt; pt++ ) {
       if( isdigit( (int) *pt ) ) numdig++;
       else if( *pt==':' ) break;
       else return 1;
    }
    if( numdig <1 || numdig > 4 ) return 1;

    for( pt++,numc=0 ; *pt; pt++ ) {
       if     ( *pt=='b' ) { *conv |= CONV_BRACKET; numc++; }
       else if( *pt=='p' ) { *conv |= CONV_PERCENT; numc++; }
       else if( *pt=='n' ) { *conv |= CONV_NEWLINE; numc++; }
       else if( *pt=='o' ) { *conv |= CONV_OKMSG;   numc++; }
       else if( *pt=='s' ) { *conv |= CONV_SHELL;   numc++; }
       else return 1;
    }
    if( numc > 5 ) return 1;
    return 0; /* ok */

}   /* check_farg() */

Here is the caller graph for this function:

int copyline ( int  opos,
char *  obuf,
char *  ipt,
int  illen 
)

Definition at line 470 of file fetchlog.c.

                                                           {

    char *p = NULL;
    int len = 0;
    int i;

    if( conv_G & CONV_NEWLINE ) {
       /* fill obuf: 
          prepend  concat( '\\' + 'n' + iline )   (newline sequence first) */
       if( opos > 2 ) {
           if( illen <= firstcol_G ) {
              *(obuf+opos-1) = 'n'; *(obuf+opos-2) = '\\'; 
              opos -= 2;
           }else{
              len = illen - 1;  /* -1 : skip newline */
              /* Note: lastcol_G means 'show inklusive column lastcol' */
              if( len > lastcol_G+1 )  len = lastcol_G;
              len -= firstcol_G - 1;
              if( len+2 > opos ) {
                  memcpy( obuf+2, ipt+firstcol_G-1+len+2-opos, opos-2 );
                  len = opos - 2;
              }else{
                  memcpy( obuf+opos-len, ipt+firstcol_G-1, len );
              }
              if( illen-1 > lastcol_G+1 ) *(obuf+opos-1) = '~';
              opos -= len+2;
              *(obuf+opos+1) = 'n'; 
              *(obuf+opos+0) = '\\'; 
           }
       }else{
           opos = 0;
       }
       if( opos==0 ) {
           p = obuf;
           *p++='\\'; *p++='n'; *p++='.'; *p++='.'; *p++='.';
           if( obuf[5]=='n' ) { *p++='.'; }
       }
    }else{
       /* without newline conversion */

       /* fill obuf: 
          prepend concat( iline + '\n' )  (newline char last) */
       if( opos > 1 ) {
           if( illen <= firstcol_G ) {
              *(obuf+opos-1) = '\n'; 
              opos -= 1;
           }else{
              len = illen - 1;  /* -1 : skip newline */
              /* Note: lastcol_G means 'show inklusive column lastcol' */
              if( len > lastcol_G+1 )  len = lastcol_G;
              len -= firstcol_G - 1;
              if( len+1 > opos ) {
                  memcpy( obuf, ipt+firstcol_G-1+len+1-opos, opos-1 );
                  len = opos - 1;
              }else{
                  memcpy( obuf+opos-len-1, ipt+firstcol_G-1, len );
              }
              *(obuf+opos-1) = '\n'; 
              if( illen-1 > lastcol_G+1 ) *(obuf+opos-2) = '~';
              opos -= len+1;
           }
       }else{
           opos = 0;
       }
       if( opos==0 ) {
           p = obuf;
           *p++='.'; *p++='.'; *p++='.';
       }
    }

    p = obuf+opos;
    if( conv_G & CONV_NEWLINE )  p += 2;  /* +2: skip '\\' 'n' */

    if( conv_G & CONV_PERCENT ) {
       for( i=0; i<len; i++ ) {
           if( *(p+i) == '%' ) *(p+i) = 'p';
       }
    }

    if( conv_G & CONV_BRACKET ) {
       for( i=0; i<len; i++ ) {
           if(      *(p+i) == '<' ) *(p+i) = '(';
           else if( *(p+i) == '>' ) *(p+i) = ')';
       }
    }

    if( conv_G & CONV_SHELL ) {
       for( i=0; i<len; i++ ) {
           if(      *(p+i) == '$' )  *(p+i) = '_';
           else if( *(p+i) == '\'' ) *(p+i) = '_';
           else if( *(p+i) == '\"' ) *(p+i) = '_';
           else if( *(p+i) == '`' )  *(p+i) = '_';
           else if( *(p+i) == '^' )  *(p+i) = '_';
           else if( *(p+i) == '\\' ) *(p+i) = '/';
       }
    }

    return opos;

}   /* copyline() */

Here is the caller graph for this function:

int fetch_logfile ( char *  logfilename,
char *  bookmarkfile,
int  updbm_flag 
)

Definition at line 272 of file fetchlog.c.

                                                                 {

    bookmark obm, nbm;             /* old, new bookmark */

    char *ibuf = NULL;             /* input buf (--> the logfile) */
    size_t ilen = 0;
    char *ipt  = NULL;
    char *bmpt = NULL;             /* points to first new char if bm exists */

    char *obuf = NULL;             /* output buf (filled backwards) */
    int opos;               /* first used char pos in obuf */

    int i;
    int fd = -1;
    struct stat sb;
    char *lgfile = NULL;
    int llen = 0;
    int done = 0;
    int logfiletouch = 0;   /* 1: logfile only touched, nothing appended */

    memset( obm.line, 0, LINELEN );
    memset( nbm.line, 0, LINELEN );
    nbm.start = -1;
    nbm.last = -1;
    nbm.linelen = 0;
    nbm.mtime = 0;

    if( read_bookmark( bmfile, &obm ) ) return RET_ERROR;

    if( (fd=open( logfile, O_RDONLY ))  == -1 ) {
       perr( "open", logfile, errno );
       return RET_ERROR;
    }
    if( fstat( fd, &sb ) == -1 ) {
       perr( "stat", logfile, errno );
       close( fd );
       return RET_ERROR;
    }
    if( obm.mtime == sb.st_mtime ) {
       if( conv_G & CONV_OKMSG ) 
           write( STDOUT_FILENO, OK_MESSAGE "\n", sizeof( OK_MESSAGE ) );
       close( fd );
       return RET_OK;
    }
    nbm.mtime = sb.st_mtime;

    /*****************/

    obuf = malloc( fetchlen_G+1 );
    if( obuf == NULL ) {
       perr( "malloc", NULL,  errno );
       close( fd );
       return RET_ERROR;
    }
    opos = fetchlen_G;
    *(obuf + opos) = '\0';  /* dummy: opos -> first used char in obuf */
    if( conv_G & CONV_NEWLINE ) {
       /* when using CONV_NEWLINE the obuf is filled up like this:
            1. init: write '\\'  'n'  '\n' to the end (3 chars)
            2. fill (copyline() ) by first prepend line contents and 
              then prepend '\\' 'n'
            result: An additional '\\'  'n'  at the beginning 
          else
            1. fill (copyline() ) by first prepend newline and then prepend 
              line contents 
       */
       *(obuf + --opos) = '\n';
       *(obuf + --opos) = 'n';
       *(obuf + --opos) = '\\';
    }

    lgfile = (char*)malloc( strlen(logfile) + sizeof(".X") );
    if( lgfile == NULL ) {
       free( obuf );
       perr( "malloc", NULL, errno );
       close( fd );
       return RET_ERROR;
    }

    /* read in all logfiles and backward fill obuf upto fetchlen_G chars */

    for( i=-1; i<10; i++ ) {
       /* i==-1: logfile without suffix, else i==logfile suffix */
       if( i==-1 ) {
           /* lgfile is already open and sb contains the stat */
           strcpy( lgfile, logfile );
       }else{
           sprintf( lgfile, "%s.%1d", logfile, i );
       
           if( (fd=open( lgfile, O_RDONLY )) == -1 ) {
              if( errno==ENOENT && i>-1 ) { break; }
              else{
                  perr( "open", lgfile, errno );
                  free( obuf ); free( lgfile );
                  return RET_ERROR;
              }
           }
           if( fstat( fd, &sb ) == -1 ) {
              perr( "stat", lgfile, errno );
              free( obuf ); free( lgfile ); close( fd );
              return RET_ERROR;
           }
       }
       
       ilen = (size_t) sb.st_size;
       if( ilen == 0 ) {
           close( fd );
           continue;
       }
       ibuf = mmap( NULL, ilen, PROT_READ, MAP_SHARED, fd, (off_t)0 );
       if( ibuf == MAP_FAILED ) {
           perr( "mmap", lgfile, errno );
           free( obuf ); free( lgfile ); close( fd );
           return RET_ERROR;
       }
       
#ifndef NO_MADVISE
       if( madvise( ibuf, ilen, MADV_RANDOM ) ) {
           perr( "madvise", NULL, errno );
           free( obuf ); free( lgfile ); close( fd );
           munmap( ibuf, ilen );
           return RET_ERROR;
       }
#endif
       
       /* setup data for new bookmark */
       if( nbm.start == -1 ) {
           for( ipt=ibuf+ilen-2; ipt>=ibuf; ipt-- ) {
              if( *ipt=='\n' ) break;
           }
           nbm.last = ilen;
           nbm.start = ipt-ibuf+1;
           nbm.linelen = ibuf+ilen-(ipt+1);
           if( nbm.linelen > LINELEN ) nbm.linelen = LINELEN;
           memcpy( nbm.line, ipt+1, nbm.linelen );
       }

       /* check for old bookmark */
       bmpt = NULL;
       if( obm.mtime && obm.start+obm.linelen<=ilen && 
           !memcmp( obm.line, ibuf+obm.start, obm.linelen ) ) 
       {
           /* stop if 1st logfile modified but nothing append since last bm */
           if( i==-1 && obm.last==ilen ) { 
              logfiletouch = 1;
              munmap( ibuf, ilen );
              close( fd );
              break;
           }else{
              bmpt = ibuf+obm.last;
           }
       }

       /* scan backwards for lines but the first */
       done = 0;
       for( llen=1,ipt=ibuf+ilen-2; ipt>=ibuf; llen++,ipt-- ) {
           if( *ipt=='\n' ) {
              if( ipt+1<bmpt ) { done=1; break; }
              opos = copyline( opos, obuf, ipt+1, llen );
              if( opos==0 ) { done=1; break; }
              llen = 0;
           }
       }
       if( ipt+1==ibuf && done==0 ) {     /* copy first line ? */
           if( ipt+1<bmpt ) { done=1; }
           else{ opos = copyline( opos, obuf, ipt+1, llen ); }
           if( opos==0 ) { done=1; }
       }

       munmap( ibuf, ilen );
       close( fd );
       if( done ) break;
    }

    if( updbm_flag && nbm.start != -1 ) {
       if( write_bookmark( bmfile, &nbm ) ) return RET_ERROR;
    }

    if( logfiletouch ) {
       if( conv_G & CONV_OKMSG ) 
           write( STDOUT_FILENO, OK_MESSAGE "\n", sizeof( OK_MESSAGE ) );
       free( obuf ); free( lgfile );
       return RET_OK;
    }else{
       write( STDOUT_FILENO, obuf+opos,fetchlen_G-opos);
    }

    free( obuf ); free( lgfile );
    return RET_NEWMSG;

}   /* fetch_logfile() */

Here is the call graph for this function:

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 653 of file fetchlog.c.

{
    int  ret=0;

    /* check args */
    if (argc == 2) {
       if( argv[1][0] == '-' && argv[1][1] == 'V' ) {
           printf( "fetchlog version %s \n", FL_VERSION );
           exit( RET_PARAM );
       }
    }else if (argc == 5) {
       if( argv[1][0] == '-' && 
           argv[3][0] == '/' && isalpha((int)argv[3][1]) &&
           argv[4][0] == '/' && isalpha((int)argv[4][1]) ) {
           if( argv[1][1] == 'f' || argv[1][1] == 'F' ) {
              if( check_farg( argv[2], &conv_G ) ) {
                  usage();
                  exit( RET_PARAM );
              }
              ret = sscanf( argv[2], "%3d:%3d:%4d", 
                           &firstcol_G, &lastcol_G, &fetchlen_G );
              if( ret != 3 ) {
                  usage();
                  exit( RET_PARAM );
              }
              if( firstcol_G >= MIN_FIRSTCOL &&
                  lastcol_G >= firstcol_G + MIN_COLS &&
                  lastcol_G <= MAX_LASTCOL &&
                  fetchlen_G >= MIN_FETCHLEN &&
                  fetchlen_G <= MAX_FETCHLEN ) {
                  
                  if( argv[1][1] == 'f' ) {
                     exit( fetch_logfile( argv[3], argv[4], 0 ) );
                  }else{
                     exit( fetch_logfile( argv[3], argv[4], 1 ) );
                  }
              }
           }
       }
    }
    usage();
    exit( RET_PARAM );

}   /* main() */

Here is the call graph for this function:

void perr ( char *  msg1,
char *  msg2,
int  err 
)

Definition at line 137 of file fetchlog.c.

                                             {
    char *msg = NULL;
    int len = 0;

    if( !msg1 ) return;

    len = sizeof( ERR_MESSAGE ) + strlen( msg1 ) + 1;   /* 1 == '\n' */
    if( msg2 ) len += strlen( msg2 ) + 2;        /* 2 == ': ' */
    if( err ) len += strlen( strerror( err ) ) + 2;     /* 2 == ': ' */

    if( (msg=malloc( len ) ) == NULL ) { exit( RET_ERROR ); }

    strcpy( msg, ERR_MESSAGE );
    strcat( msg, msg1 );
    if( msg2 ) {
       strcat( msg, ": " );
       strcat( msg, msg2 );
    }
    if( err ) {
       strcat( msg, ": " );
       strcat( msg, strerror( err ) );
    }
    if( len-1 <= fetchlen_G ) {
       strcat( msg, "\n" );
    }else{
       msg[fetchlen_G-1] = '\n';
       msg[fetchlen_G-2] = '~';
       len = fetchlen_G + 1;
    }
    write( STDOUT_FILENO, msg, len-1 );
    free( msg );
}

Here is the caller graph for this function:

int read_bookmark ( char *  bmfile,
bookmark bm 
)

Definition at line 175 of file fetchlog.c.

                                                {
    int fd = -1;
    struct stat sb;

    fd = open( bmfile, O_RDONLY );
    if( fd == -1 ) {
       if( errno == ENOENT ) {
           /* no bookmarkfile --> acts like infinite old bookmarkfile */
           bm->start = -1;
           bm->last = -1;
           bm->linelen = 0;
           bm->line[0] = '\0';
           bm->mtime = 0;
           return 0;
       }else{
           perr( "open", bmfile, errno );
           return 1;
       }
    }
    if( fstat( fd, &sb ) == -1 ) {
       perr( "stat", bmfile, errno );
       close( fd );
       return 1;
    }
    if( (int)sb.st_size != sizeof(bookmark) || 
       ((sb.st_mode & S_IFMT) != S_IFREG) ) 
    {
       perr( "no file/wrong size", bmfile, 0);
       close( fd );
       return 1;
    }
    if( read( fd, bm, sizeof(bookmark)) != sizeof( bookmark ) ) {
       perr( "file to short", bmfile, 0 );
       close( fd );
       return 1;
    }
    close( fd );
    
    if( bm->start < 0 || bm->last < 0 || 
       bm->linelen < 0 || bm->linelen > LINELEN ) 
    {
       perr( "file damaged", bmfile, 0 );
       return 1;
    }
    return 0;  /* ok */

}   /* read_bookmark() */

Here is the call graph for this function:

Here is the caller graph for this function:

void usage ( void  )
int write_bookmark ( char *  bmfile,
bookmark bm 
)

Definition at line 229 of file fetchlog.c.

                                                 {

    char *nbmfile = NULL; /* new bmfile (a tmp file to be renamed to bmfile) */
    int nbmfd = -1;

    nbmfile = (char*)malloc( strlen(bmfile) + sizeof(FETCH_FILE_SUFFIX) );
    if( nbmfile == NULL ) {
       perr("malloc", NULL, errno );
       return 1;
    }
    strcpy( nbmfile, bmfile );
    strcat( nbmfile, FETCH_FILE_SUFFIX );
    nbmfd = mkstemp( nbmfile );
    if( nbmfd == -1 ) {
       perr( "mkstemp", nbmfile, errno );
       free( nbmfile );
       return 1;
    }
    if( write( nbmfd, bm, sizeof( bookmark ) ) != sizeof( bookmark )  ) {
       perr( "write", nbmfile, errno );
       close( nbmfd );
       unlink( nbmfile );
       free( nbmfile );
       return 1;
    }
    close( nbmfd );
    if( rename( nbmfile, bmfile ) == -1 ) { 
       perr( "rename tmpfile to", bmfile, errno );
       unlink( nbmfile );
       free( nbmfile );
       return 1;
    }
    free( nbmfile );
    return 0; /* ok */
    
}   /* write_bookmark() */

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 124 of file fetchlog.c.

Definition at line 123 of file fetchlog.c.

Definition at line 121 of file fetchlog.c.

Definition at line 122 of file fetchlog.c.