|
Packit |
6bd9ab |
/*
|
|
Packit |
6bd9ab |
log.c - logging funtions
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
Copyright (C) 2002, 2003, 2008, 2010, 2011, 2012, 2013 Arthur de Jong
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
This library is free software; you can redistribute it and/or
|
|
Packit |
6bd9ab |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6bd9ab |
License as published by the Free Software Foundation; either
|
|
Packit |
6bd9ab |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
This library is distributed in the hope that it will be useful,
|
|
Packit |
6bd9ab |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6bd9ab |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6bd9ab |
Lesser General Public License for more details.
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6bd9ab |
License along with this library; if not, write to the Free Software
|
|
Packit |
6bd9ab |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit |
6bd9ab |
02110-1301 USA
|
|
Packit |
6bd9ab |
*/
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#include "config.h"
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#include <stdio.h>
|
|
Packit |
6bd9ab |
#include <stdlib.h>
|
|
Packit |
6bd9ab |
#include <sys/types.h>
|
|
Packit |
6bd9ab |
#include <unistd.h>
|
|
Packit |
6bd9ab |
#include <syslog.h>
|
|
Packit |
6bd9ab |
#include <stdarg.h>
|
|
Packit |
6bd9ab |
#include <errno.h>
|
|
Packit |
6bd9ab |
#include <string.h>
|
|
Packit |
6bd9ab |
#include <time.h>
|
|
Packit |
6bd9ab |
#include <pthread.h>
|
|
Packit |
6bd9ab |
#include <strings.h>
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#include "log.h"
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* set the logname */
|
|
Packit |
6bd9ab |
#undef PACKAGE
|
|
Packit |
6bd9ab |
#define PACKAGE "nslcd"
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* storage for logging modes */
|
|
Packit |
6bd9ab |
static struct log_cfg {
|
|
Packit |
6bd9ab |
int loglevel;
|
|
Packit |
6bd9ab |
const char *scheme;
|
|
Packit |
6bd9ab |
FILE *fp; /* NULL == syslog */
|
|
Packit |
6bd9ab |
struct log_cfg *next;
|
|
Packit |
6bd9ab |
} *loglist = NULL;
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* default loglevel when no logging is configured */
|
|
Packit |
6bd9ab |
static int prelogging_loglevel = LOG_INFO;
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#define MAX_REQUESTID_LENGTH 40
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#ifdef TLS
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* the session id that is set for this thread */
|
|
Packit |
6bd9ab |
static TLS char *sessionid = NULL;
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* the request identifier that is set for this thread */
|
|
Packit |
6bd9ab |
static TLS char *requestid = NULL;
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#else /* no TLS, use pthreads */
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static pthread_once_t tls_init_once = PTHREAD_ONCE_INIT;
|
|
Packit |
6bd9ab |
static pthread_key_t sessionid_key;
|
|
Packit |
6bd9ab |
static pthread_key_t requestid_key;
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static void tls_init_keys(void)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
pthread_key_create(&sessionid_key, NULL);
|
|
Packit |
6bd9ab |
pthread_key_create(&requestid_key, NULL);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#endif /* no TLS, use pthreads */
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* set loglevel when no logging is configured */
|
|
Packit |
6bd9ab |
void log_setdefaultloglevel(int loglevel)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
prelogging_loglevel = loglevel;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* add logging method to configuration list */
|
|
Packit |
6bd9ab |
static void addlogging(int loglevel, const char *scheme, FILE *fp)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
struct log_cfg *tmp, *lst;
|
|
Packit |
6bd9ab |
/* create new logstruct */
|
|
Packit |
6bd9ab |
tmp = (struct log_cfg *)malloc(sizeof(struct log_cfg));
|
|
Packit |
6bd9ab |
if (tmp == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "malloc() returned NULL");
|
|
Packit |
6bd9ab |
exit(EXIT_FAILURE);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
tmp->loglevel = loglevel;
|
|
Packit |
6bd9ab |
tmp->scheme = scheme;
|
|
Packit |
6bd9ab |
tmp->fp = fp;
|
|
Packit |
6bd9ab |
tmp->next = NULL;
|
|
Packit |
6bd9ab |
/* save the struct in the list */
|
|
Packit |
6bd9ab |
if (loglist == NULL)
|
|
Packit |
6bd9ab |
loglist = tmp;
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
for (lst = loglist; lst->next != NULL; lst = lst->next);
|
|
Packit |
6bd9ab |
lst->next = tmp;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* configure logging to a file */
|
|
Packit |
6bd9ab |
void log_addlogging_file(int loglevel, const char *filename)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
FILE *fp;
|
|
Packit |
6bd9ab |
filename = strdup(filename);
|
|
Packit |
6bd9ab |
if (filename == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "strdup() returned NULL");
|
|
Packit |
6bd9ab |
exit(EXIT_FAILURE);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
fp = fopen(filename, "a");
|
|
Packit |
6bd9ab |
if (fp == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "cannot open logfile (%s) for appending: %s",
|
|
Packit |
6bd9ab |
filename, strerror(errno));
|
|
Packit |
6bd9ab |
exit(1);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
addlogging(loglevel, filename, fp);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* configure logging to syslog */
|
|
Packit |
6bd9ab |
void log_addlogging_syslog(int loglevel)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
openlog(PACKAGE, LOG_PID, LOG_DAEMON);
|
|
Packit |
6bd9ab |
addlogging(loglevel, "syslog", NULL);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* configure a null logging mode (no logging) */
|
|
Packit |
6bd9ab |
void log_addlogging_none()
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* this is a hack, but it's so easy */
|
|
Packit |
6bd9ab |
addlogging(LOG_EMERG, "none", NULL);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* start the logging with the configured logging methods
|
|
Packit |
6bd9ab |
if no method is configured yet, logging is done to syslog */
|
|
Packit |
6bd9ab |
void log_startlogging(void)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (loglist == NULL)
|
|
Packit |
6bd9ab |
log_addlogging_syslog(LOG_INFO);
|
|
Packit |
6bd9ab |
prelogging_loglevel = -1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* indicate that we should clear any session identifiers set by
|
|
Packit |
6bd9ab |
log_newsession */
|
|
Packit |
6bd9ab |
void log_clearsession(void)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
#ifndef TLS
|
|
Packit |
6bd9ab |
char *sessionid, *requestid;
|
|
Packit |
6bd9ab |
pthread_once(&tls_init_once, tls_init_keys);
|
|
Packit |
6bd9ab |
sessionid = pthread_getspecific(sessionid_key);
|
|
Packit |
6bd9ab |
requestid = pthread_getspecific(requestid_key);
|
|
Packit |
6bd9ab |
#endif /* no TLS */
|
|
Packit |
6bd9ab |
/* set the session id to empty */
|
|
Packit |
6bd9ab |
if (sessionid != NULL)
|
|
Packit |
6bd9ab |
sessionid[0] = '\0';
|
|
Packit |
6bd9ab |
/* set the request id to empty */
|
|
Packit |
6bd9ab |
if (requestid != NULL)
|
|
Packit |
6bd9ab |
requestid[0] = '\0';
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* indicate that a session id should be included in the output
|
|
Packit |
6bd9ab |
and set it to a new value */
|
|
Packit |
6bd9ab |
void log_newsession(void)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
#ifndef TLS
|
|
Packit |
6bd9ab |
char *sessionid, *requestid;
|
|
Packit |
6bd9ab |
pthread_once(&tls_init_once, tls_init_keys);
|
|
Packit |
6bd9ab |
sessionid = pthread_getspecific(sessionid_key);
|
|
Packit |
6bd9ab |
requestid = pthread_getspecific(requestid_key);
|
|
Packit |
6bd9ab |
#endif /* no TLS */
|
|
Packit |
6bd9ab |
/* ensure that sessionid can hold a string */
|
|
Packit |
6bd9ab |
if (sessionid == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
sessionid = (char *)malloc(7);
|
|
Packit |
6bd9ab |
if (sessionid == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
fprintf(stderr, "malloc() failed: %s", strerror(errno));
|
|
Packit |
6bd9ab |
return; /* silently fail */
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#ifndef TLS
|
|
Packit |
6bd9ab |
pthread_setspecific(sessionid_key, sessionid);
|
|
Packit |
6bd9ab |
#endif /* no TLS */
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
sprintf(sessionid, "%06x", (int)(rand() & 0xffffff));
|
|
Packit |
6bd9ab |
/* set the request id to empty */
|
|
Packit |
6bd9ab |
if (requestid != NULL)
|
|
Packit |
6bd9ab |
requestid[0] = '\0';
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* indicate that a request identifier should be included in the output
|
|
Packit |
6bd9ab |
from this point on, until log_newsession() is called */
|
|
Packit |
6bd9ab |
void log_setrequest(const char *format, ...)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
va_list ap;
|
|
Packit |
6bd9ab |
#ifndef TLS
|
|
Packit |
6bd9ab |
char *requestid;
|
|
Packit |
6bd9ab |
pthread_once(&tls_init_once, tls_init_keys);
|
|
Packit |
6bd9ab |
requestid = pthread_getspecific(requestid_key);
|
|
Packit |
6bd9ab |
#endif /* no TLS */
|
|
Packit |
6bd9ab |
/* ensure that requestid can hold a string */
|
|
Packit |
6bd9ab |
if (requestid == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
requestid = (char *)malloc(MAX_REQUESTID_LENGTH);
|
|
Packit |
6bd9ab |
if (requestid == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
fprintf(stderr, "malloc() failed: %s", strerror(errno));
|
|
Packit |
6bd9ab |
return; /* silently fail */
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#ifndef TLS
|
|
Packit |
6bd9ab |
pthread_setspecific(requestid_key, requestid);
|
|
Packit |
6bd9ab |
#endif /* no TLS */
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* make the message */
|
|
Packit |
6bd9ab |
va_start(ap, format);
|
|
Packit |
6bd9ab |
vsnprintf(requestid, MAX_REQUESTID_LENGTH, format, ap);
|
|
Packit |
6bd9ab |
requestid[MAX_REQUESTID_LENGTH - 1] = '\0';
|
|
Packit |
6bd9ab |
va_end(ap);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* log the given message using the configured logging method */
|
|
Packit |
6bd9ab |
void log_log(int pri, const char *format, ...)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int res;
|
|
Packit |
6bd9ab |
struct log_cfg *lst;
|
|
Packit |
6bd9ab |
char buffer[200];
|
|
Packit |
6bd9ab |
va_list ap;
|
|
Packit |
6bd9ab |
#ifndef TLS
|
|
Packit |
6bd9ab |
char *sessionid, *requestid;
|
|
Packit |
6bd9ab |
pthread_once(&tls_init_once, tls_init_keys);
|
|
Packit |
6bd9ab |
sessionid = pthread_getspecific(sessionid_key);
|
|
Packit |
6bd9ab |
requestid = pthread_getspecific(requestid_key);
|
|
Packit |
6bd9ab |
#endif /* no TLS */
|
|
Packit |
6bd9ab |
/* make the message */
|
|
Packit |
6bd9ab |
va_start(ap, format);
|
|
Packit |
6bd9ab |
res = vsnprintf(buffer, sizeof(buffer), format, ap);
|
|
Packit |
6bd9ab |
if ((res < 0) || (res >= (int)sizeof(buffer)))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* truncate with "..." */
|
|
Packit |
6bd9ab |
buffer[sizeof(buffer) - 2] = '.';
|
|
Packit |
6bd9ab |
buffer[sizeof(buffer) - 3] = '.';
|
|
Packit |
6bd9ab |
buffer[sizeof(buffer) - 4] = '.';
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
buffer[sizeof(buffer) - 1] = '\0';
|
|
Packit |
6bd9ab |
va_end(ap);
|
|
Packit |
6bd9ab |
/* do the logging */
|
|
Packit |
6bd9ab |
if (prelogging_loglevel >= 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* if logging is not yet defined, log to stderr */
|
|
Packit |
6bd9ab |
if (pri <= prelogging_loglevel)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if ((requestid != NULL) && (requestid[0] != '\0'))
|
|
Packit |
6bd9ab |
fprintf(stderr, "%s: [%s] <%s> %s%s\n", PACKAGE, sessionid, requestid,
|
|
Packit |
6bd9ab |
pri == LOG_DEBUG ? "DEBUG: " : "", buffer);
|
|
Packit |
6bd9ab |
else if ((sessionid != NULL) && (sessionid[0] != '\0'))
|
|
Packit |
6bd9ab |
fprintf(stderr, "%s: [%s] %s%s\n", PACKAGE, sessionid,
|
|
Packit |
6bd9ab |
pri == LOG_DEBUG ? "DEBUG: " : "", buffer);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
fprintf(stderr, "%s: %s%s\n", PACKAGE,
|
|
Packit |
6bd9ab |
pri == LOG_DEBUG ? "DEBUG: " : "", buffer);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
for (lst = loglist; lst != NULL; lst = lst->next)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (pri <= lst->loglevel)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (lst->fp == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if ((requestid != NULL) && (requestid[0] != '\0'))
|
|
Packit |
6bd9ab |
syslog(pri, "[%s] <%s> %s%s", sessionid, requestid,
|
|
Packit |
6bd9ab |
pri == LOG_DEBUG ? "DEBUG: " : "", buffer);
|
|
Packit |
6bd9ab |
else if ((sessionid != NULL) && (sessionid[0] != '\0'))
|
|
Packit |
6bd9ab |
syslog(pri, "[%s] %s%s", sessionid,
|
|
Packit |
6bd9ab |
pri == LOG_DEBUG ? "DEBUG: " : "", buffer);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
syslog(pri, "%s%s",
|
|
Packit |
6bd9ab |
pri == LOG_DEBUG ? "DEBUG: " : "", buffer);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if ((requestid != NULL) && (requestid[0] != '\0'))
|
|
Packit |
6bd9ab |
fprintf(lst->fp, "%s: [%s] <%s> %s%s\n", PACKAGE, sessionid, requestid,
|
|
Packit |
6bd9ab |
pri == LOG_DEBUG ? "DEBUG: " : "", buffer);
|
|
Packit |
6bd9ab |
else if ((sessionid != NULL) && (sessionid[0] != '\0'))
|
|
Packit |
6bd9ab |
fprintf(lst->fp, "%s: [%s] %s%s\n", PACKAGE, sessionid,
|
|
Packit |
6bd9ab |
pri == LOG_DEBUG ? "DEBUG: " : "", buffer);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
fprintf(lst->fp, "%s: %s%s\n", PACKAGE,
|
|
Packit |
6bd9ab |
pri == LOG_DEBUG ? "DEBUG: " : "", buffer);
|
|
Packit |
6bd9ab |
fflush(lst->fp);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static const char *loglevel2str(int loglevel)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
switch (loglevel)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
case LOG_CRIT: return "crit";
|
|
Packit |
6bd9ab |
case LOG_ERR: return "error";
|
|
Packit |
6bd9ab |
case LOG_WARNING: return "warning";
|
|
Packit |
6bd9ab |
case LOG_NOTICE: return "notice";
|
|
Packit |
6bd9ab |
case LOG_INFO: return "info";
|
|
Packit |
6bd9ab |
case LOG_DEBUG: return "debug";
|
|
Packit |
6bd9ab |
default: return "???";
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* log the logging configuration on DEBUG loglevel */
|
|
Packit |
6bd9ab |
void log_log_config(void)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
struct log_cfg *lst;
|
|
Packit |
6bd9ab |
for (lst = loglist; lst != NULL; lst = lst->next)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (lst->loglevel == LOG_EMERG)
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "CFG: log %s", lst->scheme);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "CFG: log %s %s", lst->scheme,
|
|
Packit |
6bd9ab |
loglevel2str(lst->loglevel));
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|