/*
* Copyright (c) 2003-2006 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: log.c,v 1.41 2007/01/14 00:44:40 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/time.h"
#include "sm/magic.h"
#include "sm/heap.h"
#include "sm/memops.h"
#include "sm/io.h"
#include "sm/log.h"
#include "sm/syslog.h"
#include "sm/time.h"
#include "sm/str.h"
#if MTA_USE_PTHREADS
#include "sm/pthread.h"
#endif
#define SM_LOG_MAGIC SM_MAGIC('S', 'L', 'O', 'G')
#define MAX_LOG_ENTRIES 10000
/* can syslog() deal with these lengths? */
#ifdef MTA_LOG_LEN
# define LOG_LEN MTA_LOG_LEN
#else
# define LOG_LEN 1022
#endif
#ifdef MTA_LOG_LEN_MAX
# define LOG_LEN_MAX MTA_LOG_LEN_MAX
#else
# define LOG_LEN_MAX 8192
#endif
#if LOG_LEN > LOG_LEN_MAX
ERROR _LOG_LEN > _LOG_LEN_MAX: LOG_LEN > LOG_LEN_MAX
#endif
/* should be dynamically allocated later on */
#define SM_LOG_MAX_CATS 32
#define SM_LOG_MAX_MODS 32
struct sm_log_ctx_S
{
sm_magic_T sm_magic;
sm_logconfig_P lctx_cfg;
uint lctx_dbg_level;
#if 0
/* make some things optional: sev=, time stamp, ...?? */
uint lctx_flags;
#endif
int lctx_fd;
sm_file_T *lctx_fp;
char *lctx_filename;
sm_str_P lctx_str;
sm_logcategory_P lctx_cats[SM_LOG_MAX_CATS];
uint lctx_cat_n;
sm_logmodule_P lctx_mods[SM_LOG_MAX_MODS];
uint lctx_mod_n;
#if SM_LOG_ROTATE
/* doesn't work that simple: needs filename */
time_T lctx_rotated;
uint lctx_entries;
#endif
#if MTA_USE_PTHREADS
pthread_mutex_t lctx_mutex;
#endif
};
#define SM_IS_LOGCTX(lctx) SM_REQUIRE_ISA((lctx), SM_LOG_MAGIC)
/* move to magic.h? */
#define SM_LOGCFG_MAGIC SM_MAGIC('S', 'L', 'C', 'F')
struct sm_logconfig_S
{
sm_magic_T sm_magic;
};
#define SM_IS_LOGCFG(lcfg) SM_REQUIRE_ISA((lcfg), SM_LOGCFG_MAGIC)
#if SM_LOG_SEVERITY
/*
** log sev=SEVERITY () works nice here, but other stuff like
** syslog(), fprint(), don't do this...
** change all sm_log_write() calls?
*/
struct l2t_S
{
int l2t_code;
char *l2t_str;
};
typedef struct l2t_S l2t_T, *l2t_P;
static l2t_T
sm_loglev2txt[] =
{
{ SM_LOG_EMERG, "EMERG" },
{ SM_LOG_FATAL, "FATAL" },
{ SM_LOG_ALERT, "ALERT" },
{ SM_LOG_CRIT, "CRIT" },
{ SM_LOG_ERROR, "ERROR" },
{ SM_LOG_ERR, "ERROR" },
{ SM_LOG_WARNING, "WARNING" },
{ SM_LOG_WARN, "WARNING" },
{ SM_LOG_NOTICE, "NOTICE" },
{ SM_LOG_INFO, "INFO" },
{ SM_LOG_DEBUG, "DEBUG" },
{ -1, NULL }
};
static char *
sm_l2t(int loglevel)
{
int i;
i = 0;
while (sm_loglev2txt[i].l2t_code != 0 || sm_loglev2txt[i].l2t_str != NULL)
{
if (sm_loglev2txt[i].l2t_code == loglevel)
return sm_loglev2txt[i].l2t_str;
++i;
}
return "Bogus_Log_Level";
}
#endif /* SM_LOG_SEVERITY */
/*
** SM_LOG_CREATE -- Create a log context
**
** Parameters:
** mctx -- memory context to use [currently unused]
** plctx -- (pointer to) log context (output)
** plcfg -- (pointer to) log config (output)
**
** Returns:
** usual sm_error code; ENOMEM
*/
sm_ret_T
sm_log_create(sm_mem_P mctx, sm_log_ctx_P *plctx, sm_logconfig_P *plcfg)
{
sm_ret_T ret;
sm_log_ctx_P lctx;
sm_logconfig_P lcfg;
(void)mctx;
SM_REQUIRE(plctx != NULL);
lctx = (sm_log_ctx_P) sm_zalloc(sizeof(*lctx));
if (NULL == lctx)
return sm_error_temp(SM_EM_LOG, ENOMEM);
#if MTA_USE_PTHREADS
ret = pthread_mutex_init(&lctx->lctx_mutex, SM_PTHREAD_MUTEXATTR);
if (ret != 0) {
/* ret = sm_error_perm(SM_EM_LOG, ret); */
ret = sm_error_perm(SM_EM_LOG, ret);
goto error;
}
#endif /* MTA_USE_PTHREADS */
lctx->lctx_str = sm_str_new(NULL, LOG_LEN, LOG_LEN_MAX);
if (NULL == lctx->lctx_str) {
ret = sm_error_temp(SM_EM_LOG, ENOMEM);
goto error;
}
lctx->lctx_fd = INVALID_FD;
lctx->sm_magic = SM_LOG_MAGIC;
ret = sm_logconfig_create(lctx, &lcfg);
if (sm_is_err(ret))
goto error;
lctx->lctx_cfg = lcfg;
if (plcfg != NULL)
*plcfg = lcfg;
lctx->lctx_dbg_level = UINT_MAX;
*plctx = lctx;
return SM_SUCCESS;
error:
if (lctx != NULL) {
SM_STR_FREE(lctx->lctx_str);
lctx->sm_magic = SM_MAGIC_NULL;
sm_free_size(lctx, sizeof(*lctx));
}
return ret;
}
/*
** SM_LOG_DESTROY -- Destroy a log context
**
** Parameters:
** lctx -- log context
**
** Returns:
** SM_SUCCESS
*/
sm_ret_T
sm_log_destroy(sm_log_ctx_P lctx)
{
if (NULL == lctx)
return SM_SUCCESS;
SM_IS_LOGCTX(lctx);
if (lctx->lctx_fp != NULL)
sm_io_flush(lctx->lctx_fp);
sm_logconfig_destroy(lctx->lctx_cfg);
#if MTA_USE_PTHREADS
(void) pthread_mutex_destroy(&lctx->lctx_mutex);
#endif
SM_STR_FREE(lctx->lctx_str);
lctx->sm_magic = SM_MAGIC_NULL;
sm_free_size(lctx, sizeof(*lctx));
return SM_SUCCESS;
}
/*
** SM_LOGCONFIG_CREATE -- Create a log configuration
**
** Parameters:
** lctx -- log context
** plcfg -- (pointer to) log config (output)
**
** Returns:
** usual sm_error code; ENOMEM
*/
sm_ret_T
sm_logconfig_create(sm_log_ctx_P lctx, sm_logconfig_P *plcfg)
{
sm_logconfig_P lcfg;
SM_REQUIRE(lctx != NULL);
SM_REQUIRE(plcfg != NULL);
lcfg = (sm_logconfig_P) sm_zalloc(sizeof(*lcfg));
if (NULL == lcfg)
return sm_error_temp(SM_EM_LOG, ENOMEM);
lcfg->sm_magic = SM_LOGCFG_MAGIC;
*plcfg = lcfg;
return SM_SUCCESS;
}
/*
** SM_LOGCONFIG_USE -- Use a log configuration
**
** Parameters:
** lctx -- log context
** lcfg -- log config
**
** Returns:
** SM_SUCCESS
*/
sm_ret_T
sm_logconfig_use(sm_log_ctx_P lctx, sm_logconfig_P lcfg)
{
SM_IS_LOGCTX(lctx);
SM_IS_LOGCFG(lcfg);
return SM_SUCCESS;
}
/*
** SM_LOGCONFIG_GET -- Return current log configuration
**
** Parameters:
** lctx -- log context
**
** Returns:
** log config
*/
sm_logconfig_P
sm_logconfig_get(sm_log_ctx_P lctx)
{
SM_IS_LOGCTX(lctx);
return lctx->lctx_cfg;
}
/*
** SM_LOGCONFIG_DESTROY -- Destroy a log configuration
**
** Parameters:
** lcfg -- log config
**
** Returns:
** SM_SUCCESS
*/
sm_ret_T
sm_logconfig_destroy(sm_logconfig_P lcfg)
{
if (NULL == lcfg)
return SM_SUCCESS;
SM_IS_LOGCFG(lcfg);
lcfg->sm_magic = SM_MAGIC_NULL;
sm_free_size(lcfg, sizeof(*lcfg));
return SM_SUCCESS;
}
sm_ret_T
sm_log_registercategories(sm_log_ctx_P lctx, sm_logcategory_T categories[])
{
uint u;
SM_IS_LOGCTX(lctx);
for (u = 0; u < SM_ARRAY_SIZE(lctx->lctx_cats); u++) {
if (NULL == lctx->lctx_cats[u]) {
lctx->lctx_cats[u] = categories;
++lctx->lctx_cat_n;
return SM_SUCCESS;
}
}
return sm_error_perm(SM_EM_LOG, SM_E_FULL);
}
sm_ret_T
sm_log_registermodules(sm_log_ctx_P lctx, sm_logmodule_T modules[])
{
uint u;
SM_IS_LOGCTX(lctx);
for (u = 0; u < SM_ARRAY_SIZE(lctx->lctx_mods); u++) {
if (NULL == lctx->lctx_mods[u]) {
lctx->lctx_mods[u] = modules;
++lctx->lctx_mod_n;
return SM_SUCCESS;
}
}
return sm_error_perm(SM_EM_LOG, SM_E_FULL);
}
/* ARGSUSED1 */
sm_ret_T
sm_log_createchannel(sm_logconfig_P lcfg, const char *name, uint type, int priority, uint level, const sm_logdestination_P destination, uint flags)
{
SM_IS_LOGCFG(lcfg);
return SM_SUCCESS;
}
/* ARGSUSED1 */
sm_ret_T
sm_log_usechannel(sm_logconfig_P lcfg, const char *name, const sm_logcategory_P category, const sm_logmodule_P module)
{
SM_IS_LOGCFG(lcfg);
return SM_SUCCESS;
}
/*
** SM_LOG_SETFILE -- Set a logfile in a log context
**
** Parameters:
** lctx -- log context
** file -- file to use
**
** Returns:
** SM_SUCCESS
*/
sm_ret_T
sm_log_setfile(sm_log_ctx_P lctx, sm_file_T *file)
{
SM_IS_LOGCTX(lctx);
lctx->lctx_fp = file;
return SM_SUCCESS;
}
/*
** SM_LOG_SETFD -- Set a log fd in a log context
**
** Parameters:
** lctx -- log context
** fd -- fd to use
**
** Returns:
** SM_SUCCESS
*/
sm_ret_T
sm_log_setfd(sm_log_ctx_P lctx, int fd)
{
SM_IS_LOGCTX(lctx);
lctx->lctx_fd = fd;
return SM_SUCCESS;
}
/*
** SM_LOG_SETFP_FD -- Set a logfile and fd in a log context
**
** Parameters:
** lctx -- log context
** fp -- file to use
** fd -- fd to use
**
** Returns:
** SM_SUCCESS
*/
sm_ret_T
sm_log_setfp_fd(sm_log_ctx_P lctx, sm_file_T *fp, int fd)
{
SM_IS_LOGCTX(lctx);
lctx->lctx_fp = fp;
lctx->lctx_fd = fd;
return SM_SUCCESS;
}
/*
** SM_LOG_SETFILENAME -- Set a logfile name in a log context
**
** Parameters:
** lctx -- log context
** name -- file name to use (will NOT be copied!)
**
** Returns:
** SM_SUCCESS
*/
sm_ret_T
sm_log_setfilename(sm_log_ctx_P lctx, char *name)
{
SM_IS_LOGCTX(lctx);
lctx->lctx_filename = name;
return SM_SUCCESS;
}
/*
** SM_LOG_REOPEN -- Reopen a log file
**
** Parameters:
** lctx -- log context
**
** Returns:
** usual sm_error code.
*/
sm_ret_T
sm_log_reopen(sm_log_ctx_P lctx)
{
sm_ret_T ret;
#if MTA_USE_PTHREADS
int r;
#endif
SM_IS_LOGCTX(lctx);
ret = SM_SUCCESS;
#if MTA_USE_PTHREADS
r = pthread_mutex_lock(&lctx->lctx_mutex);
SM_LOCK_OK(r);
if (r != 0) {
/* ret = sm_error_perm(SM_EM_LOG, r); */
ret = sm_error_perm(SM_EM_LOG, r);
goto error;
}
#endif /* MTA_USE_PTHREADS */
if (lctx->lctx_filename != NULL && *lctx->lctx_filename != '\0') {
sm_io_flush(lctx->lctx_fp);
sm_io_close(lctx->lctx_fp, SM_IO_CF_NONE);
lctx->lctx_fp = NULL;
ret = sm_io_open(SmStStdio, lctx->lctx_filename, SM_IO_WRONLY,
&lctx->lctx_fp, SM_IO_WHAT_END);
if (sm_is_err(ret))
goto errunl;
}
else if (NULL == lctx->lctx_fp || lctx->lctx_fd == INVALID_FD)
/* nothing */; /* XXX Really? */
else {
sm_io_flush(lctx->lctx_fp);
ret = ftruncate(lctx->lctx_fd, (off_t) 0);
if (ret < 0) {
ret = sm_error_temp(SM_EM_LOG, errno);
goto errunl;
}
ret = sm_io_seek(lctx->lctx_fp, 0L, SM_IO_SEEK_SET);
if (sm_is_err(ret))
goto errunl;
}
#if SM_LOG_ROTATE
lctx->lctx_entries = 0;
lctx->lctx_rotated = time(NULLT);
#endif
#if MTA_USE_PTHREADS
r = pthread_mutex_unlock(&lctx->lctx_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_LOG, r);
#endif /* MTA_USE_PTHREADS */
return ret;
errunl:
#if MTA_USE_PTHREADS
r = pthread_mutex_unlock(&lctx->lctx_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_LOG, r);
error:
#endif /* MTA_USE_PTHREADS */
return ret;
}
/*
** SM_LOG_TSTAMP -- return timestamp
**
** Parameters:
** none.
**
** Returns:
** pointer to timestamp.
**
** Locking: must be provided by caller.
*/
static char *
sm_log_tstamp(void)
{
static char str[32] = "[1900-00-00/00:00:00] ";
static time_t lastt = 0;
struct tm *tmp;
time_t currt;
#if MTA_USE_PTHREADS
struct tm tm;
#endif
#if MTA_USE_STATETHREADS
currt = st_time();
#else
currt = time(NULLT);
#endif
if (currt == lastt || currt == (time_t) -1)
return str;
#if MTA_USE_PTHREADS
tmp = localtime_r(&currt, &tm);
#else
tmp = localtime(&currt);
#endif
sm_snprintf(str, sizeof(str), "[%d-%02d-%02d/%02d:%02d:%02d] ",
1900 + tmp->tm_year, /* HACK */
tmp->tm_mon + 1,
tmp->tm_mday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
lastt = currt;
return str;
}
#if SM_LOG_ROTATE
/*
** SM_LOG_ROTATE -- Rotate a log file
**
** Parameters:
** lctx -- log context
**
** Returns:
** SM_SUCCESS
*/
sm_ret_T
sm_log_rotate(sm_log_ctx_P lctx)
{
SM_IS_LOGCTX(lctx);
if (lctx->lctx_fp != NULL)
{
}
lctx->lctx_entries = 0;
lctx->lctx_rotated = time(NULLT);
return SM_SUCCESS;
}
#endif /* SM_LOG_ROTATE */
/*
** SM_LOG_WRITE -- Write a logfile entry
**
** Parameters:
** lctx -- log context
** category -- category
** module -- module
** priority -- priority
** level -- log level
** format -- format
** ... -- arguments
**
** Returns:
** SM_SUCCESS except for (un)lock errors
*/
sm_ret_T
sm_log_write(sm_log_ctx_P lctx, sm_logcategory_P category, sm_logmodule_P module, int priority, uint level, const char *format, ...)
{
va_list va;
#if MTA_USE_PTHREADS
int r;
#endif
sm_ret_T ret;
if (lctx != NULL) {
SM_IS_LOGCTX(lctx);
if (!sm_log_wouldlog(lctx, category, module, level))
return SM_SUCCESS;
}
/* Allow NULL context, necessary for emergency logging */
if (NULL == lctx) {
int r, save_errno;
char *log;
log = NULL;
va_start(va, format);
r = sm_vasprintf(&log, format, va);
save_errno = errno;
if (r != -1)
syslog(priority, "%.*s", LOG_LEN_MAX, log);
va_end(va);
SM_FREE(log);
return (r != -1) ? SM_SUCCESS
: sm_error_perm(SM_EM_LOG, save_errno);
}
ret = SM_SUCCESS;
#if MTA_USE_PTHREADS
r = pthread_mutex_lock(&lctx->lctx_mutex);
SM_LOCK_OK(r);
if (r != 0) {
/* ret = sm_error_perm(SM_EM_LOG, r); */
return sm_error_perm(SM_EM_LOG, r);
}
#endif /* MTA_USE_PTHREADS */
if (NULL == lctx->lctx_fp) {
sm_str_clr(lctx->lctx_str);
#if SM_LOG_SEVERITY
sm_str_scat(lctx->lctx_str, sm_l2t(priority));
#endif
va_start(va, format);
sm_strvprintf(lctx->lctx_str, format, va);
va_end(va);
syslog(priority, "%.*s", (int) sm_str_getlen(lctx->lctx_str),
(const char *) sm_str_data(lctx->lctx_str));
}
else {
sm_io_fputs(lctx->lctx_fp, (const uchar *) sm_log_tstamp());
#if SM_LOG_SEVERITY
sm_io_fprintf(lctx->lctx_fp, "sev=%s, ", sm_l2t(priority));
#endif
va_start(va, format);
sm_io_vfprintf(lctx->lctx_fp, format, va);
va_end(va);
sm_putc(lctx->lctx_fp, '\n');
#if SM_LOG_ROTATE
if (++lctx->lctx_entries > MAX_LOG_ENTRIES)
sm_log_rotate(lctx);
#endif
}
#if MTA_USE_PTHREADS
r = pthread_mutex_unlock(&lctx->lctx_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_LOG, r);
#endif /* MTA_USE_PTHREADS */
return ret;
}
/*
** SM_LOG_VWRITE -- Write a logfile entry
**
** Parameters:
** lctx -- log context
** category -- category
** module -- module
** priority -- priority
** format -- format
** args -- arguments
**
** Returns:
** SM_SUCCESS except for (un)lock errors
*/
sm_ret_T
sm_log_vwrite(sm_log_ctx_P lctx, sm_logcategory_P category, sm_logmodule_P module, int priority, uint level, const char *format, va_list args)
{
#if MTA_USE_PTHREADS
int r;
#endif
sm_ret_T ret;
/* Allow NULL context, necessary for emergence logging. */
if (lctx != NULL) {
SM_IS_LOGCTX(lctx);
if (lctx->lctx_dbg_level < level)
return SM_SUCCESS;
}
/* HACK: this doesn't really work, see begin of file */
if (NULL == lctx) {
int r, save_errno;
char *log;
log = NULL;
r = sm_vasprintf(&log, format, args);
save_errno = errno;
if (r != -1)
syslog(priority, "%.*s", LOG_LEN_MAX, log);
SM_FREE(log);
return (r != -1) ? SM_SUCCESS
: sm_error_perm(SM_EM_LOG, save_errno);
}
ret = SM_SUCCESS;
#if MTA_USE_PTHREADS
r = pthread_mutex_lock(&lctx->lctx_mutex);
SM_LOCK_OK(r);
if (r != 0) {
/* ret = sm_error_perm(SM_EM_LOG, r); */
return sm_error_perm(SM_EM_LOG, r);
}
#endif /* MTA_USE_PTHREADS */
if (NULL == lctx->lctx_fp) {
sm_str_clr(lctx->lctx_str);
#if SM_LOG_SEVERITY
sm_str_scat(lctx->lctx_str, sm_l2t(priority));
#endif
sm_strvprintf(lctx->lctx_str, format, args);
syslog(priority, "%.*s", (int) sm_str_getlen(lctx->lctx_str),
(const char *) sm_str_data(lctx->lctx_str));
}
else {
sm_io_fputs(lctx->lctx_fp, (const uchar *) sm_log_tstamp());
#if SM_LOG_SEVERITY
sm_io_fprintf(lctx->lctx_fp, "sev=%s, ", sm_l2t(priority));
#endif
sm_io_vfprintf(lctx->lctx_fp, format, args);
sm_putc(lctx->lctx_fp, '\n');
#if SM_LOG_ROTATE
if (++lctx->lctx_entries > MAX_LOG_ENTRIES)
sm_log_rotate(lctx);
#endif
}
#if MTA_USE_PTHREADS
r = pthread_mutex_unlock(&lctx->lctx_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_LOG, r);
#endif /* MTA_USE_PTHREADS */
return ret;
}
#if 0
sm_ret_T
sm_log_write1(sm_log_ctx_P lctx, sm_logcategory_P category, sm_logmodule_P module, int priority, int level, const char *format, ...)
{
SM_IS_LOGCTX(lctx);
return SM_SUCCESS;
}
sm_ret_T
sm_log_vwrite1(sm_log_ctx_P lctx, sm_logcategory_P category, sm_logmodule_P module, int priority, int level, const char *format, va_list args)
{
SM_IS_LOGCTX(lctx);
return SM_SUCCESS;
}
#endif /* 0 */
sm_ret_T
sm_log_setdebuglevel(sm_log_ctx_P lctx, uint level)
{
SM_IS_LOGCTX(lctx);
lctx->lctx_dbg_level = level;
return SM_SUCCESS;
}
uint
sm_log_getdebuglevel(sm_log_ctx_P lctx)
{
SM_IS_LOGCTX(lctx);
return lctx->lctx_dbg_level;
}
/*
** SM_LOG_WOULDLOG -- Would something be logged?
**
** Parameters:
** lctx -- log context
** category -- category
** module -- module
** level -- log level
**
** Returns:
** SM_SUCCESS except for (un)lock errors
*/
bool
sm_log_wouldlog(sm_log_ctx_P lctx, sm_logcategory_P category, sm_logmodule_P module, uint level)
{
SM_IS_LOGCTX(lctx);
if (NULL == category || 0 == category->smlc_log_level)
if (NULL == module || 0 == module->smlm_log_level)
return lctx->lctx_dbg_level >= level;
else
return module->smlm_log_level >= level;
else
if (NULL == module || 0 == module->smlm_log_level)
return category->smlc_log_level >= level;
else
return module->smlm_log_level >= level &&
category->smlc_log_level >= level;
}
#if 0
sm_ret_T
sm_log_setduplicateinterval(sm_logconfig_P lcfg, uint interval)
{
SM_IS_LOGCFG(lcfg);
return SM_SUCCESS;
}
uint
sm_log_getduplicateinterval(sm_logconfig_P lcfg)
{
SM_IS_LOGCFG(lcfg);
return SM_SUCCESS;
}
#endif /* 0 */
/* ARGSUSED1 */
sm_ret_T
sm_log_settag(sm_logconfig_P lcfg, const char *tag)
{
SM_IS_LOGCFG(lcfg);
return SM_SUCCESS;
}
sm_ret_T
sm_log_gettag(sm_logconfig_P lcfg)
{
SM_IS_LOGCFG(lcfg);
return SM_SUCCESS;
}
sm_ret_T
sm_log_opensyslog(const char *tag, int options, int facility)
{
openlog(tag, options, facility);
return SM_SUCCESS;
}
sm_ret_T
sm_log_closesyslog(void)
{
closelog();
return SM_SUCCESS;
}
sm_ret_T
sm_log_closefilelogs(sm_log_ctx_P lctx)
{
SM_IS_LOGCTX(lctx);
return SM_SUCCESS;
}
sm_ret_T
sm_log_categorybyname(sm_log_ctx_P lctx, const char *name, sm_logcategory_P *pcategories)
{
uint ul;
sm_logcategory_P categories;
SM_IS_LOGCTX(lctx);
SM_REQUIRE(name != NULL);
SM_REQUIRE(pcategories != NULL);
for (ul = 0; ul < SM_ARRAY_SIZE(lctx->lctx_cats); ul++) {
categories = lctx->lctx_cats[ul];
if (NULL == categories)
continue;
while (categories->smlc_name != NULL) {
if (strcmp(name, categories->smlc_name) == 0) {
*pcategories = categories;
return SM_SUCCESS;
}
++categories;
}
}
return sm_error_perm(SM_EM_LOG, SM_E_NOTFOUND);
}
sm_ret_T
sm_log_modulebyname(sm_log_ctx_P lctx, const char *name, sm_logmodule_P *pmodules)
{
uint u;
sm_logmodule_P modules;
SM_IS_LOGCTX(lctx);
SM_REQUIRE(name != NULL);
SM_REQUIRE(pmodules != NULL);
for (u = 0; u < SM_ARRAY_SIZE(lctx->lctx_mods); u++) {
modules = lctx->lctx_mods[u];
if (NULL == modules)
continue;
while (modules->smlm_name != NULL) {
if (strcmp(name, modules->smlm_name) == 0) {
*pmodules = modules;
return SM_SUCCESS;
}
++modules;
}
}
return sm_error_perm(SM_EM_LOG, SM_E_NOTFOUND);
}
sm_ret_T
sm_log_setcontext(sm_log_ctx_P lctx)
{
SM_IS_LOGCTX(lctx);
return SM_SUCCESS;
}
/*
** SM_LOG_CAT_SET_LEVEL -- Set log level per category
**
** Parameters:
** lctx -- log context
** name -- name of category
** format -- format
**
** Returns:
** usual sm_error code.
**
** Locking: none
*/
sm_ret_T
sm_log_cat_set_level(sm_log_ctx_P lctx, const char *name, uint level)
{
sm_ret_T ret;
sm_logcategory_P categories;
SM_IS_LOGCTX(lctx);
SM_REQUIRE(name != NULL);
ret = sm_log_categorybyname(lctx, name, &categories);
if (sm_is_err(ret))
return ret;
SM_ASSERT(categories != NULL);
categories->smlc_log_level = level;
return SM_SUCCESS;
}
sm_ret_T
sm_log_mod_set_level(sm_log_ctx_P lctx, const char *name, uint level)
{
sm_ret_T ret;
sm_logmodule_P modules;
SM_IS_LOGCTX(lctx);
SM_REQUIRE(name != NULL);
ret = sm_log_modulebyname(lctx, name, &modules);
if (sm_is_err(ret))
return ret;
SM_ASSERT(modules != NULL);
modules->smlm_log_level = level;
return SM_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1