]>
Commit | Line | Data |
---|---|---|
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 | ||
28 | static 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 |
39 | void |
40 | zed_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 | 55 | void |
8125fb71 | 56 | zed_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 | */ |
66 | void | |
67 | zed_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 | */ |
84 | void | |
85 | zed_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 | */ |
109 | void | |
110 | zed_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 | */ |
132 | void | |
133 | zed_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 | 161 | void |
8125fb71 | 162 | zed_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 |
171 | void |
172 | zed_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 |
182 | void |
183 | zed_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 |
192 | void |
193 | zed_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 |
204 | static 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 | */ |
230 | void | |
231 | zed_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 | */ | |
245 | void | |
246 | zed_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 | } |