summaryrefslogtreecommitdiffstats
path: root/common/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/log.c')
-rw-r--r--common/log.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/common/log.c b/common/log.c
new file mode 100644
index 00000000..3dae3a41
--- /dev/null
+++ b/common/log.c
@@ -0,0 +1,296 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ xrdp: A Remote Desktop Protocol server.
+ Copyright (C) Jay Sorg 2005-2009
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "os_calls.h"
+
+#include "log.h"
+
+/**
+ *
+ * @brief Opens log file
+ * @param fname log file name
+ * @return see open(2) return values
+ *
+ */
+static int DEFAULT_CC
+log_file_open(const char* fname)
+{
+ return open(fname, O_WRONLY | O_CREAT | O_APPEND | O_SYNC, S_IRUSR |
+ S_IWUSR);
+}
+
+/**
+ *
+ * @brief Converts xrdp log level to syslog logging level
+ * @param xrdp logging level
+ * @return syslog equivalent logging level
+ *
+ */
+static int DEFAULT_CC
+log_xrdp2syslog(const int lvl)
+{
+ switch (lvl)
+ {
+ case LOG_LEVEL_ALWAYS:
+ return LOG_CRIT;
+ case LOG_LEVEL_ERROR:
+ return LOG_ERR;
+ case LOG_LEVEL_WARNING:
+ return LOG_WARNING;
+ case LOG_LEVEL_INFO:
+ return LOG_INFO;
+ /* case LOG_LEVEL_DEBUG: */
+ default:
+ return LOG_DEBUG;
+ }
+}
+
+/**
+ *ring
+ * @brief Converts xrdp log level to syslog logging level
+ * @param lvl logging level
+ * @param str pointer to a st
+ * @return syslog equivalent logging level
+ *
+ */
+static void DEFAULT_CC
+log_lvl2str(int lvl, char* str)
+{
+ switch (lvl)
+ {
+ case LOG_LEVEL_ALWAYS:
+ snprintf(str, 9, "%s", "[CORE ] ");
+ break;
+ case LOG_LEVEL_ERROR:
+ snprintf(str, 9, "%s", "[ERROR] ");
+ break;
+ case LOG_LEVEL_WARNING:
+ snprintf(str, 9, "%s", "[WARN ] ");
+ break;
+ case LOG_LEVEL_INFO:
+ snprintf(str, 9, "%s", "[INFO ] ");
+ break;
+ /* case LOG_LEVEL_DEBUG: */
+ default:
+ snprintf(str, 9, "%s", "[DEBUG] ");
+ break;
+ }
+}
+
+/******************************************************************************/
+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)
+{
+ if (0 == l_cfg)
+ {
+ return LOG_ERROR_MALLOC;
+ }
+
+ /* if logfile is NULL, we use a default logfile */
+ if (0 == l_cfg->log_file)
+ {
+ l_cfg->log_file = g_strdup("./myprogram.log");
+ }
+
+ /* if progname is NULL, we use a default name */
+ if (0 == l_cfg->program_name)
+ {
+ l_cfg->program_name = g_strdup("myprogram");
+ }
+
+ /* open file */
+ l_cfg->fd = log_file_open(l_cfg->log_file);
+
+ if (-1 == l_cfg->fd)
+ {
+ return LOG_ERROR_FILE_OPEN;
+ }
+
+ /* if syslog is enabled, open it */
+ if (l_cfg->enable_syslog)
+ {
+ openlog(l_cfg->program_name, LOG_CONS | LOG_PID, LOG_DAEMON);
+ }
+
+#ifdef LOG_ENABLE_THREAD
+ pthread_mutexattr_init(&(l_cfg->log_lock_attr));
+ pthread_mutex_init(&(l_cfg->log_lock), &(l_cfg->log_lock_attr));
+#endif
+
+ return LOG_STARTUP_OK;
+}
+
+/******************************************************************************/
+void DEFAULT_CC
+log_end(struct log_config* l_cfg)
+{
+ /* if log is closed, quit silently */
+ if (0 == l_cfg)
+ {
+ return;
+ }
+
+ /* closing log file */
+ log_message(l_cfg, 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);
+
+ /* if syslog is enabled, close it */
+ if (l_cfg->enable_syslog)
+ {
+ closelog();
+ }
+
+ /* freeing allocated memory */
+ if (0 != l_cfg->log_file)
+ {
+ g_free(l_cfg->log_file);
+ l_cfg->log_file = 0;
+ }
+ if (0 != l_cfg->program_name)
+ {
+ g_free(l_cfg->program_name);
+ l_cfg->program_name = 0;
+ }
+}
+
+/******************************************************************************/
+int DEFAULT_CC
+log_text2level(char* buf)
+{
+ if (0 == g_strcasecmp(buf, "0") ||
+ 0 == g_strcasecmp(buf, "core"))
+ {
+ return LOG_LEVEL_ALWAYS;
+ }
+ else if (0 == g_strcasecmp(buf, "1") ||
+ 0 == g_strcasecmp(buf, "error"))
+ {
+ return LOG_LEVEL_ERROR;
+ }
+ else if (0 == g_strcasecmp(buf, "2") ||
+ 0 == g_strcasecmp(buf, "warn") ||
+ 0 == g_strcasecmp(buf, "warning"))
+ {
+ return LOG_LEVEL_WARNING;
+ }
+ else if (0 == g_strcasecmp(buf, "3") ||
+ 0 == g_strcasecmp(buf, "info"))
+ {
+ return LOG_LEVEL_INFO;
+ }
+ return LOG_LEVEL_DEBUG;
+}