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