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