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