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
zed_log_init(const char * identity)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
zed_log_fini(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
zed_log_pipe_open(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
zed_log_pipe_close_reads(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
zed_log_pipe_close_writes(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
zed_log_pipe_wait(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
zed_log_stderr_open(int priority)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
zed_log_stderr_close(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
zed_log_syslog_open(int facility)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
zed_log_syslog_close(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
_zed_log_aux(int priority,const char * fmt,va_list vargs)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
zed_log_msg(int priority,const char * fmt,...)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
zed_log_die(const char * fmt,...)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