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