xref: /freebsd/sys/contrib/openzfs/cmd/zed/zed_event.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 /*
13  * This file is part of the ZFS Event Daemon (ZED).
14  *
15  * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
16  * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
17  */
18 
19 #include <ctype.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <libzfs_core.h>
23 #include <paths.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/zfs_ioctl.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <sys/fm/fs/zfs.h>
32 #include "zed.h"
33 #include "zed_conf.h"
34 #include "zed_disk_event.h"
35 #include "zed_event.h"
36 #include "zed_exec.h"
37 #include "zed_file.h"
38 #include "zed_log.h"
39 #include "zed_strings.h"
40 
41 #include "agents/zfs_agents.h"
42 #include <libzutil.h>
43 
44 #define	MAXBUF	4096
45 
46 static int max_zevent_buf_len = 1 << 20;
47 
48 /*
49  * Open the libzfs interface.
50  */
51 int
zed_event_init(struct zed_conf * zcp)52 zed_event_init(struct zed_conf *zcp)
53 {
54 	if (!zcp)
55 		zed_log_die("Failed zed_event_init: %s", strerror(EINVAL));
56 
57 	zcp->zfs_hdl = libzfs_init();
58 	if (!zcp->zfs_hdl) {
59 		if (zcp->do_idle)
60 			return (-1);
61 		zed_log_die("Failed to initialize libzfs");
62 	}
63 
64 	zcp->zevent_fd = open(ZFS_DEV, O_RDWR | O_CLOEXEC);
65 	if (zcp->zevent_fd < 0) {
66 		if (zcp->do_idle)
67 			return (-1);
68 		zed_log_die("Failed to open \"%s\": %s",
69 		    ZFS_DEV, strerror(errno));
70 	}
71 
72 	zfs_agent_init(zcp->zfs_hdl);
73 
74 	if (zed_disk_event_init() != 0) {
75 		if (zcp->do_idle)
76 			return (-1);
77 		zed_log_die("Failed to initialize disk events");
78 	}
79 
80 	if (zcp->max_zevent_buf_len != 0)
81 		max_zevent_buf_len = zcp->max_zevent_buf_len;
82 
83 	return (0);
84 }
85 
86 /*
87  * Close the libzfs interface.
88  */
89 void
zed_event_fini(struct zed_conf * zcp)90 zed_event_fini(struct zed_conf *zcp)
91 {
92 	if (!zcp)
93 		zed_log_die("Failed zed_event_fini: %s", strerror(EINVAL));
94 
95 	zed_disk_event_fini();
96 	zfs_agent_fini();
97 
98 	if (zcp->zevent_fd >= 0) {
99 		if (close(zcp->zevent_fd) < 0)
100 			zed_log_msg(LOG_WARNING, "Failed to close \"%s\": %s",
101 			    ZFS_DEV, strerror(errno));
102 
103 		zcp->zevent_fd = -1;
104 	}
105 	if (zcp->zfs_hdl) {
106 		libzfs_fini(zcp->zfs_hdl);
107 		zcp->zfs_hdl = NULL;
108 	}
109 
110 	zed_exec_fini();
111 }
112 
113 static void
_bump_event_queue_length(void)114 _bump_event_queue_length(void)
115 {
116 	int zzlm, wr;
117 	char qlen_buf[12] = {0}; /* parameter is int => max "-2147483647\n" */
118 	long int qlen, orig_qlen;
119 
120 	zzlm = open("/sys/module/zfs/parameters/zfs_zevent_len_max", O_RDWR);
121 	if (zzlm < 0)
122 		goto done;
123 
124 	if (read(zzlm, qlen_buf, sizeof (qlen_buf)) < 0)
125 		goto done;
126 	qlen_buf[sizeof (qlen_buf) - 1] = '\0';
127 
128 	errno = 0;
129 	orig_qlen = qlen = strtol(qlen_buf, NULL, 10);
130 	if (errno == ERANGE)
131 		goto done;
132 
133 	if (qlen <= 0)
134 		qlen = 512; /* default zfs_zevent_len_max value */
135 	else
136 		qlen *= 2;
137 
138 	/*
139 	 * Don't consume all of kernel memory with event logs if something
140 	 * goes wrong.
141 	 */
142 	if (qlen > max_zevent_buf_len)
143 		qlen = max_zevent_buf_len;
144 	if (qlen == orig_qlen)
145 		goto done;
146 	wr = snprintf(qlen_buf, sizeof (qlen_buf), "%ld", qlen);
147 	if (wr >= sizeof (qlen_buf)) {
148 		wr = sizeof (qlen_buf) - 1;
149 		zed_log_msg(LOG_WARNING, "Truncation in %s()", __func__);
150 	}
151 
152 	if (pwrite(zzlm, qlen_buf, wr + 1, 0) < 0)
153 		goto done;
154 
155 	zed_log_msg(LOG_WARNING, "Bumping queue length to %ld", qlen);
156 
157 done:
158 	if (zzlm > -1)
159 		(void) close(zzlm);
160 }
161 
162 /*
163  * Seek to the event specified by [saved_eid] and [saved_etime].
164  * This protects against processing a given event more than once.
165  * Return 0 upon a successful seek to the specified event, or -1 otherwise.
166  *
167  * A zevent is considered to be uniquely specified by its (eid,time) tuple.
168  * The unsigned 64b eid is set to 1 when the kernel module is loaded, and
169  * incremented by 1 for each new event.  Since the state file can persist
170  * across a kernel module reload, the time must be checked to ensure a match.
171  */
172 int
zed_event_seek(struct zed_conf * zcp,uint64_t saved_eid,int64_t saved_etime[])173 zed_event_seek(struct zed_conf *zcp, uint64_t saved_eid, int64_t saved_etime[])
174 {
175 	uint64_t eid;
176 	int found;
177 	nvlist_t *nvl;
178 	int n_dropped;
179 	int64_t *etime;
180 	uint_t nelem;
181 	int rv;
182 
183 	if (!zcp) {
184 		errno = EINVAL;
185 		zed_log_msg(LOG_ERR, "Failed to seek zevent: %s",
186 		    strerror(errno));
187 		return (-1);
188 	}
189 	eid = 0;
190 	found = 0;
191 	while ((eid < saved_eid) && !found) {
192 		rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped,
193 		    ZEVENT_NONBLOCK, zcp->zevent_fd);
194 
195 		if ((rv != 0) || !nvl)
196 			break;
197 
198 		if (n_dropped > 0) {
199 			zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
200 			_bump_event_queue_length();
201 		}
202 		if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
203 			zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
204 		} else if (nvlist_lookup_int64_array(nvl, "time",
205 		    &etime, &nelem) != 0) {
206 			zed_log_msg(LOG_WARNING,
207 			    "Failed to lookup zevent time (eid=%llu)", eid);
208 		} else if (nelem != 2) {
209 			zed_log_msg(LOG_WARNING,
210 			    "Failed to lookup zevent time (eid=%llu, nelem=%u)",
211 			    eid, nelem);
212 		} else if ((eid != saved_eid) ||
213 		    (etime[0] != saved_etime[0]) ||
214 		    (etime[1] != saved_etime[1])) {
215 			/* no-op */
216 		} else {
217 			found = 1;
218 		}
219 		free(nvl);
220 	}
221 	if (!found && (saved_eid > 0)) {
222 		if (zpool_events_seek(zcp->zfs_hdl, ZEVENT_SEEK_START,
223 		    zcp->zevent_fd) < 0)
224 			zed_log_msg(LOG_WARNING, "Failed to seek to eid=0");
225 		else
226 			eid = 0;
227 	}
228 	zed_log_msg(LOG_NOTICE, "Processing events since eid=%llu", eid);
229 	return (found ? 0 : -1);
230 }
231 
232 /*
233  * Return non-zero if nvpair [name] should be formatted in hex; o/w, return 0.
234  */
235 static int
_zed_event_value_is_hex(const char * name)236 _zed_event_value_is_hex(const char *name)
237 {
238 	const char *hex_suffix[] = {
239 		"_guid",
240 		"_guids",
241 		NULL
242 	};
243 	const char **pp;
244 	const char *p;
245 
246 	if (!name)
247 		return (0);
248 
249 	for (pp = hex_suffix; *pp; pp++) {
250 		p = strstr(name, *pp);
251 		if (p && strlen(p) == strlen(*pp))
252 			return (1);
253 	}
254 	return (0);
255 }
256 
257 /*
258  * Add an environment variable for [eid] to the container [zsp].
259  *
260  * The variable name is the concatenation of [prefix] and [name] converted to
261  * uppercase with non-alphanumeric characters converted to underscores;
262  * [prefix] is optional, and [name] must begin with an alphabetic character.
263  * If the converted variable name already exists within the container [zsp],
264  * its existing value will be replaced with the new value.
265  *
266  * The variable value is specified by the format string [fmt].
267  *
268  * Returns 0 on success, and -1 on error (with errno set).
269  *
270  * All environment variables in [zsp] should be added through this function.
271  */
272 static __attribute__((format(printf, 5, 6))) int
_zed_event_add_var(uint64_t eid,zed_strings_t * zsp,const char * prefix,const char * name,const char * fmt,...)273 _zed_event_add_var(uint64_t eid, zed_strings_t *zsp,
274     const char *prefix, const char *name, const char *fmt, ...)
275 {
276 	char keybuf[MAXBUF];
277 	char valbuf[MAXBUF];
278 	char *dstp;
279 	const char *srcp;
280 	const char *lastp;
281 	int n;
282 	int buflen;
283 	va_list vargs;
284 
285 	assert(zsp != NULL);
286 	assert(fmt != NULL);
287 
288 	if (!name) {
289 		errno = EINVAL;
290 		zed_log_msg(LOG_WARNING,
291 		    "Failed to add variable for eid=%llu: Name is empty", eid);
292 		return (-1);
293 	} else if (!isalpha(name[0])) {
294 		errno = EINVAL;
295 		zed_log_msg(LOG_WARNING,
296 		    "Failed to add variable for eid=%llu: "
297 		    "Name \"%s\" is invalid", eid, name);
298 		return (-1);
299 	}
300 	/*
301 	 * Construct the string key by converting PREFIX (if present) and NAME.
302 	 */
303 	dstp = keybuf;
304 	lastp = keybuf + sizeof (keybuf);
305 	if (prefix) {
306 		for (srcp = prefix; *srcp && (dstp < lastp); srcp++)
307 			*dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_';
308 	}
309 	for (srcp = name; *srcp && (dstp < lastp); srcp++)
310 		*dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_';
311 
312 	if (dstp == lastp) {
313 		errno = ENAMETOOLONG;
314 		zed_log_msg(LOG_WARNING,
315 		    "Failed to add variable for eid=%llu: Name too long", eid);
316 		return (-1);
317 	}
318 	*dstp = '\0';
319 	/*
320 	 * Construct the string specified by "[PREFIX][NAME]=[FMT]".
321 	 */
322 	dstp = valbuf;
323 	buflen = sizeof (valbuf);
324 	n = strlcpy(dstp, keybuf, buflen);
325 	if (n >= sizeof (valbuf)) {
326 		errno = EMSGSIZE;
327 		zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
328 		    keybuf, eid, "Exceeded buffer size");
329 		return (-1);
330 	}
331 	dstp += n;
332 	buflen -= n;
333 
334 	*dstp++ = '=';
335 	buflen--;
336 
337 	if (buflen <= 0) {
338 		errno = EMSGSIZE;
339 		zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
340 		    keybuf, eid, "Exceeded buffer size");
341 		return (-1);
342 	}
343 
344 	va_start(vargs, fmt);
345 	n = vsnprintf(dstp, buflen, fmt, vargs);
346 	va_end(vargs);
347 
348 	if ((n < 0) || (n >= buflen)) {
349 		errno = EMSGSIZE;
350 		zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
351 		    keybuf, eid, "Exceeded buffer size");
352 		return (-1);
353 	} else if (zed_strings_add(zsp, keybuf, valbuf) < 0) {
354 		zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
355 		    keybuf, eid, strerror(errno));
356 		return (-1);
357 	}
358 	return (0);
359 }
360 
361 static int
_zed_event_add_array_err(uint64_t eid,const char * name)362 _zed_event_add_array_err(uint64_t eid, const char *name)
363 {
364 	errno = EMSGSIZE;
365 	zed_log_msg(LOG_WARNING,
366 	    "Failed to convert nvpair \"%s\" for eid=%llu: "
367 	    "Exceeded buffer size", name, eid);
368 	return (-1);
369 }
370 
371 static int
_zed_event_add_int8_array(uint64_t eid,zed_strings_t * zsp,const char * prefix,nvpair_t * nvp)372 _zed_event_add_int8_array(uint64_t eid, zed_strings_t *zsp,
373     const char *prefix, nvpair_t *nvp)
374 {
375 	char buf[MAXBUF];
376 	int buflen = sizeof (buf);
377 	const char *name;
378 	int8_t *i8p;
379 	uint_t nelem;
380 	uint_t i;
381 	char *p;
382 	int n;
383 
384 	assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT8_ARRAY));
385 
386 	name = nvpair_name(nvp);
387 	(void) nvpair_value_int8_array(nvp, &i8p, &nelem);
388 	for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
389 		n = snprintf(p, buflen, "%d ", i8p[i]);
390 		if ((n < 0) || (n >= buflen))
391 			return (_zed_event_add_array_err(eid, name));
392 		p += n;
393 		buflen -= n;
394 	}
395 	if (nelem > 0)
396 		*--p = '\0';
397 
398 	return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
399 }
400 
401 static int
_zed_event_add_uint8_array(uint64_t eid,zed_strings_t * zsp,const char * prefix,nvpair_t * nvp)402 _zed_event_add_uint8_array(uint64_t eid, zed_strings_t *zsp,
403     const char *prefix, nvpair_t *nvp)
404 {
405 	char buf[MAXBUF];
406 	int buflen = sizeof (buf);
407 	const char *name;
408 	uint8_t *u8p;
409 	uint_t nelem;
410 	uint_t i;
411 	char *p;
412 	int n;
413 
414 	assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT8_ARRAY));
415 
416 	name = nvpair_name(nvp);
417 	(void) nvpair_value_uint8_array(nvp, &u8p, &nelem);
418 	for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
419 		n = snprintf(p, buflen, "%u ", u8p[i]);
420 		if ((n < 0) || (n >= buflen))
421 			return (_zed_event_add_array_err(eid, name));
422 		p += n;
423 		buflen -= n;
424 	}
425 	if (nelem > 0)
426 		*--p = '\0';
427 
428 	return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
429 }
430 
431 static int
_zed_event_add_int16_array(uint64_t eid,zed_strings_t * zsp,const char * prefix,nvpair_t * nvp)432 _zed_event_add_int16_array(uint64_t eid, zed_strings_t *zsp,
433     const char *prefix, nvpair_t *nvp)
434 {
435 	char buf[MAXBUF];
436 	int buflen = sizeof (buf);
437 	const char *name;
438 	int16_t *i16p;
439 	uint_t nelem;
440 	uint_t i;
441 	char *p;
442 	int n;
443 
444 	assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT16_ARRAY));
445 
446 	name = nvpair_name(nvp);
447 	(void) nvpair_value_int16_array(nvp, &i16p, &nelem);
448 	for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
449 		n = snprintf(p, buflen, "%d ", i16p[i]);
450 		if ((n < 0) || (n >= buflen))
451 			return (_zed_event_add_array_err(eid, name));
452 		p += n;
453 		buflen -= n;
454 	}
455 	if (nelem > 0)
456 		*--p = '\0';
457 
458 	return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
459 }
460 
461 static int
_zed_event_add_uint16_array(uint64_t eid,zed_strings_t * zsp,const char * prefix,nvpair_t * nvp)462 _zed_event_add_uint16_array(uint64_t eid, zed_strings_t *zsp,
463     const char *prefix, nvpair_t *nvp)
464 {
465 	char buf[MAXBUF];
466 	int buflen = sizeof (buf);
467 	const char *name;
468 	uint16_t *u16p;
469 	uint_t nelem;
470 	uint_t i;
471 	char *p;
472 	int n;
473 
474 	assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT16_ARRAY));
475 
476 	name = nvpair_name(nvp);
477 	(void) nvpair_value_uint16_array(nvp, &u16p, &nelem);
478 	for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
479 		n = snprintf(p, buflen, "%u ", u16p[i]);
480 		if ((n < 0) || (n >= buflen))
481 			return (_zed_event_add_array_err(eid, name));
482 		p += n;
483 		buflen -= n;
484 	}
485 	if (nelem > 0)
486 		*--p = '\0';
487 
488 	return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
489 }
490 
491 static int
_zed_event_add_int32_array(uint64_t eid,zed_strings_t * zsp,const char * prefix,nvpair_t * nvp)492 _zed_event_add_int32_array(uint64_t eid, zed_strings_t *zsp,
493     const char *prefix, nvpair_t *nvp)
494 {
495 	char buf[MAXBUF];
496 	int buflen = sizeof (buf);
497 	const char *name;
498 	int32_t *i32p;
499 	uint_t nelem;
500 	uint_t i;
501 	char *p;
502 	int n;
503 
504 	assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT32_ARRAY));
505 
506 	name = nvpair_name(nvp);
507 	(void) nvpair_value_int32_array(nvp, &i32p, &nelem);
508 	for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
509 		n = snprintf(p, buflen, "%d ", i32p[i]);
510 		if ((n < 0) || (n >= buflen))
511 			return (_zed_event_add_array_err(eid, name));
512 		p += n;
513 		buflen -= n;
514 	}
515 	if (nelem > 0)
516 		*--p = '\0';
517 
518 	return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
519 }
520 
521 static int
_zed_event_add_uint32_array(uint64_t eid,zed_strings_t * zsp,const char * prefix,nvpair_t * nvp)522 _zed_event_add_uint32_array(uint64_t eid, zed_strings_t *zsp,
523     const char *prefix, nvpair_t *nvp)
524 {
525 	char buf[MAXBUF];
526 	int buflen = sizeof (buf);
527 	const char *name;
528 	uint32_t *u32p;
529 	uint_t nelem;
530 	uint_t i;
531 	char *p;
532 	int n;
533 
534 	assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT32_ARRAY));
535 
536 	name = nvpair_name(nvp);
537 	(void) nvpair_value_uint32_array(nvp, &u32p, &nelem);
538 	for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
539 		n = snprintf(p, buflen, "%u ", u32p[i]);
540 		if ((n < 0) || (n >= buflen))
541 			return (_zed_event_add_array_err(eid, name));
542 		p += n;
543 		buflen -= n;
544 	}
545 	if (nelem > 0)
546 		*--p = '\0';
547 
548 	return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
549 }
550 
551 static int
_zed_event_add_int64_array(uint64_t eid,zed_strings_t * zsp,const char * prefix,nvpair_t * nvp)552 _zed_event_add_int64_array(uint64_t eid, zed_strings_t *zsp,
553     const char *prefix, nvpair_t *nvp)
554 {
555 	char buf[MAXBUF];
556 	int buflen = sizeof (buf);
557 	const char *name;
558 	int64_t *i64p;
559 	uint_t nelem;
560 	uint_t i;
561 	char *p;
562 	int n;
563 
564 	assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT64_ARRAY));
565 
566 	name = nvpair_name(nvp);
567 	(void) nvpair_value_int64_array(nvp, &i64p, &nelem);
568 	for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
569 		n = snprintf(p, buflen, "%lld ", (u_longlong_t)i64p[i]);
570 		if ((n < 0) || (n >= buflen))
571 			return (_zed_event_add_array_err(eid, name));
572 		p += n;
573 		buflen -= n;
574 	}
575 	if (nelem > 0)
576 		*--p = '\0';
577 
578 	return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
579 }
580 
581 static int
_zed_event_add_uint64_array(uint64_t eid,zed_strings_t * zsp,const char * prefix,nvpair_t * nvp)582 _zed_event_add_uint64_array(uint64_t eid, zed_strings_t *zsp,
583     const char *prefix, nvpair_t *nvp)
584 {
585 	char buf[MAXBUF];
586 	int buflen = sizeof (buf);
587 	const char *name;
588 	const char *fmt;
589 	uint64_t *u64p;
590 	uint_t nelem;
591 	uint_t i;
592 	char *p;
593 	int n;
594 
595 	assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY));
596 
597 	name = nvpair_name(nvp);
598 	fmt = _zed_event_value_is_hex(name) ? "0x%.16llX " : "%llu ";
599 	(void) nvpair_value_uint64_array(nvp, &u64p, &nelem);
600 	for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
601 		n = snprintf(p, buflen, fmt, (u_longlong_t)u64p[i]);
602 		if ((n < 0) || (n >= buflen))
603 			return (_zed_event_add_array_err(eid, name));
604 		p += n;
605 		buflen -= n;
606 	}
607 	if (nelem > 0)
608 		*--p = '\0';
609 
610 	return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
611 }
612 
613 static int
_zed_event_add_string_array(uint64_t eid,zed_strings_t * zsp,const char * prefix,nvpair_t * nvp)614 _zed_event_add_string_array(uint64_t eid, zed_strings_t *zsp,
615     const char *prefix, nvpair_t *nvp)
616 {
617 	char buf[MAXBUF];
618 	int buflen = sizeof (buf);
619 	const char *name;
620 	const char **strp;
621 	uint_t nelem;
622 	uint_t i;
623 	char *p;
624 	int n;
625 
626 	assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY));
627 
628 	name = nvpair_name(nvp);
629 	(void) nvpair_value_string_array(nvp, &strp, &nelem);
630 	for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
631 		n = snprintf(p, buflen, "%s ", strp[i] ? strp[i] : "<NULL>");
632 		if ((n < 0) || (n >= buflen))
633 			return (_zed_event_add_array_err(eid, name));
634 		p += n;
635 		buflen -= n;
636 	}
637 	if (nelem > 0)
638 		*--p = '\0';
639 
640 	return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
641 }
642 
643 /*
644  * Convert the nvpair [nvp] to a string which is added to the environment
645  * of the child process.
646  * Return 0 on success, -1 on error.
647  */
648 static void
_zed_event_add_nvpair(uint64_t eid,zed_strings_t * zsp,nvpair_t * nvp)649 _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
650 {
651 	const char *name;
652 	data_type_t type;
653 	const char *prefix = ZEVENT_VAR_PREFIX;
654 	boolean_t b;
655 	double d;
656 	uint8_t i8;
657 	uint16_t i16;
658 	uint32_t i32;
659 	uint64_t i64;
660 	const char *str;
661 
662 	assert(zsp != NULL);
663 	assert(nvp != NULL);
664 
665 	name = nvpair_name(nvp);
666 	type = nvpair_type(nvp);
667 
668 	switch (type) {
669 	case DATA_TYPE_BOOLEAN:
670 		_zed_event_add_var(eid, zsp, prefix, name, "%s", "1");
671 		break;
672 	case DATA_TYPE_BOOLEAN_VALUE:
673 		(void) nvpair_value_boolean_value(nvp, &b);
674 		_zed_event_add_var(eid, zsp, prefix, name, "%s", b ? "1" : "0");
675 		break;
676 	case DATA_TYPE_BYTE:
677 		(void) nvpair_value_byte(nvp, &i8);
678 		_zed_event_add_var(eid, zsp, prefix, name, "%d", i8);
679 		break;
680 	case DATA_TYPE_INT8:
681 		(void) nvpair_value_int8(nvp, (int8_t *)&i8);
682 		_zed_event_add_var(eid, zsp, prefix, name, "%d", i8);
683 		break;
684 	case DATA_TYPE_UINT8:
685 		(void) nvpair_value_uint8(nvp, &i8);
686 		_zed_event_add_var(eid, zsp, prefix, name, "%u", i8);
687 		break;
688 	case DATA_TYPE_INT16:
689 		(void) nvpair_value_int16(nvp, (int16_t *)&i16);
690 		_zed_event_add_var(eid, zsp, prefix, name, "%d", i16);
691 		break;
692 	case DATA_TYPE_UINT16:
693 		(void) nvpair_value_uint16(nvp, &i16);
694 		_zed_event_add_var(eid, zsp, prefix, name, "%u", i16);
695 		break;
696 	case DATA_TYPE_INT32:
697 		(void) nvpair_value_int32(nvp, (int32_t *)&i32);
698 		_zed_event_add_var(eid, zsp, prefix, name, "%d", i32);
699 		break;
700 	case DATA_TYPE_UINT32:
701 		(void) nvpair_value_uint32(nvp, &i32);
702 		_zed_event_add_var(eid, zsp, prefix, name, "%u", i32);
703 		break;
704 	case DATA_TYPE_INT64:
705 		(void) nvpair_value_int64(nvp, (int64_t *)&i64);
706 		_zed_event_add_var(eid, zsp, prefix, name,
707 		    "%lld", (longlong_t)i64);
708 		break;
709 	case DATA_TYPE_UINT64:
710 		(void) nvpair_value_uint64(nvp, &i64);
711 		_zed_event_add_var(eid, zsp, prefix, name,
712 		    (_zed_event_value_is_hex(name) ? "0x%.16llX" : "%llu"),
713 		    (u_longlong_t)i64);
714 		/*
715 		 * shadow readable strings for vdev state pairs
716 		 */
717 		if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE) == 0 ||
718 		    strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE) == 0) {
719 			char alt[32];
720 
721 			(void) snprintf(alt, sizeof (alt), "%s_str", name);
722 			_zed_event_add_var(eid, zsp, prefix, alt, "%s",
723 			    zpool_state_to_name(i64, VDEV_AUX_NONE));
724 		} else
725 		/*
726 		 * shadow readable strings for pool state
727 		 */
728 		if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_POOL_STATE) == 0) {
729 			char alt[32];
730 
731 			(void) snprintf(alt, sizeof (alt), "%s_str", name);
732 			_zed_event_add_var(eid, zsp, prefix, alt, "%s",
733 			    zpool_pool_state_to_name(i64));
734 		}
735 		break;
736 	case DATA_TYPE_DOUBLE:
737 		(void) nvpair_value_double(nvp, &d);
738 		_zed_event_add_var(eid, zsp, prefix, name, "%g", d);
739 		break;
740 	case DATA_TYPE_HRTIME:
741 		(void) nvpair_value_hrtime(nvp, (hrtime_t *)&i64);
742 		_zed_event_add_var(eid, zsp, prefix, name,
743 		    "%llu", (u_longlong_t)i64);
744 		break;
745 	case DATA_TYPE_STRING:
746 		(void) nvpair_value_string(nvp, &str);
747 		_zed_event_add_var(eid, zsp, prefix, name,
748 		    "%s", (str ? str : "<NULL>"));
749 		break;
750 	case DATA_TYPE_INT8_ARRAY:
751 		_zed_event_add_int8_array(eid, zsp, prefix, nvp);
752 		break;
753 	case DATA_TYPE_UINT8_ARRAY:
754 		_zed_event_add_uint8_array(eid, zsp, prefix, nvp);
755 		break;
756 	case DATA_TYPE_INT16_ARRAY:
757 		_zed_event_add_int16_array(eid, zsp, prefix, nvp);
758 		break;
759 	case DATA_TYPE_UINT16_ARRAY:
760 		_zed_event_add_uint16_array(eid, zsp, prefix, nvp);
761 		break;
762 	case DATA_TYPE_INT32_ARRAY:
763 		_zed_event_add_int32_array(eid, zsp, prefix, nvp);
764 		break;
765 	case DATA_TYPE_UINT32_ARRAY:
766 		_zed_event_add_uint32_array(eid, zsp, prefix, nvp);
767 		break;
768 	case DATA_TYPE_INT64_ARRAY:
769 		_zed_event_add_int64_array(eid, zsp, prefix, nvp);
770 		break;
771 	case DATA_TYPE_UINT64_ARRAY:
772 		_zed_event_add_uint64_array(eid, zsp, prefix, nvp);
773 		break;
774 	case DATA_TYPE_STRING_ARRAY:
775 		_zed_event_add_string_array(eid, zsp, prefix, nvp);
776 		break;
777 	case DATA_TYPE_NVLIST:
778 	case DATA_TYPE_BOOLEAN_ARRAY:
779 	case DATA_TYPE_BYTE_ARRAY:
780 	case DATA_TYPE_NVLIST_ARRAY:
781 		_zed_event_add_var(eid, zsp, prefix, name, "_NOT_IMPLEMENTED_");
782 		break;
783 	default:
784 		errno = EINVAL;
785 		zed_log_msg(LOG_WARNING,
786 		    "Failed to convert nvpair \"%s\" for eid=%llu: "
787 		    "Unrecognized type=%u", name, eid, (unsigned int) type);
788 		break;
789 	}
790 }
791 
792 /*
793  * Restrict various environment variables to safe and sane values
794  * when constructing the environment for the child process, unless
795  * we're running with a custom $PATH (like under the ZFS test suite).
796  *
797  * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
798  */
799 static void
_zed_event_add_env_restrict(uint64_t eid,zed_strings_t * zsp,const char * path)800 _zed_event_add_env_restrict(uint64_t eid, zed_strings_t *zsp,
801     const char *path)
802 {
803 	const char *env_restrict[][2] = {
804 		{ "IFS",		" \t\n" },
805 		{ "PATH",		_PATH_STDPATH },
806 		{ "ZDB",		SBINDIR "/zdb" },
807 		{ "ZED",		SBINDIR "/zed" },
808 		{ "ZFS",		SBINDIR "/zfs" },
809 		{ "ZINJECT",		SBINDIR "/zinject" },
810 		{ "ZPOOL",		SBINDIR "/zpool" },
811 		{ "ZFS_ALIAS",		ZFS_META_ALIAS },
812 		{ "ZFS_VERSION",	ZFS_META_VERSION },
813 		{ "ZFS_RELEASE",	ZFS_META_RELEASE },
814 		{ NULL,			NULL }
815 	};
816 
817 	/*
818 	 * If we have a custom $PATH, use the default ZFS binary locations
819 	 * instead of the hard-coded ones.
820 	 */
821 	const char *env_path[][2] = {
822 		{ "IFS",		" \t\n" },
823 		{ "PATH",		NULL }, /* $PATH copied in later on */
824 		{ "ZDB",		"zdb" },
825 		{ "ZED",		"zed" },
826 		{ "ZFS",		"zfs" },
827 		{ "ZINJECT",		"zinject" },
828 		{ "ZPOOL",		"zpool" },
829 		{ "ZFS_ALIAS",		ZFS_META_ALIAS },
830 		{ "ZFS_VERSION",	ZFS_META_VERSION },
831 		{ "ZFS_RELEASE",	ZFS_META_RELEASE },
832 		{ NULL,			NULL }
833 	};
834 	const char *(*pa)[2];
835 
836 	assert(zsp != NULL);
837 
838 	pa = path != NULL ? env_path : env_restrict;
839 
840 	for (; *(*pa); pa++) {
841 		/* Use our custom $PATH if we have one */
842 		if (path != NULL && strcmp((*pa)[0], "PATH") == 0)
843 			(*pa)[1] = path;
844 
845 		_zed_event_add_var(eid, zsp, NULL, (*pa)[0], "%s", (*pa)[1]);
846 	}
847 }
848 
849 /*
850  * Preserve specified variables from the parent environment
851  * when constructing the environment for the child process.
852  *
853  * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
854  */
855 static void
_zed_event_add_env_preserve(uint64_t eid,zed_strings_t * zsp)856 _zed_event_add_env_preserve(uint64_t eid, zed_strings_t *zsp)
857 {
858 	const char *env_preserve[] = {
859 		"TZ",
860 		NULL
861 	};
862 	const char **keyp;
863 	const char *val;
864 
865 	assert(zsp != NULL);
866 
867 	for (keyp = env_preserve; *keyp; keyp++) {
868 		if ((val = getenv(*keyp)))
869 			_zed_event_add_var(eid, zsp, NULL, *keyp, "%s", val);
870 	}
871 }
872 
873 /*
874  * Compute the "subclass" by removing the first 3 components of [class]
875  * (which will always be of the form "*.fs.zfs").  Return a pointer inside
876  * the string [class], or NULL if insufficient components exist.
877  */
878 static const char *
_zed_event_get_subclass(const char * class)879 _zed_event_get_subclass(const char *class)
880 {
881 	const char *p;
882 	int i;
883 
884 	if (!class)
885 		return (NULL);
886 
887 	p = class;
888 	for (i = 0; i < 3; i++) {
889 		p = strchr(p, '.');
890 		if (!p)
891 			break;
892 		p++;
893 	}
894 	return (p);
895 }
896 
897 /*
898  * Convert the zevent time from a 2-element array of 64b integers
899  * into a more convenient form:
900  * - TIME_SECS is the second component of the time.
901  * - TIME_NSECS is the nanosecond component of the time.
902  * - TIME_STRING is an almost-RFC3339-compliant string representation.
903  */
904 static void
_zed_event_add_time_strings(uint64_t eid,zed_strings_t * zsp,int64_t etime[])905 _zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[])
906 {
907 	struct tm stp;
908 	char buf[32];
909 
910 	assert(zsp != NULL);
911 	assert(etime != NULL);
912 
913 	_zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_SECS",
914 	    "%" PRId64, etime[0]);
915 	_zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_NSECS",
916 	    "%" PRId64, etime[1]);
917 
918 	if (!localtime_r((const time_t *) &etime[0], &stp)) {
919 		zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
920 		    ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "localtime error");
921 	} else if (!strftime(buf, sizeof (buf), "%Y-%m-%d %H:%M:%S%z", &stp)) {
922 		zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
923 		    ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "strftime error");
924 	} else {
925 		_zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_STRING",
926 		    "%s", buf);
927 	}
928 }
929 
930 
931 static void
_zed_event_update_enc_sysfs_path(nvlist_t * nvl)932 _zed_event_update_enc_sysfs_path(nvlist_t *nvl)
933 {
934 	const char *vdev_path;
935 
936 	if (nvlist_lookup_string(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_PATH,
937 	    &vdev_path) != 0) {
938 		return; /* some other kind of event, ignore it */
939 	}
940 
941 	if (vdev_path == NULL) {
942 		return;
943 	}
944 
945 	update_vdev_config_dev_sysfs_path(nvl, vdev_path,
946 	    FM_EREPORT_PAYLOAD_ZFS_VDEV_ENC_SYSFS_PATH);
947 }
948 
949 /*
950  * Service the next zevent, blocking until one is available.
951  */
952 int
zed_event_service(struct zed_conf * zcp)953 zed_event_service(struct zed_conf *zcp)
954 {
955 	nvlist_t *nvl;
956 	nvpair_t *nvp;
957 	int n_dropped;
958 	zed_strings_t *zsp;
959 	uint64_t eid;
960 	int64_t *etime;
961 	uint_t nelem;
962 	const char *class;
963 	const char *subclass;
964 	int rv;
965 
966 	if (!zcp) {
967 		errno = EINVAL;
968 		zed_log_msg(LOG_ERR, "Failed to service zevent: %s",
969 		    strerror(errno));
970 		return (EINVAL);
971 	}
972 	rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped, ZEVENT_NONE,
973 	    zcp->zevent_fd);
974 
975 	if ((rv != 0) || !nvl)
976 		return (errno);
977 
978 	if (n_dropped > 0) {
979 		zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
980 		_bump_event_queue_length();
981 	}
982 	if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
983 		zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
984 	} else if (nvlist_lookup_int64_array(
985 	    nvl, "time", &etime, &nelem) != 0) {
986 		zed_log_msg(LOG_WARNING,
987 		    "Failed to lookup zevent time (eid=%llu)", eid);
988 	} else if (nelem != 2) {
989 		zed_log_msg(LOG_WARNING,
990 		    "Failed to lookup zevent time (eid=%llu, nelem=%u)",
991 		    eid, nelem);
992 	} else if (nvlist_lookup_string(nvl, "class", &class) != 0) {
993 		zed_log_msg(LOG_WARNING,
994 		    "Failed to lookup zevent class (eid=%llu)", eid);
995 	} else {
996 		/*
997 		 * Special case: If we can dynamically detect an enclosure sysfs
998 		 * path, then use that value rather than the one stored in the
999 		 * vd->vdev_enc_sysfs_path.  There have been rare cases where
1000 		 * vd->vdev_enc_sysfs_path becomes outdated.  However, there
1001 		 * will be other times when we can not dynamically detect the
1002 		 * sysfs path (like if a disk disappears) and have to rely on
1003 		 * the old value for things like turning on the fault LED.
1004 		 */
1005 		_zed_event_update_enc_sysfs_path(nvl);
1006 
1007 		/* let internal modules see this event first */
1008 		zfs_agent_post_event(class, NULL, nvl);
1009 
1010 		zsp = zed_strings_create();
1011 
1012 		nvp = NULL;
1013 		while ((nvp = nvlist_next_nvpair(nvl, nvp)))
1014 			_zed_event_add_nvpair(eid, zsp, nvp);
1015 
1016 		_zed_event_add_env_restrict(eid, zsp, zcp->path);
1017 		_zed_event_add_env_preserve(eid, zsp);
1018 
1019 		_zed_event_add_var(eid, zsp, ZED_VAR_PREFIX, "PID",
1020 		    "%d", (int)getpid());
1021 		_zed_event_add_var(eid, zsp, ZED_VAR_PREFIX, "ZEDLET_DIR",
1022 		    "%s", zcp->zedlet_dir);
1023 		subclass = _zed_event_get_subclass(class);
1024 		_zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "SUBCLASS",
1025 		    "%s", (subclass ? subclass : class));
1026 
1027 		_zed_event_add_time_strings(eid, zsp, etime);
1028 
1029 		zed_exec_process(eid, class, subclass, zcp, zsp);
1030 
1031 		zed_conf_write_state(zcp, eid, etime);
1032 
1033 		zed_strings_destroy(zsp);
1034 	}
1035 	nvlist_free(nvl);
1036 	return (0);
1037 }
1038