summaryrefslogtreecommitdiffstats
path: root/common/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/log.c')
-rw-r--r--common/log.c547
1 files changed, 430 insertions, 117 deletions
diff --git a/common/log.c b/common/log.c
index 7bbdfc06..040b6e18 100644
--- a/common/log.c
+++ b/common/log.c
@@ -24,11 +24,22 @@
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
-
+#include "list.h"
#include "os_calls.h"
+/* Add a define here so that the log.h will hold more information
+ * when compiled from this C file.
+ * When compiled normally the log.h file only contain the public parts
+ * of the operators in this file. */
+#define LOGINTERNALSTUFF
#include "log.h"
+/* Here we store the current state and configuration of the log */
+static struct log_config* staticLogConfig = NULL;
+
+/*This file first start with all private functions.
+ In the end of the file the public functions is defined*/
+
/**
*
* @brief Opens log file
@@ -36,11 +47,15 @@
* @return see open(2) return values
*
*/
-static int DEFAULT_CC
-log_file_open(const char* fname)
+int DEFAULT_CC
+internal_log_file_open(const char* fname)
{
- return open(fname, O_WRONLY | O_CREAT | O_APPEND | O_SYNC, S_IRUSR |
- S_IWUSR);
+ int ret = -1 ;
+ if(fname!=NULL)
+ {
+ ret = open(fname, O_WRONLY | O_CREAT | O_APPEND | O_SYNC, S_IRUSR |S_IWUSR);
+ }
+ return ret ;
}
/**
@@ -50,8 +65,8 @@ log_file_open(const char* fname)
* @return syslog equivalent logging level
*
*/
-static int DEFAULT_CC
-log_xrdp2syslog(const int lvl)
+int DEFAULT_CC
+internal_log_xrdp2syslog(const enum logLevels lvl)
{
switch (lvl)
{
@@ -63,22 +78,23 @@ log_xrdp2syslog(const int lvl)
return LOG_WARNING;
case LOG_LEVEL_INFO:
return LOG_INFO;
- /* case LOG_LEVEL_DEBUG: */
+ case LOG_LEVEL_DEBUG:
+ return LOG_DEBUG;
default:
+ g_writeln("Undefined log level - programming error");
return LOG_DEBUG;
}
}
/**
- *ring
- * @brief Converts xrdp log level to syslog logging level
+ * @brief Converts xrdp log levels to textual logging levels
* @param lvl logging level
- * @param str pointer to a st
- * @return syslog equivalent logging level
+ * @param str pointer to a string, must be allocated before
+ * @return The log string in str pointer.
*
*/
-static void DEFAULT_CC
-log_lvl2str(int lvl, char* str)
+void DEFAULT_CC
+internal_log_lvl2str(const enum logLevels lvl, char* str)
{
switch (lvl)
{
@@ -94,115 +110,44 @@ log_lvl2str(int lvl, char* str)
case LOG_LEVEL_INFO:
snprintf(str, 9, "%s", "[INFO ] ");
break;
- /* case LOG_LEVEL_DEBUG: */
- default:
+ case LOG_LEVEL_DEBUG:
snprintf(str, 9, "%s", "[DEBUG] ");
break;
+ default:
+ snprintf(str, 9, "%s", "PRG ERR!");
+ g_writeln("Programming error - undefined log level!!!");
}
}
/******************************************************************************/
-int DEFAULT_CC
-log_message(struct log_config* l_cfg, const unsigned int lvl, const char* msg, ...)
-{
- char buff[LOG_BUFFER_SIZE + 31]; /* 19 (datetime) 4 (space+cr+lf+\0) */
- va_list ap;
- int len = 0;
- int rv;
- time_t now_t;
- struct tm* now;
-
- rv = 0;
- if (0 == l_cfg)
- {
- return LOG_ERROR_NO_CFG;
- }
-
- if (0 > l_cfg->fd)
- {
- return LOG_ERROR_FILE_NOT_OPEN;
- }
-
- now_t = time(&now_t);
- now = localtime(&now_t);
-
- snprintf(buff, 21, "[%.4d%.2d%.2d-%.2d:%.2d:%.2d] ", (now->tm_year) + 1900,
- (now->tm_mon) + 1, now->tm_mday, now->tm_hour, now->tm_min,
- now->tm_sec);
-
- log_lvl2str(lvl, buff + 20);
-
- va_start(ap, msg);
- len = vsnprintf(buff + 28, LOG_BUFFER_SIZE, msg, ap);
- va_end(ap);
-
- /* checking for truncated messages */
- if (len > LOG_BUFFER_SIZE)
- {
- log_message(l_cfg, LOG_LEVEL_WARNING, "next message will be truncated");
- }
-
- /* forcing the end of message string */
- #ifdef _WIN32
- buff[len + 28] = '\r';
- buff[len + 29] = '\n';
- buff[len + 30] = '\0';
- #else
- #ifdef _MACOS
- buff[len + 28] = '\r';
- buff[len + 29] = '\0';
- #else
- buff[len + 28] = '\n';
- buff[len + 29] = '\0';
- #endif
- #endif
-
- if (l_cfg->enable_syslog && (lvl <= l_cfg->log_level))
- {
- /* log to syslog */
- syslog(log_xrdp2syslog(lvl), buff + 20);
- }
-
- if (lvl <= l_cfg->log_level)
- {
- /* log to console */
- g_printf((char*)buff);
-
- /* log to application logfile */
-#ifdef LOG_ENABLE_THREAD
- pthread_mutex_lock(&(l_cfg->log_lock));
-#endif
- rv = g_file_write(l_cfg->fd, (char*)buff, g_strlen((char*)buff));
-#ifdef LOG_ENABLE_THREAD
- pthread_mutex_unlock(&(l_cfg->log_lock));
-#endif
- }
- return rv;
-}
/******************************************************************************/
-int DEFAULT_CC
-log_start(struct log_config* l_cfg)
+enum logReturns DEFAULT_CC
+internal_log_start(struct log_config* l_cfg)
{
+ enum logReturns ret = LOG_GENERAL_ERROR;
if (0 == l_cfg)
{
- return LOG_ERROR_MALLOC;
+ ret = LOG_ERROR_MALLOC;
+ return ret;
}
- /* if logfile is NULL, we use a default logfile */
+ /* if logfile is NULL, we return error */
if (0 == l_cfg->log_file)
{
- l_cfg->log_file = g_strdup("./myprogram.log");
+ g_writeln("log_file not properly assigned");
+ return ret ;
}
- /* if progname is NULL, we use a default name */
+ /* if progname is NULL, we ureturn error */
if (0 == l_cfg->program_name)
{
- l_cfg->program_name = g_strdup("myprogram");
+ g_writeln("program_name not properly assigned");
+ return ret ;
}
/* open file */
- l_cfg->fd = log_file_open(l_cfg->log_file);
+ l_cfg->fd = internal_log_file_open(l_cfg->log_file);
if (-1 == l_cfg->fd)
{
@@ -224,29 +169,24 @@ log_start(struct log_config* l_cfg)
}
/******************************************************************************/
-void DEFAULT_CC
-log_end(struct log_config* l_cfg)
+enum logReturns DEFAULT_CC
+internal_log_end(struct log_config* l_cfg)
{
+ enum logReturns ret = LOG_GENERAL_ERROR ;
/* if log is closed, quit silently */
if (0 == l_cfg)
{
- return;
+ return ret;
}
/* closing log file */
- log_message(l_cfg, LOG_LEVEL_ALWAYS, "shutting down log subsystem...");
+ log_message(LOG_LEVEL_ALWAYS, "shutting down log subsystem...");
if (0 > l_cfg->fd)
{
- /* if syslog is enabled, close it */
- if (l_cfg->enable_syslog)
- {
- closelog();
- }
- }
-
- /* closing logfile... */
- g_file_close(l_cfg->fd);
+ /* closing logfile... */
+ g_file_close(l_cfg->fd);
+ }
/* if syslog is enabled, close it */
if (l_cfg->enable_syslog)
@@ -265,11 +205,17 @@ log_end(struct log_config* l_cfg)
g_free(l_cfg->program_name);
l_cfg->program_name = 0;
}
+ ret = LOG_STARTUP_OK ;
+ return ret ;
}
-/******************************************************************************/
-int DEFAULT_CC
-log_text2level(char* buf)
+/**
+ * Converts a string representing th log level to a value
+ * @param buf
+ * @return
+ */
+enum logLevels DEFAULT_CC
+internal_log_text2level(char* buf)
{
if (0 == g_strcasecmp(buf, "0") ||
0 == g_strcasecmp(buf, "core"))
@@ -292,5 +238,372 @@ log_text2level(char* buf)
{
return LOG_LEVEL_INFO;
}
+ else if (0 == g_strcasecmp(buf, "4") ||
+ 0 == g_strcasecmp(buf, "debug"))
+ {
+ return LOG_LEVEL_DEBUG;
+ }
+ g_writeln("Your configured log level is corrupt - we use debug log level");
return LOG_LEVEL_DEBUG;
}
+
+enum logReturns DEFAULT_CC
+internalReadConfiguration(const char *inFilename,const char *applicationName)
+{
+ int fd;
+ enum logReturns ret = LOG_GENERAL_ERROR ;
+ struct list* sec;
+ struct list* param_n;
+ struct list* param_v;
+
+ if(inFilename==NULL)
+ {
+ g_writeln("The inifile is null to readConfiguration!");
+ return ret ;
+ }
+ fd = g_file_open(inFilename);
+ if (-1 == fd)
+ {
+ ret = LOG_ERROR_NO_CFG ;
+ g_writeln("We could not open the configuration file to read log parameters");
+ return ret ;
+ }
+ // we initialize the memory for the configuration and set all content to zero.
+ ret = internalInitAndAllocStruct();
+ if(ret!=LOG_STARTUP_OK){
+ return ret ;
+ }
+
+ sec = list_create();
+ sec->auto_free = 1;
+ file_read_sections(fd, sec);
+ param_n = list_create();
+ param_n->auto_free = 1;
+ param_v = list_create();
+ param_v->auto_free = 1;
+
+ /* read logging config */
+ ret = internal_config_read_logging(fd, staticLogConfig, param_n,
+ param_v, applicationName);
+ if(ret!=LOG_STARTUP_OK)
+ {
+ return ret ;
+ }
+ /* cleanup */
+ list_delete(sec);
+ list_delete(param_v);
+ list_delete(param_n);
+ g_file_close(fd);
+ return ret ;
+}
+
+
+/******************************************************************************/
+enum logReturns DEFAULT_CC
+internal_config_read_logging(int file, struct log_config* lc, struct list* param_n,
+ struct list* param_v,const char *applicationName)
+{
+ int i;
+ char* buf;
+
+ list_clear(param_v);
+ list_clear(param_n);
+
+ /* setting defaults */
+ lc->program_name = g_strdup(applicationName);
+ lc->log_file = 0;
+ lc->fd = 0;
+ lc->log_level = LOG_LEVEL_DEBUG;
+ lc->enable_syslog = 0;
+ lc->syslog_level = LOG_LEVEL_DEBUG;
+
+ file_read_section(file, SESMAN_CFG_LOGGING, param_n, param_v);
+ for (i = 0; i < param_n->count; i++)
+ {
+ buf = (char*)list_get_item(param_n, i);
+ if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_FILE))
+ {
+ lc->log_file = g_strdup((char*)list_get_item(param_v, i));
+ }
+ if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_LEVEL))
+ {
+ lc->log_level = internal_log_text2level((char*)list_get_item(param_v, i));
+ }
+ if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_SYSLOG))
+ {
+ lc->enable_syslog = text2bool((char*)list_get_item(param_v, i));
+ }
+ if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_SYSLOG_LEVEL))
+ {
+ lc->syslog_level = internal_log_text2level((char*)list_get_item(param_v, i));
+ }
+ }
+
+ if (0 == lc->log_file)
+ {
+ lc->log_file=g_strdup("./sesman.log");
+ }
+
+ g_printf("logging configuration:\r\n");
+ g_printf("\tLogFile: %s\r\n",lc->log_file);
+ g_printf("\tLogLevel: %i\r\n", lc->log_level);
+ g_printf("\tEnableSyslog: %i\r\n", lc->enable_syslog);
+ g_printf("\tSyslogLevel: %i\r\n", lc->syslog_level);
+ return LOG_STARTUP_OK;
+}
+
+enum logReturns DEFAULT_CC
+internalInitAndAllocStruct()
+{
+ enum logReturns ret = LOG_GENERAL_ERROR ;
+ staticLogConfig = g_malloc(sizeof(struct log_config),1);
+ if(staticLogConfig!=NULL)
+ {
+ staticLogConfig->fd = -1;
+ staticLogConfig->enable_syslog = 0 ;
+ ret = LOG_STARTUP_OK ;
+ }
+ else
+ {
+ g_writeln("could not allocate memory for log struct") ;
+ ret = LOG_ERROR_MALLOC ;
+ }
+ return ret ;
+}
+
+/*
+ * Here below the public functions
+ */
+
+
+/**
+ *
+ * @brief Reads sesman configuration
+ * @param s translates the strings "1", "true" and "yes" in 1 (true) and other strings in 0
+ * @return 0 on false, 1 on 1,true, yes
+ *
+ */
+int APP_CC
+text2bool(char* s)
+{
+ if (0 == g_strcasecmp(s, "1") ||
+ 0 == g_strcasecmp(s, "true") ||
+ 0 == g_strcasecmp(s, "yes"))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+
+enum logReturns DEFAULT_CC
+log_start_from_param(const struct log_config* iniParams)
+{
+ enum logReturns ret = LOG_GENERAL_ERROR ;
+ if(staticLogConfig!=NULL)
+ {
+ log_message(LOG_LEVEL_ALWAYS,"Log already initialized");
+ return ret ;
+ }
+ if(iniParams==NULL)
+ {
+ g_writeln("inparam to log_start_from_param is NULL");
+ return ret ;
+ }
+ else
+ {
+ /*Copy the struct information*/
+ ret = internalInitAndAllocStruct();
+ if(ret!=LOG_STARTUP_OK)
+ {
+ return ret ;
+ }
+ staticLogConfig->enable_syslog = iniParams->enable_syslog;
+ staticLogConfig->fd = iniParams->fd;
+ staticLogConfig->log_file = g_strdup(iniParams->log_file);
+ staticLogConfig->log_level = iniParams->log_level ;
+ staticLogConfig->log_lock = iniParams->log_lock ;
+ staticLogConfig->log_lock_attr = iniParams->log_lock_attr ;
+ staticLogConfig->program_name = g_strdup(iniParams->program_name);
+ staticLogConfig->syslog_level = iniParams->syslog_level;
+ ret = internal_log_start(staticLogConfig);
+ if(ret!=LOG_STARTUP_OK)
+ {
+ g_writeln("Could not start log");
+ if(staticLogConfig!=NULL)
+ {
+ g_free(staticLogConfig);
+ staticLogConfig = NULL ;
+ }
+ }
+ }
+ return ret ;
+}
+
+
+/**
+ * This function initialize the log facilities according to the configuration
+ * file, that is described by the in parameter.
+ * @param iniFile
+ * @param applicationName, the name that is used in the log for the running application
+ * @return 0 on success
+ */
+enum logReturns DEFAULT_CC
+log_start(const char *iniFile, const char *applicationName)
+{
+ enum logReturns ret = LOG_GENERAL_ERROR ;
+ if(applicationName==NULL)
+ {
+ g_writeln("Programming error your application name cannot be null");
+ return ret ;
+ }
+ ret = internalReadConfiguration(iniFile, applicationName) ;
+ if(ret==LOG_STARTUP_OK)
+ {
+ ret = internal_log_start(staticLogConfig);
+ if(ret!=LOG_STARTUP_OK)
+ {
+ g_writeln("Could not start log");
+ if(staticLogConfig!=NULL){
+ g_free(staticLogConfig);
+ staticLogConfig = NULL ;
+ }
+ }
+ }
+ else
+ {
+ g_writeln("Error reading configuration for log based on config: %s",iniFile);
+ }
+ return ret ;
+}
+
+/**
+ * Function that terminates all logging
+ * @return
+ */
+enum logReturns DEFAULT_CC
+log_end()
+{
+ enum logReturns ret = LOG_GENERAL_ERROR;
+ ret = internal_log_end(staticLogConfig);
+ if(staticLogConfig!=NULL)
+ {
+ g_free(staticLogConfig);
+ staticLogConfig = NULL ;
+ }
+ return ret ;
+}
+
+enum logReturns DEFAULT_CC
+log_message( const enum logLevels lvl,
+const char* msg, ...)
+{
+ char buff[LOG_BUFFER_SIZE + 31]; /* 19 (datetime) 4 (space+cr+lf+\0) */
+ va_list ap;
+ int len = 0;
+ enum logReturns rv = LOG_STARTUP_OK;
+ int writereply = 0 ;
+ time_t now_t;
+ struct tm* now;
+ enum logReturns ret = LOG_GENERAL_ERROR;
+ if(staticLogConfig==NULL)
+ {
+ g_writeln("The log reference is NULL - log not initialized properly");
+ return LOG_ERROR_NO_CFG;
+ }
+ if (0 > staticLogConfig->fd && staticLogConfig->enable_syslog==0)
+ {
+ return LOG_ERROR_FILE_NOT_OPEN;
+ }
+
+ now_t = time(&now_t);
+ now = localtime(&now_t);
+
+ snprintf(buff, 21, "[%.4d%.2d%.2d-%.2d:%.2d:%.2d] ", (now->tm_year) + 1900,
+ (now->tm_mon) + 1, now->tm_mday, now->tm_hour, now->tm_min,
+ now->tm_sec);
+
+ internal_log_lvl2str(lvl, buff + 20);
+
+ va_start(ap, msg);
+ len = vsnprintf(buff + 28, LOG_BUFFER_SIZE, msg, ap);
+ va_end(ap);
+
+ /* checking for truncated messages */
+ if (len > LOG_BUFFER_SIZE)
+ {
+ log_message(LOG_LEVEL_WARNING,"next message will be truncated");
+ }
+
+ /* forcing the end of message string */
+ #ifdef _WIN32
+ buff[len + 28] = '\r';
+ buff[len + 29] = '\n';
+ buff[len + 30] = '\0';
+ #else
+ #ifdef _MACOS
+ buff[len + 28] = '\r';
+ buff[len + 29] = '\0';
+ #else
+ buff[len + 28] = '\n';
+ buff[len + 29] = '\0';
+ #endif
+ #endif
+
+ if (staticLogConfig->enable_syslog && (lvl <= staticLogConfig->syslog_level))
+ {
+ /* log to syslog*/
+ /* %s fix compiler warning 'not a string literal' */
+ syslog(internal_log_xrdp2syslog(lvl), "(%d)(%d)%s",g_getpid(),g_gettid(),(char *)(buff + 20));
+ }
+
+ if (lvl <= staticLogConfig->log_level)
+ {
+ /* log to console */
+ g_printf((char*)buff);
+
+ /* log to application logfile */
+#ifdef LOG_ENABLE_THREAD
+ pthread_mutex_lock(&(staticLogConfig->log_lock));
+#endif
+ if(staticLogConfig->fd>0)
+ {
+ writereply = g_file_write(staticLogConfig->fd, (char*)buff, g_strlen((char*)buff));
+ if(writereply <= 0)
+ {
+ rv = LOG_ERROR_NULL_FILE;
+ }
+ }
+#ifdef LOG_ENABLE_THREAD
+ pthread_mutex_unlock(&(staticLogConfig->log_lock));
+#endif
+ }
+ return rv;
+}
+
+
+/**
+ * Return the configured log file name
+ * @return
+ */
+char *getLogFile(char *replybuf, int bufsize)
+{
+ if(staticLogConfig )
+ {
+ if(staticLogConfig->log_file)
+ {
+ g_strncpy(replybuf, staticLogConfig->log_file,bufsize);
+ }
+ else
+ {
+ g_sprintf(replybuf,"The log_file name is NULL");
+ }
+ }
+ else
+ {
+ g_snprintf(replybuf,bufsize,"The log is not properly started");
+ }
+ return replybuf ;
+}
+
+