/* $Id: tail.c,v 1.14 2004/03/27 13:05:10 doug Exp $
*
* This file is part of EXACT.
*
* EXACT is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* EXACT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EXACT; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "config.h" /* autoconf generated */
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
/* autoconf default include instructions */
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#include "conffile.h"
#include "logger.h"
#define PAWS_MAX (1 * 1000000)
FILE *f;
unsigned long paws; // useconds
time_t last;
char *tail_buff;
unsigned int tail_bufflen;
// taken from comp.unix.questions FAQ
// http://www.faqs.org/faqs/unix-faq/faq/part4/
// used to avoid usleep/SIGALRM issues
int nap(long usec){
struct timeval tv;
tv.tv_sec = usec / 1000000L;
tv.tv_usec = usec % 1000000L;
return(select(0,NULL,NULL,NULL,&tv));
}
int tail_open() {
f=fopen(conffile_param("maillog"),"r");
last=time(NULL);
paws=PAWS_MAX;
if(f) {
fseek(f,0,SEEK_END);
tail_buff=malloc(1024);
}
return(f!=NULL);
}
int linecount(char *buff, int len) {
int i;
int ctr=0;
for(i=0;i<len;++i) {
if(buff[i]=='\n') ctr++;
}
return(ctr);
}
void tail_reopen(long current) {
long end;
if(f) fclose(f);
logger(LOG_DEBUG,"suspicious about file, reopening\n");
// We should really check the file for various exceptional conditions
// before opening - check for existence, then permissions, then size
f=fopen(conffile_param("maillog"),"r");
if(!f) {
logger(LOG_NOTICE, "log file '%s' has disappeared.\n",conffile_param("maillog"));
f=NULL;
return;
}
fseek(f,0,SEEK_END);
end=ftell(f);
if(end<current) { // the file has been rotated
logger(LOG_DEBUG,"the file has been rotated.\n");
if(fseek(f,0,SEEK_SET)==-1) {
logger(LOG_ERR, "Unable to seek to beginning of logfile\n");
exit(71);
}
} else { // it hasn't
logger(LOG_DEBUG, "the file hasn't been rotated\n");
if(fseek(f,current,SEEK_SET)==-1) {
logger(LOG_ERR, "Unable to seek to end of logfile\n");
exit(71);
}
}
}
char *tail_read() {
long current,end;
size_t read;
unsigned int lines;
if(f==NULL) {
tail_reopen(0);
last=time(NULL);
tail_bufflen=0;
nap(paws);
return tail_buff;
}
nap(paws);
current=ftell(f);
if(fseek(f,0,SEEK_END)==-1) {
logger(LOG_ERR, "Unable to seek to end of logfile\n");
exit(71);
}
end=ftell(f);
if(fseek(f,current,SEEK_SET)==-1) {
logger(LOG_ERR, "Unable to seek to current position\n");
exit(72);
}
if(end>current)
last=time(NULL);
if(time(NULL) - last > conffile_param_int("suspicious")) {
tail_reopen(current);
last=time(NULL);
tail_bufflen=0;
return tail_buff;
}
tail_bufflen=end-current;
logger(LOG_DEBUG,"%ld bytes added to file\n", tail_bufflen);
if(tail_bufflen>0) {
tail_buff=(char *)realloc(tail_buff,tail_bufflen+1);
}
if(!tail_buff) {
logger(LOG_ERR,"unable to realloc %d bytes\n", tail_bufflen);
exit(30);
}
read=fread(tail_buff,1,tail_bufflen,f);
if(read!=tail_bufflen) {
logger(LOG_ERR,"read %d bytes, wanted %d bytes\n", read, tail_bufflen);
exit(31);
}
tail_buff[tail_bufflen]='\0'; // zero terminate it, so it can be matched
lines=linecount(tail_buff,tail_bufflen);
logger(LOG_DEBUG, "read %d lines with a pause of %ld usecs\n", lines, paws);
if(lines>0) {
// try and read one line per pause
paws=paws/lines;
// integer arithmetic issues
if(paws==0) paws=1;
} else {
// exponential back off to a maximum
paws=paws*2;
paws=paws > PAWS_MAX ? PAWS_MAX : paws;
}
return(tail_buff);
}
syntax highlighted by Code2HTML, v. 0.9.1