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