Blame nslcd/log.c

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
}