2006-09-27 14:14:44 +00:00
|
|
|
/*
|
2012-01-21 13:47:13 +00:00
|
|
|
* Copyright (C) 2012 Tobias Brunner
|
2006-09-27 14:14:44 +00:00
|
|
|
* Copyright (C) 2006 Martin Willi
|
|
|
|
* Hochschule fuer Technik Rapperswil
|
|
|
|
*
|
|
|
|
* This program 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
|
|
*
|
|
|
|
* This program 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2010-07-08 14:11:55 +00:00
|
|
|
#include <time.h>
|
2012-10-04 16:07:42 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
2006-09-27 14:14:44 +00:00
|
|
|
|
|
|
|
#include "file_logger.h"
|
|
|
|
|
2012-10-04 16:07:42 +00:00
|
|
|
#include <daemon.h>
|
2012-01-23 12:38:48 +00:00
|
|
|
#include <threading/mutex.h>
|
2012-10-04 16:07:42 +00:00
|
|
|
#include <threading/rwlock.h>
|
2006-09-27 14:14:44 +00:00
|
|
|
|
|
|
|
typedef struct private_file_logger_t private_file_logger_t;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Private data of a file_logger_t object
|
|
|
|
*/
|
|
|
|
struct private_file_logger_t {
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-09-27 14:14:44 +00:00
|
|
|
/**
|
|
|
|
* Public data.
|
|
|
|
*/
|
|
|
|
file_logger_t public;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-09-27 14:14:44 +00:00
|
|
|
/**
|
2012-10-04 16:07:42 +00:00
|
|
|
* File name of the target
|
|
|
|
*/
|
|
|
|
char *filename;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Current output file
|
2006-09-27 14:14:44 +00:00
|
|
|
*/
|
|
|
|
FILE *out;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-09-27 14:14:44 +00:00
|
|
|
/**
|
2008-10-14 08:52:13 +00:00
|
|
|
* Maximum level to log, for each group
|
2006-09-27 14:14:44 +00:00
|
|
|
*/
|
2006-10-26 09:46:56 +00:00
|
|
|
level_t levels[DBG_MAX];
|
2010-07-08 14:11:55 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* strftime() format of time prefix, if any
|
|
|
|
*/
|
|
|
|
char *time_format;
|
2010-08-25 07:53:43 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Print the name/# of the IKE_SA?
|
|
|
|
*/
|
|
|
|
bool ike_name;
|
2012-01-23 12:38:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Mutex to ensure multi-line log messages are not torn apart
|
|
|
|
*/
|
|
|
|
mutex_t *mutex;
|
2012-10-04 16:07:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Lock to read/write options (FD, levels, time_format, etc.)
|
|
|
|
*/
|
|
|
|
rwlock_t *lock;
|
2006-09-27 14:14:44 +00:00
|
|
|
};
|
|
|
|
|
2012-01-21 13:47:13 +00:00
|
|
|
METHOD(logger_t, log_, void,
|
|
|
|
private_file_logger_t *this, debug_t group, level_t level, int thread,
|
2012-07-13 13:42:14 +00:00
|
|
|
ike_sa_t* ike_sa, const char *message)
|
2006-09-27 14:14:44 +00:00
|
|
|
{
|
2012-01-23 12:51:21 +00:00
|
|
|
char timestr[128], namestr[128] = "";
|
2012-07-13 13:42:14 +00:00
|
|
|
const char *current = message, *next;
|
2012-01-23 12:51:21 +00:00
|
|
|
struct tm tm;
|
|
|
|
time_t t;
|
2010-07-08 14:11:55 +00:00
|
|
|
|
2012-10-04 16:07:42 +00:00
|
|
|
this->lock->read_lock(this->lock);
|
|
|
|
if (!this->out)
|
|
|
|
{ /* file is not open */
|
|
|
|
this->lock->unlock(this->lock);
|
|
|
|
return;
|
|
|
|
}
|
2012-01-23 12:51:21 +00:00
|
|
|
if (this->time_format)
|
|
|
|
{
|
|
|
|
t = time(NULL);
|
|
|
|
localtime_r(&t, &tm);
|
|
|
|
strftime(timestr, sizeof(timestr), this->time_format, &tm);
|
|
|
|
}
|
|
|
|
if (this->ike_name && ike_sa)
|
|
|
|
{
|
|
|
|
if (ike_sa->get_peer_cfg(ike_sa))
|
2010-08-25 07:53:43 +00:00
|
|
|
{
|
2012-01-23 12:51:21 +00:00
|
|
|
snprintf(namestr, sizeof(namestr), " <%s|%d>",
|
|
|
|
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
|
2010-08-25 07:53:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-23 12:51:21 +00:00
|
|
|
snprintf(namestr, sizeof(namestr), " <%d>",
|
|
|
|
ike_sa->get_unique_id(ike_sa));
|
2010-08-25 07:53:43 +00:00
|
|
|
}
|
2012-01-23 12:51:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
namestr[0] = '\0';
|
|
|
|
}
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2012-01-23 12:51:21 +00:00
|
|
|
/* prepend a prefix in front of every line */
|
|
|
|
this->mutex->lock(this->mutex);
|
2012-07-13 13:42:14 +00:00
|
|
|
while (TRUE)
|
2012-01-23 12:51:21 +00:00
|
|
|
{
|
|
|
|
next = strchr(current, '\n');
|
|
|
|
if (this->time_format)
|
2006-09-27 14:14:44 +00:00
|
|
|
{
|
2012-07-13 13:42:14 +00:00
|
|
|
fprintf(this->out, "%s %.2d[%N]%s ",
|
|
|
|
timestr, thread, debug_names, group, namestr);
|
2006-09-27 14:14:44 +00:00
|
|
|
}
|
2012-01-23 12:51:21 +00:00
|
|
|
else
|
|
|
|
{
|
2012-07-13 13:42:14 +00:00
|
|
|
fprintf(this->out, "%.2d[%N]%s ",
|
|
|
|
thread, debug_names, group, namestr);
|
|
|
|
}
|
|
|
|
if (next == NULL)
|
|
|
|
{
|
|
|
|
fprintf(this->out, "%s\n", current);
|
|
|
|
break;
|
2012-01-23 12:51:21 +00:00
|
|
|
}
|
2012-07-13 13:42:14 +00:00
|
|
|
fprintf(this->out, "%.*s\n", (int)(next - current), current);
|
|
|
|
current = next + 1;
|
2006-09-27 14:14:44 +00:00
|
|
|
}
|
2012-01-23 12:51:21 +00:00
|
|
|
this->mutex->unlock(this->mutex);
|
2012-10-04 16:07:42 +00:00
|
|
|
this->lock->unlock(this->lock);
|
2012-01-23 12:51:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(logger_t, get_level, level_t,
|
|
|
|
private_file_logger_t *this, debug_t group)
|
|
|
|
{
|
2012-10-04 16:07:42 +00:00
|
|
|
level_t level;
|
|
|
|
|
|
|
|
this->lock->read_lock(this->lock);
|
|
|
|
level = this->levels[group];
|
|
|
|
this->lock->unlock(this->lock);
|
|
|
|
return level;
|
2006-09-27 14:14:44 +00:00
|
|
|
}
|
|
|
|
|
2011-05-03 08:21:03 +00:00
|
|
|
METHOD(file_logger_t, set_level, void,
|
2012-01-21 13:47:13 +00:00
|
|
|
private_file_logger_t *this, debug_t group, level_t level)
|
2006-09-27 14:14:44 +00:00
|
|
|
{
|
2012-10-04 16:07:42 +00:00
|
|
|
this->lock->write_lock(this->lock);
|
2008-10-14 08:52:13 +00:00
|
|
|
if (group < DBG_ANY)
|
2006-10-18 11:46:13 +00:00
|
|
|
{
|
2008-10-14 08:52:13 +00:00
|
|
|
this->levels[group] = level;
|
2006-10-18 11:46:13 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-10-14 08:52:13 +00:00
|
|
|
for (group = 0; group < DBG_MAX; group++)
|
|
|
|
{
|
|
|
|
this->levels[group] = level;
|
|
|
|
}
|
2006-10-18 11:46:13 +00:00
|
|
|
}
|
2012-10-04 16:07:42 +00:00
|
|
|
this->lock->unlock(this->lock);
|
2006-09-27 14:14:44 +00:00
|
|
|
}
|
|
|
|
|
2012-10-04 16:07:42 +00:00
|
|
|
METHOD(file_logger_t, set_options, void,
|
|
|
|
private_file_logger_t *this, char *time_format, bool ike_name)
|
2006-09-27 14:14:44 +00:00
|
|
|
{
|
2012-10-04 16:07:42 +00:00
|
|
|
this->lock->write_lock(this->lock);
|
|
|
|
free(this->time_format);
|
|
|
|
this->time_format = strdupnull(time_format);
|
|
|
|
this->ike_name = ike_name;
|
|
|
|
this->lock->unlock(this->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Close the current file, if any
|
|
|
|
*/
|
|
|
|
static void close_file(private_file_logger_t *this)
|
|
|
|
{
|
|
|
|
if (this->out && this->out != stdout && this->out != stderr)
|
2008-11-11 10:52:37 +00:00
|
|
|
{
|
|
|
|
fclose(this->out);
|
2012-10-04 16:07:42 +00:00
|
|
|
this->out = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(file_logger_t, open_, void,
|
|
|
|
private_file_logger_t *this, bool flush_line, bool append)
|
|
|
|
{
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
if (streq(this->filename, "stderr"))
|
|
|
|
{
|
|
|
|
file = stderr;
|
|
|
|
}
|
|
|
|
else if (streq(this->filename, "stdout"))
|
|
|
|
{
|
|
|
|
file = stdout;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
file = fopen(this->filename, append ? "a" : "w");
|
|
|
|
if (file == NULL)
|
|
|
|
{
|
|
|
|
DBG1(DBG_DMN, "opening file %s for logging failed: %s",
|
|
|
|
this->filename, strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
2013-10-29 09:58:39 +00:00
|
|
|
#ifdef HAVE_SETLINEBUF
|
2012-10-04 16:07:42 +00:00
|
|
|
if (flush_line)
|
|
|
|
{
|
|
|
|
setlinebuf(file);
|
|
|
|
}
|
2013-10-29 09:58:39 +00:00
|
|
|
#endif /* HAVE_SETLINEBUF */
|
2008-11-11 10:52:37 +00:00
|
|
|
}
|
2012-10-04 16:07:42 +00:00
|
|
|
this->lock->write_lock(this->lock);
|
|
|
|
close_file(this);
|
|
|
|
this->out = file;
|
|
|
|
this->lock->unlock(this->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
METHOD(file_logger_t, destroy, void,
|
|
|
|
private_file_logger_t *this)
|
|
|
|
{
|
|
|
|
this->lock->write_lock(this->lock);
|
|
|
|
close_file(this);
|
|
|
|
this->lock->unlock(this->lock);
|
2012-01-23 12:38:48 +00:00
|
|
|
this->mutex->destroy(this->mutex);
|
2012-10-04 16:07:42 +00:00
|
|
|
this->lock->destroy(this->lock);
|
|
|
|
free(this->time_format);
|
|
|
|
free(this->filename);
|
2006-09-27 14:14:44 +00:00
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Described in header.
|
|
|
|
*/
|
2012-10-04 16:07:42 +00:00
|
|
|
file_logger_t *file_logger_create(char *filename)
|
2006-09-27 14:14:44 +00:00
|
|
|
{
|
2011-05-03 08:21:03 +00:00
|
|
|
private_file_logger_t *this;
|
|
|
|
|
|
|
|
INIT(this,
|
|
|
|
.public = {
|
2012-01-21 13:47:13 +00:00
|
|
|
.logger = {
|
2011-05-03 08:21:03 +00:00
|
|
|
.log = _log_,
|
2012-01-23 12:51:21 +00:00
|
|
|
.get_level = _get_level,
|
2011-05-03 08:21:03 +00:00
|
|
|
},
|
|
|
|
.set_level = _set_level,
|
2012-10-04 16:07:42 +00:00
|
|
|
.set_options = _set_options,
|
|
|
|
.open = _open_,
|
2011-05-03 08:21:03 +00:00
|
|
|
.destroy = _destroy,
|
|
|
|
},
|
2012-10-04 16:07:42 +00:00
|
|
|
.filename = strdup(filename),
|
2012-01-23 12:38:48 +00:00
|
|
|
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
2012-10-04 16:07:42 +00:00
|
|
|
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
2011-05-03 08:21:03 +00:00
|
|
|
);
|
|
|
|
|
2008-10-14 08:52:13 +00:00
|
|
|
set_level(this, DBG_ANY, LEVEL_SILENT);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2006-09-27 14:14:44 +00:00
|
|
|
return &this->public;
|
|
|
|
}
|