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