diff options
Diffstat (limited to 'common/log.c')
-rw-r--r-- | common/log.c | 547 |
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 ; +} + + |