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