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"
42 static int max_zevent_buf_len
= 1 << 20;
45 * Open the libzfs interface.
48 zed_event_init(struct zed_conf
*zcp
)
51 zed_log_die("Failed zed_event_init: %s", strerror(EINVAL
));
53 zcp
->zfs_hdl
= libzfs_init();
57 zed_log_die("Failed to initialize libzfs");
60 zcp
->zevent_fd
= open(ZFS_DEV
, O_RDWR
| O_CLOEXEC
);
61 if (zcp
->zevent_fd
< 0) {
64 zed_log_die("Failed to open \"%s\": %s",
65 ZFS_DEV
, strerror(errno
));
68 zfs_agent_init(zcp
->zfs_hdl
);
70 if (zed_disk_event_init() != 0) {
73 zed_log_die("Failed to initialize disk events");
76 if (zcp
->max_zevent_buf_len
!= 0)
77 max_zevent_buf_len
= zcp
->max_zevent_buf_len
;
83 * Close the libzfs interface.
86 zed_event_fini(struct zed_conf
*zcp
)
89 zed_log_die("Failed zed_event_fini: %s", strerror(EINVAL
));
91 zed_disk_event_fini();
94 if (zcp
->zevent_fd
>= 0) {
95 if (close(zcp
->zevent_fd
) < 0)
96 zed_log_msg(LOG_WARNING
, "Failed to close \"%s\": %s",
97 ZFS_DEV
, strerror(errno
));
102 libzfs_fini(zcp
->zfs_hdl
);
110 _bump_event_queue_length(void)
113 char qlen_buf
[12] = {0}; /* parameter is int => max "-2147483647\n" */
114 long int qlen
, orig_qlen
;
116 zzlm
= open("/sys/module/zfs/parameters/zfs_zevent_len_max", O_RDWR
);
120 if (read(zzlm
, qlen_buf
, sizeof (qlen_buf
)) < 0)
122 qlen_buf
[sizeof (qlen_buf
) - 1] = '\0';
125 orig_qlen
= qlen
= strtol(qlen_buf
, NULL
, 10);
130 qlen
= 512; /* default zfs_zevent_len_max value */
135 * Don't consume all of kernel memory with event logs if something
138 if (qlen
> max_zevent_buf_len
)
139 qlen
= max_zevent_buf_len
;
140 if (qlen
== orig_qlen
)
142 wr
= snprintf(qlen_buf
, sizeof (qlen_buf
), "%ld", qlen
);
143 if (wr
>= sizeof (qlen_buf
)) {
144 wr
= sizeof (qlen_buf
) - 1;
145 zed_log_msg(LOG_WARNING
, "Truncation in %s()", __func__
);
148 if (pwrite(zzlm
, qlen_buf
, wr
+ 1, 0) < 0)
151 zed_log_msg(LOG_WARNING
, "Bumping queue length to %ld", qlen
);
159 * Seek to the event specified by [saved_eid] and [saved_etime].
160 * This protects against processing a given event more than once.
161 * Return 0 upon a successful seek to the specified event, or -1 otherwise.
163 * A zevent is considered to be uniquely specified by its (eid,time) tuple.
164 * The unsigned 64b eid is set to 1 when the kernel module is loaded, and
165 * incremented by 1 for each new event. Since the state file can persist
166 * across a kernel module reload, the time must be checked to ensure a match.
169 zed_event_seek(struct zed_conf
*zcp
, uint64_t saved_eid
, int64_t saved_etime
[])
181 zed_log_msg(LOG_ERR
, "Failed to seek zevent: %s",
187 while ((eid
< saved_eid
) && !found
) {
188 rv
= zpool_events_next(zcp
->zfs_hdl
, &nvl
, &n_dropped
,
189 ZEVENT_NONBLOCK
, zcp
->zevent_fd
);
191 if ((rv
!= 0) || !nvl
)
195 zed_log_msg(LOG_WARNING
, "Missed %d events", n_dropped
);
196 _bump_event_queue_length();
198 if (nvlist_lookup_uint64(nvl
, "eid", &eid
) != 0) {
199 zed_log_msg(LOG_WARNING
, "Failed to lookup zevent eid");
200 } else if (nvlist_lookup_int64_array(nvl
, "time",
201 &etime
, &nelem
) != 0) {
202 zed_log_msg(LOG_WARNING
,
203 "Failed to lookup zevent time (eid=%llu)", eid
);
204 } else if (nelem
!= 2) {
205 zed_log_msg(LOG_WARNING
,
206 "Failed to lookup zevent time (eid=%llu, nelem=%u)",
208 } else if ((eid
!= saved_eid
) ||
209 (etime
[0] != saved_etime
[0]) ||
210 (etime
[1] != saved_etime
[1])) {
217 if (!found
&& (saved_eid
> 0)) {
218 if (zpool_events_seek(zcp
->zfs_hdl
, ZEVENT_SEEK_START
,
220 zed_log_msg(LOG_WARNING
, "Failed to seek to eid=0");
224 zed_log_msg(LOG_NOTICE
, "Processing events since eid=%llu", eid
);
225 return (found
? 0 : -1);
229 * Return non-zero if nvpair [name] should be formatted in hex; o/w, return 0.
232 _zed_event_value_is_hex(const char *name
)
234 const char *hex_suffix
[] = {
245 for (pp
= hex_suffix
; *pp
; pp
++) {
246 p
= strstr(name
, *pp
);
247 if (p
&& strlen(p
) == strlen(*pp
))
254 * Add an environment variable for [eid] to the container [zsp].
256 * The variable name is the concatenation of [prefix] and [name] converted to
257 * uppercase with non-alphanumeric characters converted to underscores;
258 * [prefix] is optional, and [name] must begin with an alphabetic character.
259 * If the converted variable name already exists within the container [zsp],
260 * its existing value will be replaced with the new value.
262 * The variable value is specified by the format string [fmt].
264 * Returns 0 on success, and -1 on error (with errno set).
266 * All environment variables in [zsp] should be added through this function.
268 static __attribute__((format(printf
, 5, 6))) int
269 _zed_event_add_var(uint64_t eid
, zed_strings_t
*zsp
,
270 const char *prefix
, const char *name
, const char *fmt
, ...)
286 zed_log_msg(LOG_WARNING
,
287 "Failed to add variable for eid=%llu: Name is empty", eid
);
289 } else if (!isalpha(name
[0])) {
291 zed_log_msg(LOG_WARNING
,
292 "Failed to add variable for eid=%llu: "
293 "Name \"%s\" is invalid", eid
, name
);
297 * Construct the string key by converting PREFIX (if present) and NAME.
300 lastp
= keybuf
+ sizeof (keybuf
);
302 for (srcp
= prefix
; *srcp
&& (dstp
< lastp
); srcp
++)
303 *dstp
++ = isalnum(*srcp
) ? toupper(*srcp
) : '_';
305 for (srcp
= name
; *srcp
&& (dstp
< lastp
); srcp
++)
306 *dstp
++ = isalnum(*srcp
) ? toupper(*srcp
) : '_';
309 errno
= ENAMETOOLONG
;
310 zed_log_msg(LOG_WARNING
,
311 "Failed to add variable for eid=%llu: Name too long", eid
);
316 * Construct the string specified by "[PREFIX][NAME]=[FMT]".
319 buflen
= sizeof (valbuf
);
320 n
= strlcpy(dstp
, keybuf
, buflen
);
321 if (n
>= sizeof (valbuf
)) {
323 zed_log_msg(LOG_WARNING
, "Failed to add %s for eid=%llu: %s",
324 keybuf
, eid
, "Exceeded buffer size");
335 zed_log_msg(LOG_WARNING
, "Failed to add %s for eid=%llu: %s",
336 keybuf
, eid
, "Exceeded buffer size");
340 va_start(vargs
, fmt
);
341 n
= vsnprintf(dstp
, buflen
, fmt
, vargs
);
344 if ((n
< 0) || (n
>= buflen
)) {
346 zed_log_msg(LOG_WARNING
, "Failed to add %s for eid=%llu: %s",
347 keybuf
, eid
, "Exceeded buffer size");
349 } else if (zed_strings_add(zsp
, keybuf
, valbuf
) < 0) {
350 zed_log_msg(LOG_WARNING
, "Failed to add %s for eid=%llu: %s",
351 keybuf
, eid
, strerror(errno
));
358 _zed_event_add_array_err(uint64_t eid
, const char *name
)
361 zed_log_msg(LOG_WARNING
,
362 "Failed to convert nvpair \"%s\" for eid=%llu: "
363 "Exceeded buffer size", name
, eid
);
368 _zed_event_add_int8_array(uint64_t eid
, zed_strings_t
*zsp
,
369 const char *prefix
, nvpair_t
*nvp
)
372 int buflen
= sizeof (buf
);
380 assert((nvp
!= NULL
) && (nvpair_type(nvp
) == DATA_TYPE_INT8_ARRAY
));
382 name
= nvpair_name(nvp
);
383 (void) nvpair_value_int8_array(nvp
, &i8p
, &nelem
);
384 for (i
= 0, p
= buf
; (i
< nelem
) && (buflen
> 0); i
++) {
385 n
= snprintf(p
, buflen
, "%d ", i8p
[i
]);
386 if ((n
< 0) || (n
>= buflen
))
387 return (_zed_event_add_array_err(eid
, name
));
394 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
398 _zed_event_add_uint8_array(uint64_t eid
, zed_strings_t
*zsp
,
399 const char *prefix
, nvpair_t
*nvp
)
402 int buflen
= sizeof (buf
);
410 assert((nvp
!= NULL
) && (nvpair_type(nvp
) == DATA_TYPE_UINT8_ARRAY
));
412 name
= nvpair_name(nvp
);
413 (void) nvpair_value_uint8_array(nvp
, &u8p
, &nelem
);
414 for (i
= 0, p
= buf
; (i
< nelem
) && (buflen
> 0); i
++) {
415 n
= snprintf(p
, buflen
, "%u ", u8p
[i
]);
416 if ((n
< 0) || (n
>= buflen
))
417 return (_zed_event_add_array_err(eid
, name
));
424 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
428 _zed_event_add_int16_array(uint64_t eid
, zed_strings_t
*zsp
,
429 const char *prefix
, nvpair_t
*nvp
)
432 int buflen
= sizeof (buf
);
440 assert((nvp
!= NULL
) && (nvpair_type(nvp
) == DATA_TYPE_INT16_ARRAY
));
442 name
= nvpair_name(nvp
);
443 (void) nvpair_value_int16_array(nvp
, &i16p
, &nelem
);
444 for (i
= 0, p
= buf
; (i
< nelem
) && (buflen
> 0); i
++) {
445 n
= snprintf(p
, buflen
, "%d ", i16p
[i
]);
446 if ((n
< 0) || (n
>= buflen
))
447 return (_zed_event_add_array_err(eid
, name
));
454 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
458 _zed_event_add_uint16_array(uint64_t eid
, zed_strings_t
*zsp
,
459 const char *prefix
, nvpair_t
*nvp
)
462 int buflen
= sizeof (buf
);
470 assert((nvp
!= NULL
) && (nvpair_type(nvp
) == DATA_TYPE_UINT16_ARRAY
));
472 name
= nvpair_name(nvp
);
473 (void) nvpair_value_uint16_array(nvp
, &u16p
, &nelem
);
474 for (i
= 0, p
= buf
; (i
< nelem
) && (buflen
> 0); i
++) {
475 n
= snprintf(p
, buflen
, "%u ", u16p
[i
]);
476 if ((n
< 0) || (n
>= buflen
))
477 return (_zed_event_add_array_err(eid
, name
));
484 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
488 _zed_event_add_int32_array(uint64_t eid
, zed_strings_t
*zsp
,
489 const char *prefix
, nvpair_t
*nvp
)
492 int buflen
= sizeof (buf
);
500 assert((nvp
!= NULL
) && (nvpair_type(nvp
) == DATA_TYPE_INT32_ARRAY
));
502 name
= nvpair_name(nvp
);
503 (void) nvpair_value_int32_array(nvp
, &i32p
, &nelem
);
504 for (i
= 0, p
= buf
; (i
< nelem
) && (buflen
> 0); i
++) {
505 n
= snprintf(p
, buflen
, "%d ", i32p
[i
]);
506 if ((n
< 0) || (n
>= buflen
))
507 return (_zed_event_add_array_err(eid
, name
));
514 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
518 _zed_event_add_uint32_array(uint64_t eid
, zed_strings_t
*zsp
,
519 const char *prefix
, nvpair_t
*nvp
)
522 int buflen
= sizeof (buf
);
530 assert((nvp
!= NULL
) && (nvpair_type(nvp
) == DATA_TYPE_UINT32_ARRAY
));
532 name
= nvpair_name(nvp
);
533 (void) nvpair_value_uint32_array(nvp
, &u32p
, &nelem
);
534 for (i
= 0, p
= buf
; (i
< nelem
) && (buflen
> 0); i
++) {
535 n
= snprintf(p
, buflen
, "%u ", u32p
[i
]);
536 if ((n
< 0) || (n
>= buflen
))
537 return (_zed_event_add_array_err(eid
, name
));
544 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
548 _zed_event_add_int64_array(uint64_t eid
, zed_strings_t
*zsp
,
549 const char *prefix
, nvpair_t
*nvp
)
552 int buflen
= sizeof (buf
);
560 assert((nvp
!= NULL
) && (nvpair_type(nvp
) == DATA_TYPE_INT64_ARRAY
));
562 name
= nvpair_name(nvp
);
563 (void) nvpair_value_int64_array(nvp
, &i64p
, &nelem
);
564 for (i
= 0, p
= buf
; (i
< nelem
) && (buflen
> 0); i
++) {
565 n
= snprintf(p
, buflen
, "%lld ", (u_longlong_t
)i64p
[i
]);
566 if ((n
< 0) || (n
>= buflen
))
567 return (_zed_event_add_array_err(eid
, name
));
574 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
578 _zed_event_add_uint64_array(uint64_t eid
, zed_strings_t
*zsp
,
579 const char *prefix
, nvpair_t
*nvp
)
582 int buflen
= sizeof (buf
);
591 assert((nvp
!= NULL
) && (nvpair_type(nvp
) == DATA_TYPE_UINT64_ARRAY
));
593 name
= nvpair_name(nvp
);
594 fmt
= _zed_event_value_is_hex(name
) ? "0x%.16llX " : "%llu ";
595 (void) nvpair_value_uint64_array(nvp
, &u64p
, &nelem
);
596 for (i
= 0, p
= buf
; (i
< nelem
) && (buflen
> 0); i
++) {
597 n
= snprintf(p
, buflen
, fmt
, (u_longlong_t
)u64p
[i
]);
598 if ((n
< 0) || (n
>= buflen
))
599 return (_zed_event_add_array_err(eid
, name
));
606 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
610 _zed_event_add_string_array(uint64_t eid
, zed_strings_t
*zsp
,
611 const char *prefix
, nvpair_t
*nvp
)
614 int buflen
= sizeof (buf
);
622 assert((nvp
!= NULL
) && (nvpair_type(nvp
) == DATA_TYPE_STRING_ARRAY
));
624 name
= nvpair_name(nvp
);
625 (void) nvpair_value_string_array(nvp
, &strp
, &nelem
);
626 for (i
= 0, p
= buf
; (i
< nelem
) && (buflen
> 0); i
++) {
627 n
= snprintf(p
, buflen
, "%s ", strp
[i
] ? strp
[i
] : "<NULL>");
628 if ((n
< 0) || (n
>= buflen
))
629 return (_zed_event_add_array_err(eid
, name
));
636 return (_zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", buf
));
640 * Convert the nvpair [nvp] to a string which is added to the environment
641 * of the child process.
642 * Return 0 on success, -1 on error.
645 _zed_event_add_nvpair(uint64_t eid
, zed_strings_t
*zsp
, nvpair_t
*nvp
)
649 const char *prefix
= ZEVENT_VAR_PREFIX
;
661 name
= nvpair_name(nvp
);
662 type
= nvpair_type(nvp
);
665 case DATA_TYPE_BOOLEAN
:
666 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", "1");
668 case DATA_TYPE_BOOLEAN_VALUE
:
669 (void) nvpair_value_boolean_value(nvp
, &b
);
670 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%s", b
? "1" : "0");
673 (void) nvpair_value_byte(nvp
, &i8
);
674 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%d", i8
);
677 (void) nvpair_value_int8(nvp
, (int8_t *)&i8
);
678 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%d", i8
);
680 case DATA_TYPE_UINT8
:
681 (void) nvpair_value_uint8(nvp
, &i8
);
682 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%u", i8
);
684 case DATA_TYPE_INT16
:
685 (void) nvpair_value_int16(nvp
, (int16_t *)&i16
);
686 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%d", i16
);
688 case DATA_TYPE_UINT16
:
689 (void) nvpair_value_uint16(nvp
, &i16
);
690 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%u", i16
);
692 case DATA_TYPE_INT32
:
693 (void) nvpair_value_int32(nvp
, (int32_t *)&i32
);
694 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%d", i32
);
696 case DATA_TYPE_UINT32
:
697 (void) nvpair_value_uint32(nvp
, &i32
);
698 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%u", i32
);
700 case DATA_TYPE_INT64
:
701 (void) nvpair_value_int64(nvp
, (int64_t *)&i64
);
702 _zed_event_add_var(eid
, zsp
, prefix
, name
,
703 "%lld", (longlong_t
)i64
);
705 case DATA_TYPE_UINT64
:
706 (void) nvpair_value_uint64(nvp
, &i64
);
707 _zed_event_add_var(eid
, zsp
, prefix
, name
,
708 (_zed_event_value_is_hex(name
) ? "0x%.16llX" : "%llu"),
711 * shadow readable strings for vdev state pairs
713 if (strcmp(name
, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE
) == 0 ||
714 strcmp(name
, FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE
) == 0) {
717 (void) snprintf(alt
, sizeof (alt
), "%s_str", name
);
718 _zed_event_add_var(eid
, zsp
, prefix
, alt
, "%s",
719 zpool_state_to_name(i64
, VDEV_AUX_NONE
));
722 * shadow readable strings for pool state
724 if (strcmp(name
, FM_EREPORT_PAYLOAD_ZFS_POOL_STATE
) == 0) {
727 (void) snprintf(alt
, sizeof (alt
), "%s_str", name
);
728 _zed_event_add_var(eid
, zsp
, prefix
, alt
, "%s",
729 zpool_pool_state_to_name(i64
));
732 case DATA_TYPE_DOUBLE
:
733 (void) nvpair_value_double(nvp
, &d
);
734 _zed_event_add_var(eid
, zsp
, prefix
, name
, "%g", d
);
736 case DATA_TYPE_HRTIME
:
737 (void) nvpair_value_hrtime(nvp
, (hrtime_t
*)&i64
);
738 _zed_event_add_var(eid
, zsp
, prefix
, name
,
739 "%llu", (u_longlong_t
)i64
);
741 case DATA_TYPE_STRING
:
742 (void) nvpair_value_string(nvp
, &str
);
743 _zed_event_add_var(eid
, zsp
, prefix
, name
,
744 "%s", (str
? str
: "<NULL>"));
746 case DATA_TYPE_INT8_ARRAY
:
747 _zed_event_add_int8_array(eid
, zsp
, prefix
, nvp
);
749 case DATA_TYPE_UINT8_ARRAY
:
750 _zed_event_add_uint8_array(eid
, zsp
, prefix
, nvp
);
752 case DATA_TYPE_INT16_ARRAY
:
753 _zed_event_add_int16_array(eid
, zsp
, prefix
, nvp
);
755 case DATA_TYPE_UINT16_ARRAY
:
756 _zed_event_add_uint16_array(eid
, zsp
, prefix
, nvp
);
758 case DATA_TYPE_INT32_ARRAY
:
759 _zed_event_add_int32_array(eid
, zsp
, prefix
, nvp
);
761 case DATA_TYPE_UINT32_ARRAY
:
762 _zed_event_add_uint32_array(eid
, zsp
, prefix
, nvp
);
764 case DATA_TYPE_INT64_ARRAY
:
765 _zed_event_add_int64_array(eid
, zsp
, prefix
, nvp
);
767 case DATA_TYPE_UINT64_ARRAY
:
768 _zed_event_add_uint64_array(eid
, zsp
, prefix
, nvp
);
770 case DATA_TYPE_STRING_ARRAY
:
771 _zed_event_add_string_array(eid
, zsp
, prefix
, nvp
);
773 case DATA_TYPE_NVLIST
:
774 case DATA_TYPE_BOOLEAN_ARRAY
:
775 case DATA_TYPE_BYTE_ARRAY
:
776 case DATA_TYPE_NVLIST_ARRAY
:
777 _zed_event_add_var(eid
, zsp
, prefix
, name
, "_NOT_IMPLEMENTED_");
781 zed_log_msg(LOG_WARNING
,
782 "Failed to convert nvpair \"%s\" for eid=%llu: "
783 "Unrecognized type=%u", name
, eid
, (unsigned int) type
);
789 * Restrict various environment variables to safe and sane values
790 * when constructing the environment for the child process, unless
791 * we're running with a custom $PATH (like under the ZFS test suite).
793 * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
796 _zed_event_add_env_restrict(uint64_t eid
, zed_strings_t
*zsp
,
799 const char *env_restrict
[][2] = {
801 { "PATH", _PATH_STDPATH
},
802 { "ZDB", SBINDIR
"/zdb" },
803 { "ZED", SBINDIR
"/zed" },
804 { "ZFS", SBINDIR
"/zfs" },
805 { "ZINJECT", SBINDIR
"/zinject" },
806 { "ZPOOL", SBINDIR
"/zpool" },
807 { "ZFS_ALIAS", ZFS_META_ALIAS
},
808 { "ZFS_VERSION", ZFS_META_VERSION
},
809 { "ZFS_RELEASE", ZFS_META_RELEASE
},
814 * If we have a custom $PATH, use the default ZFS binary locations
815 * instead of the hard-coded ones.
817 const char *env_path
[][2] = {
819 { "PATH", NULL
}, /* $PATH copied in later on */
823 { "ZINJECT", "zinject" },
824 { "ZPOOL", "zpool" },
825 { "ZFS_ALIAS", ZFS_META_ALIAS
},
826 { "ZFS_VERSION", ZFS_META_VERSION
},
827 { "ZFS_RELEASE", ZFS_META_RELEASE
},
830 const char *(*pa
)[2];
834 pa
= path
!= NULL
? env_path
: env_restrict
;
836 for (; *(*pa
); pa
++) {
837 /* Use our custom $PATH if we have one */
838 if (path
!= NULL
&& strcmp((*pa
)[0], "PATH") == 0)
841 _zed_event_add_var(eid
, zsp
, NULL
, (*pa
)[0], "%s", (*pa
)[1]);
846 * Preserve specified variables from the parent environment
847 * when constructing the environment for the child process.
849 * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
852 _zed_event_add_env_preserve(uint64_t eid
, zed_strings_t
*zsp
)
854 const char *env_preserve
[] = {
863 for (keyp
= env_preserve
; *keyp
; keyp
++) {
864 if ((val
= getenv(*keyp
)))
865 _zed_event_add_var(eid
, zsp
, NULL
, *keyp
, "%s", val
);
870 * Compute the "subclass" by removing the first 3 components of [class]
871 * (which will always be of the form "*.fs.zfs"). Return a pointer inside
872 * the string [class], or NULL if insufficient components exist.
875 _zed_event_get_subclass(const char *class)
884 for (i
= 0; i
< 3; i
++) {
894 * Convert the zevent time from a 2-element array of 64b integers
895 * into a more convenient form:
896 * - TIME_SECS is the second component of the time.
897 * - TIME_NSECS is the nanosecond component of the time.
898 * - TIME_STRING is an almost-RFC3339-compliant string representation.
901 _zed_event_add_time_strings(uint64_t eid
, zed_strings_t
*zsp
, int64_t etime
[])
907 assert(etime
!= NULL
);
909 _zed_event_add_var(eid
, zsp
, ZEVENT_VAR_PREFIX
, "TIME_SECS",
910 "%" PRId64
, etime
[0]);
911 _zed_event_add_var(eid
, zsp
, ZEVENT_VAR_PREFIX
, "TIME_NSECS",
912 "%" PRId64
, etime
[1]);
914 if (!localtime_r((const time_t *) &etime
[0], &stp
)) {
915 zed_log_msg(LOG_WARNING
, "Failed to add %s%s for eid=%llu: %s",
916 ZEVENT_VAR_PREFIX
, "TIME_STRING", eid
, "localtime error");
917 } else if (!strftime(buf
, sizeof (buf
), "%Y-%m-%d %H:%M:%S%z", &stp
)) {
918 zed_log_msg(LOG_WARNING
, "Failed to add %s%s for eid=%llu: %s",
919 ZEVENT_VAR_PREFIX
, "TIME_STRING", eid
, "strftime error");
921 _zed_event_add_var(eid
, zsp
, ZEVENT_VAR_PREFIX
, "TIME_STRING",
928 _zed_event_update_enc_sysfs_path(nvlist_t
*nvl
)
930 const char *vdev_path
;
932 if (nvlist_lookup_string(nvl
, FM_EREPORT_PAYLOAD_ZFS_VDEV_PATH
,
934 return; /* some other kind of event, ignore it */
937 if (vdev_path
== NULL
) {
941 update_vdev_config_dev_sysfs_path(nvl
, vdev_path
,
942 FM_EREPORT_PAYLOAD_ZFS_VDEV_ENC_SYSFS_PATH
);
946 * Service the next zevent, blocking until one is available.
949 zed_event_service(struct zed_conf
*zcp
)
959 const char *subclass
;
964 zed_log_msg(LOG_ERR
, "Failed to service zevent: %s",
968 rv
= zpool_events_next(zcp
->zfs_hdl
, &nvl
, &n_dropped
, ZEVENT_NONE
,
971 if ((rv
!= 0) || !nvl
)
975 zed_log_msg(LOG_WARNING
, "Missed %d events", n_dropped
);
976 _bump_event_queue_length();
978 if (nvlist_lookup_uint64(nvl
, "eid", &eid
) != 0) {
979 zed_log_msg(LOG_WARNING
, "Failed to lookup zevent eid");
980 } else if (nvlist_lookup_int64_array(
981 nvl
, "time", &etime
, &nelem
) != 0) {
982 zed_log_msg(LOG_WARNING
,
983 "Failed to lookup zevent time (eid=%llu)", eid
);
984 } else if (nelem
!= 2) {
985 zed_log_msg(LOG_WARNING
,
986 "Failed to lookup zevent time (eid=%llu, nelem=%u)",
988 } else if (nvlist_lookup_string(nvl
, "class", &class) != 0) {
989 zed_log_msg(LOG_WARNING
,
990 "Failed to lookup zevent class (eid=%llu)", eid
);
993 * Special case: If we can dynamically detect an enclosure sysfs
994 * path, then use that value rather than the one stored in the
995 * vd->vdev_enc_sysfs_path. There have been rare cases where
996 * vd->vdev_enc_sysfs_path becomes outdated. However, there
997 * will be other times when we can not dynamically detect the
998 * sysfs path (like if a disk disappears) and have to rely on
999 * the old value for things like turning on the fault LED.
1001 _zed_event_update_enc_sysfs_path(nvl
);
1003 /* let internal modules see this event first */
1004 zfs_agent_post_event(class, NULL
, nvl
);
1006 zsp
= zed_strings_create();
1009 while ((nvp
= nvlist_next_nvpair(nvl
, nvp
)))
1010 _zed_event_add_nvpair(eid
, zsp
, nvp
);
1012 _zed_event_add_env_restrict(eid
, zsp
, zcp
->path
);
1013 _zed_event_add_env_preserve(eid
, zsp
);
1015 _zed_event_add_var(eid
, zsp
, ZED_VAR_PREFIX
, "PID",
1016 "%d", (int)getpid());
1017 _zed_event_add_var(eid
, zsp
, ZED_VAR_PREFIX
, "ZEDLET_DIR",
1018 "%s", zcp
->zedlet_dir
);
1019 subclass
= _zed_event_get_subclass(class);
1020 _zed_event_add_var(eid
, zsp
, ZEVENT_VAR_PREFIX
, "SUBCLASS",
1021 "%s", (subclass
? subclass
: class));
1023 _zed_event_add_time_strings(eid
, zsp
, etime
);
1025 zed_exec_process(eid
, class, subclass
, zcp
, zsp
);
1027 zed_conf_write_state(zcp
, eid
, etime
);
1029 zed_strings_destroy(zsp
);