1eda14cbcSMatt Macy /* 2180f8225SMatt Macy * This file is part of the ZFS Event Daemon (ZED). 3180f8225SMatt Macy * 4eda14cbcSMatt Macy * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). 5eda14cbcSMatt Macy * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. 6*16038816SMartin Matuska * Refer to the OpenZFS git commit log for authoritative copyright attribution. 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 9eda14cbcSMatt Macy * Common Development and Distribution License Version 1.0 (CDDL-1.0). 10eda14cbcSMatt Macy * You can obtain a copy of the license from the top-level file 11eda14cbcSMatt Macy * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>. 12eda14cbcSMatt Macy * You may not use this file except in compliance with the license. 13eda14cbcSMatt Macy */ 14eda14cbcSMatt Macy 15eda14cbcSMatt Macy #include <assert.h> 16eda14cbcSMatt Macy #include <errno.h> 17eda14cbcSMatt Macy #include <stdarg.h> 18eda14cbcSMatt Macy #include <stdio.h> 19eda14cbcSMatt Macy #include <stdlib.h> 20eda14cbcSMatt Macy #include <string.h> 21eda14cbcSMatt Macy #include <sys/types.h> 22eda14cbcSMatt Macy #include <syslog.h> 23eda14cbcSMatt Macy #include <unistd.h> 24eda14cbcSMatt Macy #include "zed_log.h" 25eda14cbcSMatt Macy 26eda14cbcSMatt Macy #define ZED_LOG_MAX_LOG_LEN 1024 27eda14cbcSMatt Macy 28eda14cbcSMatt Macy static struct { 29eda14cbcSMatt Macy unsigned do_stderr:1; 30eda14cbcSMatt Macy unsigned do_syslog:1; 31eda14cbcSMatt Macy const char *identity; 32eda14cbcSMatt Macy int priority; 33eda14cbcSMatt Macy int pipe_fd[2]; 34eda14cbcSMatt Macy } _ctx; 35eda14cbcSMatt Macy 36eda14cbcSMatt Macy /* 37eda14cbcSMatt Macy * Initialize the logging subsystem. 38eda14cbcSMatt Macy */ 39eda14cbcSMatt Macy void 40eda14cbcSMatt Macy zed_log_init(const char *identity) 41eda14cbcSMatt Macy { 42eda14cbcSMatt Macy if (identity) { 43eda14cbcSMatt Macy const char *p = strrchr(identity, '/'); 44eda14cbcSMatt Macy _ctx.identity = (p != NULL) ? p + 1 : identity; 45eda14cbcSMatt Macy } else { 46eda14cbcSMatt Macy _ctx.identity = NULL; 47eda14cbcSMatt Macy } 48eda14cbcSMatt Macy _ctx.pipe_fd[0] = -1; 49eda14cbcSMatt Macy _ctx.pipe_fd[1] = -1; 50eda14cbcSMatt Macy } 51eda14cbcSMatt Macy 52eda14cbcSMatt Macy /* 53eda14cbcSMatt Macy * Shutdown the logging subsystem. 54eda14cbcSMatt Macy */ 55eda14cbcSMatt Macy void 56eda14cbcSMatt Macy zed_log_fini(void) 57eda14cbcSMatt Macy { 58eda14cbcSMatt Macy zed_log_stderr_close(); 59eda14cbcSMatt Macy zed_log_syslog_close(); 60eda14cbcSMatt Macy } 61eda14cbcSMatt Macy 62eda14cbcSMatt Macy /* 63eda14cbcSMatt Macy * Create pipe for communicating daemonization status between the parent and 64eda14cbcSMatt Macy * child processes across the double-fork(). 65eda14cbcSMatt Macy */ 66eda14cbcSMatt Macy void 67eda14cbcSMatt Macy zed_log_pipe_open(void) 68eda14cbcSMatt Macy { 69eda14cbcSMatt Macy if ((_ctx.pipe_fd[0] != -1) || (_ctx.pipe_fd[1] != -1)) 70eda14cbcSMatt Macy zed_log_die("Invalid use of zed_log_pipe_open in PID %d", 71eda14cbcSMatt Macy (int)getpid()); 72eda14cbcSMatt Macy 73eda14cbcSMatt Macy if (pipe(_ctx.pipe_fd) < 0) 74eda14cbcSMatt Macy zed_log_die("Failed to create daemonize pipe in PID %d: %s", 75eda14cbcSMatt Macy (int)getpid(), strerror(errno)); 76eda14cbcSMatt Macy } 77eda14cbcSMatt Macy 78eda14cbcSMatt Macy /* 79eda14cbcSMatt Macy * Close the read-half of the daemonize pipe. 80eda14cbcSMatt Macy * 81eda14cbcSMatt Macy * This should be called by the child after fork()ing from the parent since 82eda14cbcSMatt Macy * the child will never read from this pipe. 83eda14cbcSMatt Macy */ 84eda14cbcSMatt Macy void 85eda14cbcSMatt Macy zed_log_pipe_close_reads(void) 86eda14cbcSMatt Macy { 87eda14cbcSMatt Macy if (_ctx.pipe_fd[0] < 0) 88eda14cbcSMatt Macy zed_log_die( 89eda14cbcSMatt Macy "Invalid use of zed_log_pipe_close_reads in PID %d", 90eda14cbcSMatt Macy (int)getpid()); 91eda14cbcSMatt Macy 92eda14cbcSMatt Macy if (close(_ctx.pipe_fd[0]) < 0) 93eda14cbcSMatt Macy zed_log_die( 94eda14cbcSMatt Macy "Failed to close reads on daemonize pipe in PID %d: %s", 95eda14cbcSMatt Macy (int)getpid(), strerror(errno)); 96eda14cbcSMatt Macy 97eda14cbcSMatt Macy _ctx.pipe_fd[0] = -1; 98eda14cbcSMatt Macy } 99eda14cbcSMatt Macy 100eda14cbcSMatt Macy /* 101eda14cbcSMatt Macy * Close the write-half of the daemonize pipe. 102eda14cbcSMatt Macy * 103eda14cbcSMatt Macy * This should be called by the parent after fork()ing its child since the 104eda14cbcSMatt Macy * parent will never write to this pipe. 105eda14cbcSMatt Macy * 106eda14cbcSMatt Macy * This should also be called by the child once initialization is complete 107eda14cbcSMatt Macy * in order to signal the parent that it can safely exit. 108eda14cbcSMatt Macy */ 109eda14cbcSMatt Macy void 110eda14cbcSMatt Macy zed_log_pipe_close_writes(void) 111eda14cbcSMatt Macy { 112eda14cbcSMatt Macy if (_ctx.pipe_fd[1] < 0) 113eda14cbcSMatt Macy zed_log_die( 114eda14cbcSMatt Macy "Invalid use of zed_log_pipe_close_writes in PID %d", 115eda14cbcSMatt Macy (int)getpid()); 116eda14cbcSMatt Macy 117eda14cbcSMatt Macy if (close(_ctx.pipe_fd[1]) < 0) 118eda14cbcSMatt Macy zed_log_die( 119eda14cbcSMatt Macy "Failed to close writes on daemonize pipe in PID %d: %s", 120eda14cbcSMatt Macy (int)getpid(), strerror(errno)); 121eda14cbcSMatt Macy 122eda14cbcSMatt Macy _ctx.pipe_fd[1] = -1; 123eda14cbcSMatt Macy } 124eda14cbcSMatt Macy 125eda14cbcSMatt Macy /* 126eda14cbcSMatt Macy * Block on reading from the daemonize pipe until signaled by the child 127eda14cbcSMatt Macy * (via zed_log_pipe_close_writes()) that initialization is complete. 128eda14cbcSMatt Macy * 129eda14cbcSMatt Macy * This should only be called by the parent while waiting to exit after 130eda14cbcSMatt Macy * fork()ing the child. 131eda14cbcSMatt Macy */ 132eda14cbcSMatt Macy void 133eda14cbcSMatt Macy zed_log_pipe_wait(void) 134eda14cbcSMatt Macy { 135eda14cbcSMatt Macy ssize_t n; 136eda14cbcSMatt Macy char c; 137eda14cbcSMatt Macy 138eda14cbcSMatt Macy if (_ctx.pipe_fd[0] < 0) 139eda14cbcSMatt Macy zed_log_die("Invalid use of zed_log_pipe_wait in PID %d", 140eda14cbcSMatt Macy (int)getpid()); 141eda14cbcSMatt Macy 142eda14cbcSMatt Macy for (;;) { 143eda14cbcSMatt Macy n = read(_ctx.pipe_fd[0], &c, sizeof (c)); 144eda14cbcSMatt Macy if (n < 0) { 145eda14cbcSMatt Macy if (errno == EINTR) 146eda14cbcSMatt Macy continue; 147eda14cbcSMatt Macy zed_log_die( 148eda14cbcSMatt Macy "Failed to read from daemonize pipe in PID %d: %s", 149eda14cbcSMatt Macy (int)getpid(), strerror(errno)); 150eda14cbcSMatt Macy } 151eda14cbcSMatt Macy if (n == 0) { 152eda14cbcSMatt Macy break; 153eda14cbcSMatt Macy } 154eda14cbcSMatt Macy } 155eda14cbcSMatt Macy } 156eda14cbcSMatt Macy 157eda14cbcSMatt Macy /* 158eda14cbcSMatt Macy * Start logging messages at the syslog [priority] level or higher to stderr. 159eda14cbcSMatt Macy * Refer to syslog(3) for valid priority values. 160eda14cbcSMatt Macy */ 161eda14cbcSMatt Macy void 162eda14cbcSMatt Macy zed_log_stderr_open(int priority) 163eda14cbcSMatt Macy { 164eda14cbcSMatt Macy _ctx.do_stderr = 1; 165eda14cbcSMatt Macy _ctx.priority = priority; 166eda14cbcSMatt Macy } 167eda14cbcSMatt Macy 168eda14cbcSMatt Macy /* 169eda14cbcSMatt Macy * Stop logging messages to stderr. 170eda14cbcSMatt Macy */ 171eda14cbcSMatt Macy void 172eda14cbcSMatt Macy zed_log_stderr_close(void) 173eda14cbcSMatt Macy { 174eda14cbcSMatt Macy if (_ctx.do_stderr) 175eda14cbcSMatt Macy _ctx.do_stderr = 0; 176eda14cbcSMatt Macy } 177eda14cbcSMatt Macy 178eda14cbcSMatt Macy /* 179eda14cbcSMatt Macy * Start logging messages to syslog. 180eda14cbcSMatt Macy * Refer to syslog(3) for valid option/facility values. 181eda14cbcSMatt Macy */ 182eda14cbcSMatt Macy void 183eda14cbcSMatt Macy zed_log_syslog_open(int facility) 184eda14cbcSMatt Macy { 185eda14cbcSMatt Macy _ctx.do_syslog = 1; 186eda14cbcSMatt Macy openlog(_ctx.identity, LOG_NDELAY | LOG_PID, facility); 187eda14cbcSMatt Macy } 188eda14cbcSMatt Macy 189eda14cbcSMatt Macy /* 190eda14cbcSMatt Macy * Stop logging messages to syslog. 191eda14cbcSMatt Macy */ 192eda14cbcSMatt Macy void 193eda14cbcSMatt Macy zed_log_syslog_close(void) 194eda14cbcSMatt Macy { 195eda14cbcSMatt Macy if (_ctx.do_syslog) { 196eda14cbcSMatt Macy _ctx.do_syslog = 0; 197eda14cbcSMatt Macy closelog(); 198eda14cbcSMatt Macy } 199eda14cbcSMatt Macy } 200eda14cbcSMatt Macy 201eda14cbcSMatt Macy /* 202eda14cbcSMatt Macy * Auxiliary function to log a message to syslog and/or stderr. 203eda14cbcSMatt Macy */ 204eda14cbcSMatt Macy static void 205eda14cbcSMatt Macy _zed_log_aux(int priority, const char *fmt, va_list vargs) 206eda14cbcSMatt Macy { 207eda14cbcSMatt Macy char buf[ZED_LOG_MAX_LOG_LEN]; 208eda14cbcSMatt Macy int n; 209eda14cbcSMatt Macy 210eda14cbcSMatt Macy if (!fmt) 211eda14cbcSMatt Macy return; 212eda14cbcSMatt Macy 213eda14cbcSMatt Macy n = vsnprintf(buf, sizeof (buf), fmt, vargs); 214eda14cbcSMatt Macy if ((n < 0) || (n >= sizeof (buf))) { 215eda14cbcSMatt Macy buf[sizeof (buf) - 2] = '+'; 216eda14cbcSMatt Macy buf[sizeof (buf) - 1] = '\0'; 217eda14cbcSMatt Macy } 218eda14cbcSMatt Macy 219eda14cbcSMatt Macy if (_ctx.do_syslog) 220eda14cbcSMatt Macy syslog(priority, "%s", buf); 221eda14cbcSMatt Macy 222eda14cbcSMatt Macy if (_ctx.do_stderr && (priority <= _ctx.priority)) 223eda14cbcSMatt Macy fprintf(stderr, "%s\n", buf); 224eda14cbcSMatt Macy } 225eda14cbcSMatt Macy 226eda14cbcSMatt Macy /* 227eda14cbcSMatt Macy * Log a message at the given [priority] level specified by the printf-style 228eda14cbcSMatt Macy * format string [fmt]. 229eda14cbcSMatt Macy */ 230eda14cbcSMatt Macy void 231eda14cbcSMatt Macy zed_log_msg(int priority, const char *fmt, ...) 232eda14cbcSMatt Macy { 233eda14cbcSMatt Macy va_list vargs; 234eda14cbcSMatt Macy 235eda14cbcSMatt Macy if (fmt) { 236eda14cbcSMatt Macy va_start(vargs, fmt); 237eda14cbcSMatt Macy _zed_log_aux(priority, fmt, vargs); 238eda14cbcSMatt Macy va_end(vargs); 239eda14cbcSMatt Macy } 240eda14cbcSMatt Macy } 241eda14cbcSMatt Macy 242eda14cbcSMatt Macy /* 243eda14cbcSMatt Macy * Log a fatal error message specified by the printf-style format string [fmt]. 244eda14cbcSMatt Macy */ 245eda14cbcSMatt Macy void 246eda14cbcSMatt Macy zed_log_die(const char *fmt, ...) 247eda14cbcSMatt Macy { 248eda14cbcSMatt Macy va_list vargs; 249eda14cbcSMatt Macy 250eda14cbcSMatt Macy if (fmt) { 251eda14cbcSMatt Macy va_start(vargs, fmt); 252eda14cbcSMatt Macy _zed_log_aux(LOG_ERR, fmt, vargs); 253eda14cbcSMatt Macy va_end(vargs); 254eda14cbcSMatt Macy } 255eda14cbcSMatt Macy exit(EXIT_FAILURE); 256eda14cbcSMatt Macy } 257