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