--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <common/log.h>
+
+static int log_mask = MRP_LOG_MASK_ERROR;
+static const char *log_target = MRP_LOG_TO_STDERR;
+static FILE *log_fp;
+
+
+mrp_log_mask_t mrp_log_parse_levels(const char *levels)
+{
+ const char *p;
+ mrp_log_mask_t mask;
+
+ mask = 0;
+
+ if (levels == NULL) {
+ if (mask == 0)
+ mask = 1;
+ else {
+ mask <<= 1;
+ mask |= 1;
+ }
+ }
+ else {
+ p = levels;
+ while (p && *p) {
+# define MATCHES(s, l) (!strcmp(s, l) || \
+ !strncmp(s, l",", sizeof(l",") - 1))
+
+ if (MATCHES(p, "info"))
+ mask |= MRP_LOG_MASK_INFO;
+ else if (MATCHES(p, "error"))
+ mask |= MRP_LOG_MASK_ERROR;
+ else if (MATCHES(p, "warning"))
+ mask |= MRP_LOG_MASK_WARNING;
+ else
+ return -1;
+
+ if ((p = strchr(p, ',')) != NULL)
+ p += 1;
+
+# undef MATCHES
+ }
+ }
+
+ return mask;
+}
+
+
+const char *mrp_log_parse_target(const char *target)
+{
+ if (!strcmp(target, "stderr"))
+ return MRP_LOG_TO_STDERR;
+ if (!strcmp(target, "stdout"))
+ return MRP_LOG_TO_STDOUT;
+ if (!strcmp(target, "syslog"))
+ return MRP_LOG_TO_SYSLOG;
+ else
+ return target;
+}
+
+
+mrp_log_mask_t mrp_log_enable(mrp_log_mask_t enabled)
+{
+ mrp_log_mask_t old_mask = log_mask;
+
+ log_mask |= enabled;
+
+ return old_mask;
+}
+
+
+mrp_log_mask_t mrp_log_disable(mrp_log_mask_t disabled)
+{
+ mrp_log_mask_t old_mask = log_mask;
+
+ log_mask &= ~disabled;
+
+ return old_mask;
+}
+
+
+mrp_log_mask_t mrp_log_set_mask(mrp_log_mask_t enabled)
+{
+ mrp_log_mask_t old_mask = log_mask;
+
+ log_mask = enabled;
+
+ return old_mask;
+}
+
+
+int mrp_log_set_target(const char *target)
+{
+ const char *old_target = log_target;
+ FILE *old_fp = log_fp;
+
+ if (!target || log_target == target)
+ return FALSE;
+
+ if (target == MRP_LOG_TO_SYSLOG) {
+ log_target = target;
+ log_fp = NULL;
+ openlog(NULL, 0, LOG_DAEMON);
+ }
+ else if (target == MRP_LOG_TO_STDERR) {
+ log_target = target;
+ log_fp = stdout;
+ }
+ else if (target == MRP_LOG_TO_STDOUT) {
+ log_target = target;
+ log_fp = stdout;
+ }
+ else {
+ log_target = target;
+ log_fp = fopen(log_target, "a");
+
+ if (log_fp == NULL) {
+ log_target = old_target;
+ log_fp = old_fp;
+
+ return FALSE;
+ }
+ }
+
+ if (old_target == MRP_LOG_TO_SYSLOG)
+ closelog();
+ else if (old_target != MRP_LOG_TO_STDOUT && old_target != MRP_LOG_TO_STDERR)
+ fclose(old_fp);
+
+ return TRUE;
+}
+
+
+void mrp_log_msg(mrp_log_level_t level, const char *file,
+ int line, const char *func, const char *format, ...)
+{
+ va_list ap;
+ int lvl;
+ const char *prefix;
+ char prfx[2*1024];
+
+ (void)file;
+ (void)line;
+
+ if (!(log_mask & (1 << level)))
+ return;
+
+ switch (level) {
+ case MRP_LOG_ERROR: lvl = LOG_ERR; prefix = "E: "; break;
+ case MRP_LOG_WARNING: lvl = LOG_WARNING; prefix = "W: "; break;
+ case MRP_LOG_INFO: lvl = LOG_INFO; prefix = "I: "; break;
+ case MRP_LOG_DEBUG: lvl = LOG_INFO;
+ snprintf(prfx, sizeof(prfx) - 1, "D: [%s] ", func);
+ prfx[sizeof(prfx)-1] = '\0';
+ prefix = prfx;
+ break;
+ default:
+ return;
+ }
+
+ va_start(ap, format);
+
+ if (log_fp == NULL)
+ vsyslog(lvl, format, ap);
+ else {
+ fputs(prefix, log_fp);
+ vfprintf(log_fp, format, ap); fputs("\n", log_fp);
+ fflush(log_fp);
+ }
+
+ va_end(ap);
+}
+
+
+/*
+ * workaround for not being able to initialize log_fp to stderr
+ */
+
+static __attribute__((constructor)) void set_default_logging(void)
+{
+ log_target = MRP_LOG_TO_STDERR;
+ log_fp = stderr;
+}
--- /dev/null
+#ifndef __MURPHY_LOG_H__
+#define __MURPHY_LOG_H__
+
+/** \file
+ * Logging functions and macros.
+ */
+
+#include <syslog.h>
+
+#include <common/macros.h>
+
+MRP_CDECL_BEGIN
+
+#define MRP_LOG_NAME_ERROR "error" /**< name for error level */
+#define MRP_LOG_NAME_WARNING "warning" /**< name for warning level */
+#define MRP_LOG_NAME_INFO "info" /**< name for info level */
+#define MRP_LOG_NAME_DEBUG "debug" /**< name for debug level */
+
+
+/**
+ * Logging levels.
+ */
+typedef enum {
+ MRP_LOG_ERROR = 0, /**< error log level */
+ MRP_LOG_WARNING, /**< warning log level */
+ MRP_LOG_INFO, /**< info log level */
+ MRP_LOG_DEBUG, /**< debug log level */
+} mrp_log_level_t;
+
+
+/**
+ * Logging masks.
+ */
+typedef enum {
+ MRP_LOG_MASK_ERROR = 0x01, /**< error logging mask */
+ MRP_LOG_MASK_WARNING = 0x02, /**< warning logging mask */
+ MRP_LOG_MASK_INFO = 0x04, /**< info logging mask */
+ MRP_LOG_MASK_DEBUG = 0x08, /**< debug logging mask */
+} mrp_log_mask_t;
+
+#define MRP_LOG_MASK(level) (1 << ((level) - 1)) /**< mask of level */
+#define MRP_LOG_UPTO(level) ((1 << (level)) - 1) /**< mask up to level */
+
+/** Parse a string of comma-separated log level names to a log mask. */
+mrp_log_mask_t mrp_log_parse_levels(const char *levels);
+
+/** Clear current logging level and enable levels in mask. */
+mrp_log_mask_t mrp_log_set_mask(mrp_log_mask_t mask);
+
+/** Enable logging for levels in mask. */
+mrp_log_mask_t mrp_log_enable(mrp_log_mask_t mask);
+
+/** Disable logging for levels in mask. */
+mrp_log_mask_t mrp_log_disable(mrp_log_mask_t mask);
+
+/**
+ * Logging target names.
+ */
+#define MRP_LOG_NAME_STDOUT "stdout"
+#define MRP_LOG_NAME_STDERR "stderr"
+#define MRP_LOG_NAME_SYSLOG "syslog"
+
+/**
+ * Logging targets.
+ */
+#define MRP_LOG_TO_STDOUT ((const char *)1)
+#define MRP_LOG_TO_STDERR ((const char *)2)
+#define MRP_LOG_TO_SYSLOG ((const char *)3)
+#define MRP_LOG_TO_FILE(path) ((const char *)(path))
+
+/** Parse a log target name to MRP_LOG_TO_*. */
+const char *mrp_log_parse_target(const char *target);
+
+/** Set logging target. */
+int mrp_log_set_target(const char *target);
+
+/** Log an error. */
+#define mrp_log_error(fmt, args...) \
+ mrp_log_msg(MRP_LOG_ERROR, __LOC__, fmt , ## args)
+
+/** Log a warning. */
+#define mrp_log_warning(fmt, args...) \
+ mrp_log_msg(MRP_LOG_WARNING, __LOC__, fmt , ## args)
+
+/** Log an informational message. */
+#define mrp_log_info(fmt, args...) \
+ mrp_log_msg(MRP_LOG_INFO, __LOC__, fmt , ## args)
+
+/** Log an (unclassified) debugging message. */
+#define mrp_debug(fmt, args...) \
+ mrp_log_msg(MRP_LOG_DEBUG, __LOC__, fmt , ## args)
+
+/** Generic logging function. */
+void mrp_log_msg(mrp_log_level_t level,
+ const char *file, int line, const char *func,
+ const char *format, ...) MRP_PRINTF_LIKE(5, 6);
+
+MRP_CDECL_END
+
+#endif /* __MURPHY_LOG_H__ */