summaryrefslogtreecommitdiffstats
path: root/src/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/log.c')
-rw-r--r--src/log.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..ddfc14a
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,279 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/* $OpenBSD: log.c,v 1.11 2007/12/07 17:17:00 reyk Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include "log.h"
+
+/* By default, logging is done on stderr. */
+static int use_syslog = 0;
+/* Default debug level */
+static int debug = 0;
+
+/* Logging can be modified by providing an appropriate log handler. */
+static void (*logh)(int severity, const char *msg) = NULL;
+
+static void vlog(int, const char *, const char *, va_list);
+static void logit(int, const char *, const char *, ...);
+
+#define MAX_DBG_TOKENS 40
+static const char *tokens[MAX_DBG_TOKENS + 1] = { NULL };
+
+void
+log_init(int n_syslog, int n_debug, const char *progname)
+{
+ use_syslog = n_syslog;
+ debug = n_debug;
+
+ if (use_syslog) openlog(progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
+
+ tzset();
+}
+
+void
+log_level(int n_debug)
+{
+ if (n_debug >= 0) debug = n_debug;
+}
+
+void
+log_register(void (*cb)(int, const char *))
+{
+ logh = cb;
+}
+
+void
+log_accept(const char *token)
+{
+ int i;
+ for (i = 0; i < MAX_DBG_TOKENS; i++) {
+ if (tokens[i] == NULL) {
+ tokens[i + 1] = NULL;
+ tokens[i] = token;
+ return;
+ }
+ }
+}
+
+static void
+logit(int pri, const char *token, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vlog(pri, token, fmt, ap);
+ va_end(ap);
+}
+
+static char *
+date()
+{
+ /* Return the current date as incomplete ISO 8601 (2012-12-12T16:13:30) */
+ static char date[] = "2012-12-12T16:13:30";
+ time_t t = time(NULL);
+ struct tm *tmp = localtime(&t);
+ strftime(date, sizeof(date), "%Y-%m-%dT%H:%M:%S", tmp);
+ return date;
+}
+
+static const char *
+translate(int fd, int priority)
+{
+ /* Translate a syslog priority to a string. With colors if the output is a
+ * terminal. */
+ int tty = isatty(fd);
+ switch (tty) {
+ case 1:
+ switch (priority) {
+ case LOG_EMERG:
+ return "\033[1;37;41m[EMRG";
+ case LOG_ALERT:
+ return "\033[1;37;41m[ALRT";
+ case LOG_CRIT:
+ return "\033[1;37;41m[CRIT";
+ case LOG_ERR:
+ return "\033[1;31m[ ERR";
+ case LOG_WARNING:
+ return "\033[1;33m[WARN";
+ case LOG_NOTICE:
+ return "\033[1;34m[NOTI";
+ case LOG_INFO:
+ return "\033[1;34m[INFO";
+ case LOG_DEBUG:
+ return "\033[36m[ DBG";
+ }
+ break;
+ default:
+ switch (priority) {
+ case LOG_EMERG:
+ return "[EMRG";
+ case LOG_ALERT:
+ return "[ALRT";
+ case LOG_CRIT:
+ return "[CRIT";
+ case LOG_ERR:
+ return "[ ERR";
+ case LOG_WARNING:
+ return "[WARN";
+ case LOG_NOTICE:
+ return "[NOTI";
+ case LOG_INFO:
+ return "[INFO";
+ case LOG_DEBUG:
+ return "[ DBG";
+ }
+ }
+ return "[UNKN]";
+}
+
+static void
+vlog(int pri, const char *token, const char *fmt, va_list ap)
+{
+ if (logh) {
+ char *result = NULL;
+ if (vasprintf(&result, fmt, ap) != -1) {
+ logh(pri, result);
+ free(result);
+ return;
+ }
+ /* Otherwise, abort. We don't know if "ap" is still OK. We could
+ * have made a copy, but this is too much overhead for a
+ * situation that shouldn't happen. */
+ return;
+ }
+
+ /* Log to syslog if requested */
+ if (use_syslog) {
+ va_list ap2;
+ va_copy(ap2, ap);
+ vsyslog(pri, fmt, ap2);
+ va_end(ap2);
+ }
+
+ /* Log to standard error in all cases */
+ char *nfmt;
+ /* best effort in out of mem situations */
+ if (asprintf(&nfmt, "%s %s%s%s]%s %s\n", date(), translate(STDERR_FILENO, pri),
+ token ? "/" : "", token ? token : "",
+ isatty(STDERR_FILENO) ? "\033[0m" : "", fmt) == -1) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ } else {
+ vfprintf(stderr, nfmt, ap);
+ free(nfmt);
+ }
+ fflush(stderr);
+}
+
+void
+log_warn(const char *token, const char *emsg, ...)
+{
+ char *nfmt = NULL;
+ va_list ap;
+
+ /* best effort to even work in out of memory situations */
+ if (emsg == NULL)
+ logit(LOG_WARNING, "%s", strerror(errno));
+ else {
+ va_start(ap, emsg);
+
+ if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) {
+ /* we tried it... */
+ vlog(LOG_WARNING, token, emsg, ap);
+ logit(LOG_WARNING, "%s", strerror(errno));
+ } else {
+ vlog(LOG_WARNING, token, nfmt, ap);
+ free(nfmt);
+ }
+ va_end(ap);
+ }
+}
+
+void
+log_warnx(const char *token, const char *emsg, ...)
+{
+ va_list ap;
+
+ va_start(ap, emsg);
+ vlog(LOG_WARNING, token, emsg, ap);
+ va_end(ap);
+}
+
+void
+log_info(const char *token, const char *emsg, ...)
+{
+ va_list ap;
+
+ if (use_syslog || debug > 0 || logh) {
+ va_start(ap, emsg);
+ vlog(LOG_INFO, token, emsg, ap);
+ va_end(ap);
+ }
+}
+
+static int
+log_debug_accept_token(const char *token)
+{
+ int i;
+ if (tokens[0] == NULL) return 1;
+ for (i = 0; (i < MAX_DBG_TOKENS) && (tokens[i] != NULL); i++) {
+ if (!strcmp(tokens[i], token)) return 1;
+ }
+ return 0;
+}
+
+void
+log_debug(const char *token, const char *emsg, ...)
+{
+ va_list ap;
+
+ if ((debug > 1 && log_debug_accept_token(token)) || logh) {
+ va_start(ap, emsg);
+ vlog(LOG_DEBUG, token, emsg, ap);
+ va_end(ap);
+ }
+}
+
+void
+fatal(const char *token, const char *emsg)
+{
+ if (emsg == NULL)
+ logit(LOG_CRIT, token ? token : "fatal", "%s", strerror(errno));
+ else if (errno)
+ logit(LOG_CRIT, token ? token : "fatal", "%s: %s", emsg,
+ strerror(errno));
+ else
+ logit(LOG_CRIT, token ? token : "fatal", "%s", emsg);
+
+ exit(1);
+}
+
+void
+fatalx(const char *token, const char *emsg)
+{
+ errno = 0;
+ fatal(token, emsg);
+}