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