aboutsummaryrefslogtreecommitdiff
path: root/cmd/zed/zed_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/zed/zed_log.c')
-rw-r--r--cmd/zed/zed_log.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/cmd/zed/zed_log.c b/cmd/zed/zed_log.c
new file mode 100644
index 000000000000..5a3f2dbdb832
--- /dev/null
+++ b/cmd/zed/zed_log.c
@@ -0,0 +1,256 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "zed_log.h"
+
+#define ZED_LOG_MAX_LOG_LEN 1024
+
+static struct {
+ unsigned do_stderr:1;
+ unsigned do_syslog:1;
+ const char *identity;
+ int priority;
+ int pipe_fd[2];
+} _ctx;
+
+/*
+ * Initialize the logging subsystem.
+ */
+void
+zed_log_init(const char *identity)
+{
+ if (identity) {
+ const char *p = strrchr(identity, '/');
+ _ctx.identity = (p != NULL) ? p + 1 : identity;
+ } else {
+ _ctx.identity = NULL;
+ }
+ _ctx.pipe_fd[0] = -1;
+ _ctx.pipe_fd[1] = -1;
+}
+
+/*
+ * Shutdown the logging subsystem.
+ */
+void
+zed_log_fini(void)
+{
+ zed_log_stderr_close();
+ zed_log_syslog_close();
+}
+
+/*
+ * Create pipe for communicating daemonization status between the parent and
+ * child processes across the double-fork().
+ */
+void
+zed_log_pipe_open(void)
+{
+ if ((_ctx.pipe_fd[0] != -1) || (_ctx.pipe_fd[1] != -1))
+ zed_log_die("Invalid use of zed_log_pipe_open in PID %d",
+ (int)getpid());
+
+ if (pipe(_ctx.pipe_fd) < 0)
+ zed_log_die("Failed to create daemonize pipe in PID %d: %s",
+ (int)getpid(), strerror(errno));
+}
+
+/*
+ * Close the read-half of the daemonize pipe.
+ *
+ * This should be called by the child after fork()ing from the parent since
+ * the child will never read from this pipe.
+ */
+void
+zed_log_pipe_close_reads(void)
+{
+ if (_ctx.pipe_fd[0] < 0)
+ zed_log_die(
+ "Invalid use of zed_log_pipe_close_reads in PID %d",
+ (int)getpid());
+
+ if (close(_ctx.pipe_fd[0]) < 0)
+ zed_log_die(
+ "Failed to close reads on daemonize pipe in PID %d: %s",
+ (int)getpid(), strerror(errno));
+
+ _ctx.pipe_fd[0] = -1;
+}
+
+/*
+ * Close the write-half of the daemonize pipe.
+ *
+ * This should be called by the parent after fork()ing its child since the
+ * parent will never write to this pipe.
+ *
+ * This should also be called by the child once initialization is complete
+ * in order to signal the parent that it can safely exit.
+ */
+void
+zed_log_pipe_close_writes(void)
+{
+ if (_ctx.pipe_fd[1] < 0)
+ zed_log_die(
+ "Invalid use of zed_log_pipe_close_writes in PID %d",
+ (int)getpid());
+
+ if (close(_ctx.pipe_fd[1]) < 0)
+ zed_log_die(
+ "Failed to close writes on daemonize pipe in PID %d: %s",
+ (int)getpid(), strerror(errno));
+
+ _ctx.pipe_fd[1] = -1;
+}
+
+/*
+ * Block on reading from the daemonize pipe until signaled by the child
+ * (via zed_log_pipe_close_writes()) that initialization is complete.
+ *
+ * This should only be called by the parent while waiting to exit after
+ * fork()ing the child.
+ */
+void
+zed_log_pipe_wait(void)
+{
+ ssize_t n;
+ char c;
+
+ if (_ctx.pipe_fd[0] < 0)
+ zed_log_die("Invalid use of zed_log_pipe_wait in PID %d",
+ (int)getpid());
+
+ for (;;) {
+ n = read(_ctx.pipe_fd[0], &c, sizeof (c));
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ zed_log_die(
+ "Failed to read from daemonize pipe in PID %d: %s",
+ (int)getpid(), strerror(errno));
+ }
+ if (n == 0) {
+ break;
+ }
+ }
+}
+
+/*
+ * Start logging messages at the syslog [priority] level or higher to stderr.
+ * Refer to syslog(3) for valid priority values.
+ */
+void
+zed_log_stderr_open(int priority)
+{
+ _ctx.do_stderr = 1;
+ _ctx.priority = priority;
+}
+
+/*
+ * Stop logging messages to stderr.
+ */
+void
+zed_log_stderr_close(void)
+{
+ if (_ctx.do_stderr)
+ _ctx.do_stderr = 0;
+}
+
+/*
+ * Start logging messages to syslog.
+ * Refer to syslog(3) for valid option/facility values.
+ */
+void
+zed_log_syslog_open(int facility)
+{
+ _ctx.do_syslog = 1;
+ openlog(_ctx.identity, LOG_NDELAY | LOG_PID, facility);
+}
+
+/*
+ * Stop logging messages to syslog.
+ */
+void
+zed_log_syslog_close(void)
+{
+ if (_ctx.do_syslog) {
+ _ctx.do_syslog = 0;
+ closelog();
+ }
+}
+
+/*
+ * Auxiliary function to log a message to syslog and/or stderr.
+ */
+static void
+_zed_log_aux(int priority, const char *fmt, va_list vargs)
+{
+ char buf[ZED_LOG_MAX_LOG_LEN];
+ int n;
+
+ if (!fmt)
+ return;
+
+ n = vsnprintf(buf, sizeof (buf), fmt, vargs);
+ if ((n < 0) || (n >= sizeof (buf))) {
+ buf[sizeof (buf) - 2] = '+';
+ buf[sizeof (buf) - 1] = '\0';
+ }
+
+ if (_ctx.do_syslog)
+ syslog(priority, "%s", buf);
+
+ if (_ctx.do_stderr && (priority <= _ctx.priority))
+ fprintf(stderr, "%s\n", buf);
+}
+
+/*
+ * Log a message at the given [priority] level specified by the printf-style
+ * format string [fmt].
+ */
+void
+zed_log_msg(int priority, const char *fmt, ...)
+{
+ va_list vargs;
+
+ if (fmt) {
+ va_start(vargs, fmt);
+ _zed_log_aux(priority, fmt, vargs);
+ va_end(vargs);
+ }
+}
+
+/*
+ * Log a fatal error message specified by the printf-style format string [fmt].
+ */
+void
+zed_log_die(const char *fmt, ...)
+{
+ va_list vargs;
+
+ if (fmt) {
+ va_start(vargs, fmt);
+ _zed_log_aux(LOG_ERR, fmt, vargs);
+ va_end(vargs);
+ }
+ exit(EXIT_FAILURE);
+}