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