diff options
Diffstat (limited to 'cmd/zed/zed_log.c')
-rw-r--r-- | cmd/zed/zed_log.c | 256 |
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); +} |