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.
18 #include <libzfs_core.h>
24 #include <sys/zfs_ioctl.h>
27 #include <sys/fm/fs/zfs.h>
30 #include "zed_disk_event.h"
31 #include "zed_event.h"
35 #include "zed_strings.h"
37 #include "agents/zfs_agents.h"
41 static int max_zevent_buf_len
= 1 << 20;
44 * Open the libzfs interface.
47 zed_event_init(struct zed_conf
*zcp
)
50 zed_log_die("Failed zed_event_init: %s", strerror(EINVAL
));
52 zcp
->zfs_hdl
= libzfs_init();
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) {
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) {
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
;
82 * Close the libzfs interface.
85 zed_event_fini(struct zed_conf
*zcp
)
88 zed_log_die("Failed zed_event_fini: %s", strerror(EINVAL
));
90 zed_disk_event_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
));
101 libzfs_fini(zcp
->zfs_hdl
);
109 _bump_event_queue_length(void)
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
);
119 if (read(zzlm
, qlen_buf
, sizeof (qlen_buf
)) < 0)
121 qlen_buf
[sizeof (qlen_buf
) - 1] = '\0';
124 orig_qlen
= qlen
= strtol(qlen_buf
, NULL
, 10);
129 qlen
= 512; /* default zfs_zevent_len_max value */
134 * Don't consume all of kernel memory with event logs if something
137 if (qlen
> max_zevent_buf_len
)
138 qlen
= max_zevent_buf_len
;
139 if (qlen
== orig_qlen
)
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)
150 zed_log_msg(LOG_WARNING
, "Bumping queue length to %ld", qlen
);
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
[])
180 zed_log_msg(LOG_ERR
, "Failed to seek zevent: %s",
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
)
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)",
207 } else if ((eid
!= saved_eid
) ||
208 (etime
[0] != saved_etime
[0]) ||
209 (etime
[1] != saved_etime
[1])) {
216 if (!found
&& (saved_eid
> 0)) {
217 if (zpool_events_seek(zcp
->zfs_hdl
, ZEVENT_SEEK_START
,
219 zed_log_msg(LOG_WARNING
, "Failed to seek to 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.
231 _zed_event_value_is_hex(const char *name
)
233 const char *hex_suffix
[] = {
244 for (pp
= hex_suffix
; *pp
; pp
++) {
245 p
= strstr(name
, *pp
);
246 if (p
&& strlen(p
) == strlen(*pp
))
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
, ...)
285 zed_log_msg(LOG_WARNING
,
286 "Failed to add variable for eid=%llu: Name is empty", eid
);
288 } else if (!isalpha(name
[0])) {
290 zed_log_msg(LOG_WARNING
,
291 "Failed to add variable for eid=%llu: "
292 "Name \"%s\" is invalid", eid
, name
);
296 * Construct the string key by converting PREFIX (if present) and NAME.
299 lastp
= keybuf
+ sizeof (keybuf
);
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
) : '_';
308 errno
= ENAMETOOLONG
;
309 zed_log_msg(LOG_WARNING
,
310 "Failed to add variable for eid=%llu: Name too long", eid
);
315 * Construct the string specified by "[PREFIX][NAME]=[FMT]".
318 buflen
= sizeof (valbuf
);
319 n
= strlcpy(dstp
, keybuf
, buflen
);
320 if (n
>= sizeof (valbuf
)) {
322 zed_log_msg(LOG_WARNING
, "Failed to add %s for eid=%llu: %s",
323 keybuf
, eid
, "Exceeded buffer size");
334 zed_log_msg(LOG_WARNING
, "Failed to add %s for eid=%llu: %s",
335 keybuf
, eid
, "Exceeded buffer size");
339 va_start(vargs
, fmt
);
340 n
= vsnprintf(dstp
, buflen
, fmt
, vargs
);
343 if ((n
< 0) || (n
>= buflen
)) {
345 zed_log_msg(LOG_WARNING
, "Failed to add %s for eid=%llu: %s",
346 keybuf
, eid
, "Exceeded buffer size");
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
));
357 _zed_event_add_array_err(uint64_t eid
, const char *name
)
360 zed_log_msg(LOG_WARNING
,
361 "Failed to convert nvpair \"%s\" for eid=%llu: "
362 "Exceeded buffer size", name
, eid
);
367 _zed_event_add_int8_array(uint64_t eid
, zed_strings_t
*zsp
,
368 const char *prefix
, nvpair_t
*nvp
)
371 int buflen
= sizeof (buf
);
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
));
393 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
397 _zed_event_add_uint8_array(uint64_t eid
, zed_strings_t
*zsp
,
398 const char *prefix
, nvpair_t
*nvp
)
401 int buflen
= sizeof (buf
);
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
));
423 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
427 _zed_event_add_int16_array(uint64_t eid
, zed_strings_t
*zsp
,
428 const char *prefix
, nvpair_t
*nvp
)
431 int buflen
= sizeof (buf
);
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
));
453 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
457 _zed_event_add_uint16_array(uint64_t eid
, zed_strings_t
*zsp
,
458 const char *prefix
, nvpair_t
*nvp
)
461 int buflen
= sizeof (buf
);
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
));
483 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
487 _zed_event_add_int32_array(uint64_t eid
, zed_strings_t
*zsp
,
488 const char *prefix
, nvpair_t
*nvp
)
491 int buflen
= sizeof (buf
);
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
));
513 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
517 _zed_event_add_uint32_array(uint64_t eid
, zed_strings_t
*zsp
,
518 const char *prefix
, nvpair_t
*nvp
)
521 int buflen
= sizeof (buf
);
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
));
543 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
547 _zed_event_add_int64_array(uint64_t eid
, zed_strings_t
*zsp
,
548 const char *prefix
, nvpair_t
*nvp
)
551 int buflen
= sizeof (buf
);
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
));
573 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
577 _zed_event_add_uint64_array(uint64_t eid
, zed_strings_t
*zsp
,
578 const char *prefix
, nvpair_t
*nvp
)
581 int buflen
= sizeof (buf
);
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
));
605 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
609 _zed_event_add_string_array(uint64_t eid
, zed_strings_t
*zsp
,
610 const char *prefix
, nvpair_t
*nvp
)
613 int buflen
= sizeof (buf
);
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
));
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.
644 _zed_event_add_nvpair(uint64_t eid
, zed_strings_t
*zsp
, nvpair_t
*nvp
)
648 const char *prefix
= ZEVENT_VAR_PREFIX
;
660 name
= nvpair_name(nvp
);
661 type
= nvpair_type(nvp
);
664 case DATA_TYPE_BOOLEAN
:
665 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", "1");
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");
672 (void) nvpair_value_byte(nvp
, &i8
);
673 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%d", i8
);
676 (void) nvpair_value_int8(nvp
, (int8_t *)&i8
);
677 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%d", i8
);
679 case DATA_TYPE_UINT8
:
680 (void) nvpair_value_uint8(nvp
, &i8
);
681 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%u", i8
);
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
);
687 case DATA_TYPE_UINT16
:
688 (void) nvpair_value_uint16(nvp
, &i16
);
689 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%u", i16
);
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
);
695 case DATA_TYPE_UINT32
:
696 (void) nvpair_value_uint32(nvp
, &i32
);
697 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%u", i32
);
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
);
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"),
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) {
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
));
721 * shadow readable strings for pool state
723 if (strcmp(name
, FM_EREPORT_PAYLOAD_ZFS_POOL_STATE
) == 0) {
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
));
731 case DATA_TYPE_DOUBLE
:
732 (void) nvpair_value_double(nvp
, &d
);
733 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%g", d
);
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
);
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>"));
745 case DATA_TYPE_INT8_ARRAY
:
746 _zed_event_add_int8_array(eid
, zsp
, prefix
, nvp
);
748 case DATA_TYPE_UINT8_ARRAY
:
749 _zed_event_add_uint8_array(eid
, zsp
, prefix
, nvp
);
751 case DATA_TYPE_INT16_ARRAY
:
752 _zed_event_add_int16_array(eid
, zsp
, prefix
, nvp
);
754 case DATA_TYPE_UINT16_ARRAY
:
755 _zed_event_add_uint16_array(eid
, zsp
, prefix
, nvp
);
757 case DATA_TYPE_INT32_ARRAY
:
758 _zed_event_add_int32_array(eid
, zsp
, prefix
, nvp
);
760 case DATA_TYPE_UINT32_ARRAY
:
761 _zed_event_add_uint32_array(eid
, zsp
, prefix
, nvp
);
763 case DATA_TYPE_INT64_ARRAY
:
764 _zed_event_add_int64_array(eid
, zsp
, prefix
, nvp
);
766 case DATA_TYPE_UINT64_ARRAY
:
767 _zed_event_add_uint64_array(eid
, zsp
, prefix
, nvp
);
769 case DATA_TYPE_STRING_ARRAY
:
770 _zed_event_add_string_array(eid
, zsp
, prefix
, nvp
);
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_");
780 zed_log_msg(LOG_WARNING
,
781 "Failed to convert nvpair \"%s\" for eid=%llu: "
782 "Unrecognized type=%u", name
, eid
, (unsigned int) type
);
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.
795 _zed_event_add_env_restrict(uint64_t eid
, zed_strings_t
*zsp
,
798 const char *env_restrict
[][2] = {
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
},
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] = {
818 { "PATH", NULL
}, /* $PATH copied in later on */
822 { "ZINJECT", "zinject" },
823 { "ZPOOL", "zpool" },
824 { "ZFS_ALIAS", ZFS_META_ALIAS
},
825 { "ZFS_VERSION", ZFS_META_VERSION
},
826 { "ZFS_RELEASE", ZFS_META_RELEASE
},
829 const char *(*pa
)[2];
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)
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.
851 _zed_event_add_env_preserve(uint64_t eid
, zed_strings_t
*zsp
)
853 const char *env_preserve
[] = {
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.
874 _zed_event_get_subclass(const char *class)
883 for (i
= 0; i
< 3; i
++) {
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.
900 _zed_event_add_time_strings(uint64_t eid
, zed_strings_t
*zsp
, int64_t etime
[])
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");
920 _zed_event_add_var(eid
, zsp
, ZEVENT_VAR_PREFIX
, "TIME_STRING",
926 * Service the next zevent, blocking until one is available.
929 zed_event_service(struct zed_conf
*zcp
)
939 const char *subclass
;
944 zed_log_msg(LOG_ERR
, "Failed to service zevent: %s",
948 rv
= zpool_events_next(zcp
->zfs_hdl
, &nvl
, &n_dropped
, ZEVENT_NONE
,
951 if ((rv
!= 0) || !nvl
)
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)",
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
);
972 /* let internal modules see this event first */
973 zfs_agent_post_event(class, NULL
, nvl
);
975 zsp
= zed_strings_create();
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
);