/******************************************************************************
* $Id: log.c,v 1.12 2006/01/15 19:43:12 gareuselesinge Exp $
* This file is part of liberopops (http://liberopops.sf.net) *
* This file is distributed under the terms of GNU GPL license. *
******************************************************************************/
/******************************************************************************
* File description:
* Implements logging function
* Notes:
*
* Authors:
* Simone Vellei <simone_vellei@users.sourceforge.net>
******************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#include <errno.h>
#include <pthread.h>
#include <math.h>
#include "regularexp.h"
#include "log.h"
#define LOG_ZONE "LOG"
#define HIDDEN static
#define OPENLOG_NAME "freepopsd"
//! max of two
#ifndef MAX
#define MAX(a,b) ((a<b)?(b):(a))
#endif
//! len
#define B(n) floor(MAX(log10(n),0) + 1)
/******************************************************************************/
HIDDEN int verbose_output = 0;
HIDDEN FILE *fd = NULL;
HIDDEN char *log_file_name = NULL;
#ifndef WIN32
HIDDEN int do_syslog = 0;
#endif
#define ZONE_POSTPEND ": "
#define MAX_LOG_FILE_NEMBER 100
#define LOG_OF_MAX_LOG_FILE_NEMBER_PLUS_1 4
#define LOG_FILE_FORMAT "%s.%d"
/******************************************************************************/
HIDDEN pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
HIDDEN int file_exists(char *filename) {
FILE *fp;
fp = fopen(filename,"r");
if(fp != NULL){
fclose(fp);
return(1);
}
else
return(0);
}
HIDDEN char *get_free_logfile(char *logfile){
int suffix=-1;
int len = strlen(logfile)+LOG_OF_MAX_LOG_FILE_NEMBER_PLUS_1;
char *str = (char*) calloc(len,sizeof(char));
if (str == NULL){
fprintf(stderr,"Out of memory allocating free log file name\n");
exit(1);
}
do {
suffix++;
memset(str,0,len);
snprintf(str,len,LOG_FILE_FORMAT,logfile,suffix);
} while(file_exists(str) && suffix < MAX_LOG_FILE_NEMBER);
if (suffix == 100) {
fprintf(stderr,"Unable to find a free file name\n");
return NULL;
}
return(str);
}
HIDDEN void remove_all_old_log_files(char *logfile){
int suffix;
int len = strlen(logfile)+LOG_OF_MAX_LOG_FILE_NEMBER_PLUS_1;
char *str = (char*) calloc(len,sizeof(char));
for (suffix=0;suffix<MAX_LOG_FILE_NEMBER;suffix++){
memset(str,0,len);
snprintf(str,len,LOG_FILE_FORMAT,logfile,suffix);
remove(str);
}
free(str);
}
HIDDEN void copy_file(char *src, char* dst){
FILE *fpin, *fpout;
char buf[512];
int n;
fpin = fopen(src,"r");
fpout = fopen(dst,"w");
if ( fpin == NULL || fpout == NULL) {
fprintf(stderr,"Unable to open %s or %s\n",src,dst);
return;
}
for(;;){
n = fread(buf, 1, 512, fpin);
if(n == 0)
break;
fwrite(buf, 1, n, fpout);
}
fclose(fpin);
fclose(fpout);
}
// controls logfile size
int log_rotate(char *logfile)
{
struct stat filestats;
int rc;
int reopen=0;
pthread_mutex_lock(&mutex);
if(fd!=NULL)
reopen=1;
rc = stat(logfile, &filestats);
if (rc != -1 && filestats.st_size > MAX_LOG_SIZE) {
char *freefile=get_free_logfile(logfile);
if ( freefile == NULL) {
//retry after removing files
remove_all_old_log_files(logfile);
freefile=get_free_logfile(logfile);
if ( freefile == NULL) {
fprintf(stderr,
"Unable to open free log file\n");
exit(1);
}
}
// creates backup file
copy_file(logfile, freefile);
free(freefile);
remove(logfile);
}
if(reopen) {
fclose(fd);
fd = fopen(logfile, "a");
if (fd == NULL) {
fprintf(stderr,"Unable to open %s\n",logfile);
exit(1);
}
}
pthread_mutex_unlock(&mutex);
return 0;
}
int log_init(char* logfile)
{
#if (!(defined(WIN32) && !defined(CYGWIN))) && (!defined(BEOS))
char *filestr = NULL;
if(logfile == NULL)
{
//suppress the log!
filestr = strdup("/dev/null");
}
else if (!strcmp(logfile,"stdout"))
{
//log to stdout
filestr = NULL;
}
#ifndef WIN32
else if (!strcmp(logfile,"syslog"))
{
//syslog
filestr = NULL;
do_syslog = 1;
}
#endif
else
{
//filename
filestr = strdup(logfile);
}
#ifndef WIN32
if(do_syslog)
{
openlog(OPENLOG_NAME,LOG_CONS,LOG_USER);
}
else
#endif
{
if(filestr == NULL)
{
fd = stdout;
}
else
{
log_rotate(filestr);
log_file_name=(char*)strdup(filestr);
fd = fopen(filestr,"a");
if(strcmp("/dev/null",filestr))
chmod(filestr,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
}
if(fd == NULL)
fprintf(stderr, "UNABLE TO OPEN LOGFILE: %s\n",
filestr == NULL ? "stdout" : filestr);
}
free(filestr);
#endif
#if (defined(WIN32) && !defined(CYGWIN)) || defined(BEOS)
if(logfile == NULL)
logfile = strdup("log.txt");
log_rotate(logfile);
log_file_name=(char*)strdup(logfile);
fd = fopen(logfile, "a");
if (fd == NULL)
fprintf(stderr, "UNABLE TO OPEN LOGFILE: %s\n",logfile);
#endif
free(logfile);
return 0;
}
int log_end()
{
pthread_mutex_lock(&mutex);
if (fd)
fclose(fd);
return 0;
}
int logit(char* zone, char* preamble, char*filename,int line,char *str, ...)
{
// the string that will be printed
char *logstr = NULL;
// the string the user wants to print
char *strtmp = NULL;
int logstr_len,rc;
va_list args;
// lock the logging media
pthread_mutex_lock(&mutex);
// create and clean the buffer for the user string
strtmp = (char *) malloc(MAX_LOG_STRING);
memset(strtmp, '\0', MAX_LOG_STRING);
// fill the buffer for the user string
va_start(args, str);
rc = vsnprintf(strtmp, MAX_LOG_STRING, str, args);
va_end(args);
if (preamble == NULL)
logstr_len = strlen(zone) + strlen(ZONE_POSTPEND) +
strlen(strtmp) + 1;
else
// +1 is for "\0" , + 3 is for "(,)"
logstr_len = strlen(preamble) +
strlen(filename) + MAX(B(line),4) +
strlen(ZONE_POSTPEND) + strlen(strtmp) + 4;
// allocate logstr
logstr = (char *) malloc(logstr_len);
MALLOC_CHECK(logstr);
// create logstr (all data wanted by the user)
if (preamble == NULL)
snprintf(logstr,logstr_len,"%s%s%s",zone,ZONE_POSTPEND,strtmp);
else
snprintf(logstr,logstr_len,"%s(%s,%4d)%s%s",
preamble,filename,line,ZONE_POSTPEND,strtmp);
#ifndef WIN32
if (do_syslog) {
// syslog adds date and process name
syslog(LOG_DEBUG, logstr);
} else {
#endif
// syslog adds date and process name, here we have to do it
// by hand
struct tm *newtime = NULL;
time_t aclock;
char timestr[30]; //see the manpage
regmatch_t p;
/* Get time in seconds */
time(&aclock);
/* Convert time to struct tm form */
newtime = localtime(&aclock);
free(strtmp);
strtmp = (char *) malloc(MAX_LOG_STRING + 1);
memset(strtmp, '\0', MAX_LOG_STRING + 1);
strncpy(timestr, asctime(newtime), 30);
/* remove the \n at the end */
p = regfind(timestr, "\n");
if (p.begin != -1)
timestr[p.begin] = '\0';
rc = snprintf(strtmp, MAX_LOG_STRING, "%s %s: %s", timestr,
OPENLOG_NAME, logstr);
// put an endline if the string was truncated
if (rc >= MAX_LOG_STRING-1 && strtmp[MAX_LOG_STRING-2] != '\n')
{ printf("XXX\n"); strtmp[MAX_LOG_STRING-2] = '\n';}
fprintf(fd, "%s", strtmp);
fflush(fd);
#ifndef WIN32
}
#endif
free(strtmp);
free(logstr);
pthread_mutex_unlock(&mutex);
return 0;
}
int log_get_verbosity()
{
return verbose_output;
}
void log_set_verbosity(int v)
{
verbose_output = v;
}
char *log_get_logfile(){
return(log_file_name);
}
syntax highlighted by Code2HTML, v. 0.9.1