138363Swpaul/* 238363Swpaul * This file is part of the ZFS Event Daemon (ZED). 338363Swpaul * 438363Swpaul * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). 538363Swpaul * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. 638363Swpaul * Refer to the OpenZFS git commit log for authoritative copyright attribution. 738363Swpaul * 838363Swpaul * The contents of this file are subject to the terms of the 938363Swpaul * Common Development and Distribution License Version 1.0 (CDDL-1.0). 1038363Swpaul * You can obtain a copy of the license from the top-level file 1138363Swpaul * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>. 1238363Swpaul * You may not use this file except in compliance with the license. 1338363Swpaul */ 1438363Swpaul 1538363Swpaul#include <ctype.h> 1638363Swpaul#include <errno.h> 1738363Swpaul#include <fcntl.h> 1838363Swpaul#include <libzfs_core.h> 1938363Swpaul#include <paths.h> 2038363Swpaul#include <stdarg.h> 2138363Swpaul#include <stdio.h> 2238363Swpaul#include <stdlib.h> 2338363Swpaul#include <string.h> 2438363Swpaul#include <sys/zfs_ioctl.h> 2538363Swpaul#include <time.h> 2638363Swpaul#include <unistd.h> 2738363Swpaul#include <sys/fm/fs/zfs.h> 2838363Swpaul#include "zed.h" 2938363Swpaul#include "zed_conf.h" 3038363Swpaul#include "zed_disk_event.h" 3138363Swpaul#include "zed_event.h" 3246514Swpaul#include "zed_exec.h" 3338363Swpaul#include "zed_file.h" 3438363Swpaul#include "zed_log.h" 3538363Swpaul#include "zed_strings.h" 3638363Swpaul 3738363Swpaul#include "agents/zfs_agents.h" 3838363Swpaul#include <libzutil.h> 3938363Swpaul 4038363Swpaul#define MAXBUF 4096 4138363Swpaul 4238363Swpaulstatic int max_zevent_buf_len = 1 << 20; 4338363Swpaul 4438363Swpaul/* 4538363Swpaul * Open the libzfs interface. 4638363Swpaul */ 4738363Swpaulint 4838363Swpaulzed_event_init(struct zed_conf *zcp) 4938363Swpaul{ 5038363Swpaul if (!zcp) 5138363Swpaul zed_log_die("Failed zed_event_init: %s", strerror(EINVAL)); 5238363Swpaul 5338363Swpaul zcp->zfs_hdl = libzfs_init(); 5438363Swpaul if (!zcp->zfs_hdl) { 5538363Swpaul if (zcp->do_idle) 5638363Swpaul return (-1); 5738363Swpaul zed_log_die("Failed to initialize libzfs"); 5838363Swpaul } 5938363Swpaul 6038363Swpaul zcp->zevent_fd = open(ZFS_DEV, O_RDWR | O_CLOEXEC); 6138363Swpaul if (zcp->zevent_fd < 0) { 6238363Swpaul if (zcp->do_idle) 6338363Swpaul return (-1); 6438363Swpaul zed_log_die("Failed to open \"%s\": %s", 6538363Swpaul ZFS_DEV, strerror(errno)); 6638363Swpaul } 6738363Swpaul 6838363Swpaul zfs_agent_init(zcp->zfs_hdl); 6938363Swpaul 7038363Swpaul if (zed_disk_event_init() != 0) { 7138363Swpaul if (zcp->do_idle) 7238363Swpaul return (-1); 7338363Swpaul zed_log_die("Failed to initialize disk events"); 7438363Swpaul } 7538363Swpaul 7638363Swpaul if (zcp->max_zevent_buf_len != 0) 7738363Swpaul max_zevent_buf_len = zcp->max_zevent_buf_len; 7838363Swpaul 7938363Swpaul return (0); 8038363Swpaul} 8138363Swpaul 8238363Swpaul/* 8338363Swpaul * Close the libzfs interface. 8438363Swpaul */ 8538363Swpaulvoid 8638363Swpaulzed_event_fini(struct zed_conf *zcp) 8738363Swpaul{ 8838363Swpaul if (!zcp) 8938363Swpaul zed_log_die("Failed zed_event_fini: %s", strerror(EINVAL)); 9038363Swpaul 9138363Swpaul zed_disk_event_fini(); 9238363Swpaul zfs_agent_fini(); 9338363Swpaul 9438363Swpaul if (zcp->zevent_fd >= 0) { 9538363Swpaul if (close(zcp->zevent_fd) < 0) 9638363Swpaul zed_log_msg(LOG_WARNING, "Failed to close \"%s\": %s", 9738363Swpaul ZFS_DEV, strerror(errno)); 9838363Swpaul 9938363Swpaul zcp->zevent_fd = -1; 10038363Swpaul } 10138363Swpaul if (zcp->zfs_hdl) { 10238363Swpaul libzfs_fini(zcp->zfs_hdl); 10338363Swpaul zcp->zfs_hdl = NULL; 10438363Swpaul } 10538363Swpaul 10638363Swpaul zed_exec_fini(); 10738363Swpaul} 10838363Swpaul 10938363Swpaulstatic void 11038363Swpaul_bump_event_queue_length(void) 11138363Swpaul{ 11238363Swpaul int zzlm = -1, wr; 11338363Swpaul char qlen_buf[12] = {0}; /* parameter is int => max "-2147483647\n" */ 11438363Swpaul long int qlen, orig_qlen; 11538363Swpaul 11638363Swpaul zzlm = open("/sys/module/zfs/parameters/zfs_zevent_len_max", O_RDWR); 11738363Swpaul if (zzlm < 0) 11838363Swpaul goto done; 11938363Swpaul 12038363Swpaul if (read(zzlm, qlen_buf, sizeof (qlen_buf)) < 0) 12138363Swpaul goto done; 12238363Swpaul qlen_buf[sizeof (qlen_buf) - 1] = '\0'; 12338363Swpaul 12438363Swpaul errno = 0; 12538363Swpaul orig_qlen = qlen = strtol(qlen_buf, NULL, 10); 12638363Swpaul if (errno == ERANGE) 12738363Swpaul goto done; 12838363Swpaul 12938363Swpaul if (qlen <= 0) 13038363Swpaul qlen = 512; /* default zfs_zevent_len_max value */ 13138363Swpaul else 13238363Swpaul qlen *= 2; 13338363Swpaul 13438363Swpaul /* 13538363Swpaul * Don't consume all of kernel memory with event logs if something 13638363Swpaul * goes wrong. 13738363Swpaul */ 13838363Swpaul if (qlen > max_zevent_buf_len) 13938363Swpaul qlen = max_zevent_buf_len; 14038363Swpaul if (qlen == orig_qlen) 14138363Swpaul goto done; 14238363Swpaul wr = snprintf(qlen_buf, sizeof (qlen_buf), "%ld", qlen); 14338363Swpaul if (wr >= sizeof (qlen_buf)) { 14438363Swpaul wr = sizeof (qlen_buf) - 1; 14538363Swpaul zed_log_msg(LOG_WARNING, "Truncation in %s()", __func__); 14638363Swpaul } 14738363Swpaul 14838363Swpaul if (pwrite(zzlm, qlen_buf, wr + 1, 0) < 0) 14938363Swpaul goto done; 15038363Swpaul 15138363Swpaul zed_log_msg(LOG_WARNING, "Bumping queue length to %ld", qlen); 15238363Swpaul 15338363Swpauldone: 15438363Swpaul if (zzlm > -1) 15538363Swpaul (void) close(zzlm); 15638363Swpaul} 15738363Swpaul 15838363Swpaul/* 15938363Swpaul * Seek to the event specified by [saved_eid] and [saved_etime]. 16038363Swpaul * This protects against processing a given event more than once. 16138363Swpaul * Return 0 upon a successful seek to the specified event, or -1 otherwise. 16238363Swpaul * 16338363Swpaul * A zevent is considered to be uniquely specified by its (eid,time) tuple. 16438363Swpaul * The unsigned 64b eid is set to 1 when the kernel module is loaded, and 16538363Swpaul * incremented by 1 for each new event. Since the state file can persist 16638363Swpaul * across a kernel module reload, the time must be checked to ensure a match. 16738363Swpaul */ 16838363Swpaulint 16938363Swpaulzed_event_seek(struct zed_conf *zcp, uint64_t saved_eid, int64_t saved_etime[]) 17038363Swpaul{ 17138363Swpaul uint64_t eid; 17238363Swpaul int found; 17338363Swpaul nvlist_t *nvl; 17438526Swpaul int n_dropped; 17538526Swpaul int64_t *etime; 17638526Swpaul uint_t nelem; 17738526Swpaul int rv; 17838526Swpaul 17938526Swpaul if (!zcp) { 18038526Swpaul errno = EINVAL; 18138363Swpaul zed_log_msg(LOG_ERR, "Failed to seek zevent: %s", 18238363Swpaul strerror(errno)); 18338363Swpaul return (-1); 18438363Swpaul } 18538363Swpaul eid = 0; 18638363Swpaul found = 0; 18738363Swpaul while ((eid < saved_eid) && !found) { 18838363Swpaul rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped, 18938363Swpaul ZEVENT_NONBLOCK, zcp->zevent_fd); 19038363Swpaul 19138363Swpaul if ((rv != 0) || !nvl) 19238363Swpaul break; 19338363Swpaul 19438363Swpaul if (n_dropped > 0) { 19538363Swpaul zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped); 19638363Swpaul _bump_event_queue_length(); 19738363Swpaul } 19838363Swpaul if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) { 19938363Swpaul zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid"); 20038363Swpaul } else if (nvlist_lookup_int64_array(nvl, "time", 20138363Swpaul &etime, &nelem) != 0) { 20238363Swpaul zed_log_msg(LOG_WARNING, 20338363Swpaul "Failed to lookup zevent time (eid=%llu)", eid); 20438363Swpaul } else if (nelem != 2) { 20538363Swpaul zed_log_msg(LOG_WARNING, 20638363Swpaul "Failed to lookup zevent time (eid=%llu, nelem=%u)", 20738363Swpaul eid, nelem); 20838363Swpaul } else if ((eid != saved_eid) || 20938363Swpaul (etime[0] != saved_etime[0]) || 21038363Swpaul (etime[1] != saved_etime[1])) { 21138363Swpaul /* no-op */ 21238363Swpaul } else { 21338363Swpaul found = 1; 21438363Swpaul } 21538363Swpaul free(nvl); 21638363Swpaul } 21738363Swpaul if (!found && (saved_eid > 0)) { 21838363Swpaul if (zpool_events_seek(zcp->zfs_hdl, ZEVENT_SEEK_START, 21938363Swpaul zcp->zevent_fd) < 0) 22038363Swpaul zed_log_msg(LOG_WARNING, "Failed to seek to eid=0"); 22138363Swpaul else 22238363Swpaul eid = 0; 22338363Swpaul } 22438363Swpaul zed_log_msg(LOG_NOTICE, "Processing events since eid=%llu", eid); 22538363Swpaul return (found ? 0 : -1); 22638363Swpaul} 22738363Swpaul 22838363Swpaul/* 22938363Swpaul * Return non-zero if nvpair [name] should be formatted in hex; o/w, return 0. 23038363Swpaul */ 23138363Swpaulstatic int 23238363Swpaul_zed_event_value_is_hex(const char *name) 23338363Swpaul{ 23438363Swpaul const char *hex_suffix[] = { 23538363Swpaul "_guid", 23638363Swpaul "_guids", 23738363Swpaul NULL 23838363Swpaul }; 23938363Swpaul const char **pp; 24038363Swpaul char *p; 24138363Swpaul 24238363Swpaul if (!name) 24338363Swpaul return (0); 24438363Swpaul 24538363Swpaul for (pp = hex_suffix; *pp; pp++) { 24638363Swpaul p = strstr(name, *pp); 24738363Swpaul if (p && strlen(p) == strlen(*pp)) 24838363Swpaul return (1); 24938363Swpaul } 25038363Swpaul return (0); 25138363Swpaul} 25238363Swpaul 25338363Swpaul/* 25438363Swpaul * Add an environment variable for [eid] to the container [zsp]. 25538363Swpaul * 25638363Swpaul * The variable name is the concatenation of [prefix] and [name] converted to 25738363Swpaul * uppercase with non-alphanumeric characters converted to underscores; 25838363Swpaul * [prefix] is optional, and [name] must begin with an alphabetic character. 25938363Swpaul * If the converted variable name already exists within the container [zsp], 26038363Swpaul * its existing value will be replaced with the new value. 26138363Swpaul * 26238363Swpaul * The variable value is specified by the format string [fmt]. 26338363Swpaul * 26438363Swpaul * Returns 0 on success, and -1 on error (with errno set). 26538363Swpaul * 26638363Swpaul * All environment variables in [zsp] should be added through this function. 26738363Swpaul */ 26838363Swpaulstatic __attribute__((format(printf, 5, 6))) int 26938363Swpaul_zed_event_add_var(uint64_t eid, zed_strings_t *zsp, 27038363Swpaul const char *prefix, const char *name, const char *fmt, ...) 27138363Swpaul{ 27238363Swpaul char keybuf[MAXBUF]; 27338363Swpaul char valbuf[MAXBUF]; 27438363Swpaul char *dstp; 27538363Swpaul const char *srcp; 27638363Swpaul const char *lastp; 27738363Swpaul int n; 27838363Swpaul int buflen; 27938363Swpaul va_list vargs; 28038363Swpaul 28138363Swpaul assert(zsp != NULL); 28238363Swpaul assert(fmt != NULL); 28338363Swpaul 28438363Swpaul if (!name) { 28538363Swpaul errno = EINVAL; 28638363Swpaul zed_log_msg(LOG_WARNING, 28738363Swpaul "Failed to add variable for eid=%llu: Name is empty", eid); 28838363Swpaul return (-1); 28938363Swpaul } else if (!isalpha(name[0])) { 29038363Swpaul errno = EINVAL; 29138363Swpaul zed_log_msg(LOG_WARNING, 29238363Swpaul "Failed to add variable for eid=%llu: " 29338363Swpaul "Name \"%s\" is invalid", eid, name); 29438363Swpaul return (-1); 29538363Swpaul } 29638363Swpaul /* 29738363Swpaul * Construct the string key by converting PREFIX (if present) and NAME. 29838363Swpaul */ 29938363Swpaul dstp = keybuf; 30038363Swpaul lastp = keybuf + sizeof (keybuf); 30138363Swpaul if (prefix) { 30238363Swpaul for (srcp = prefix; *srcp && (dstp < lastp); srcp++) 30338363Swpaul *dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_'; 30438363Swpaul } 30538363Swpaul for (srcp = name; *srcp && (dstp < lastp); srcp++) 30638363Swpaul *dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_'; 30738363Swpaul 30838363Swpaul if (dstp == lastp) { 30938363Swpaul errno = ENAMETOOLONG; 31038363Swpaul zed_log_msg(LOG_WARNING, 31138363Swpaul "Failed to add variable for eid=%llu: Name too long", eid); 31238363Swpaul return (-1); 31338363Swpaul } 31438363Swpaul *dstp = '\0'; 31538363Swpaul /* 31638363Swpaul * Construct the string specified by "[PREFIX][NAME]=[FMT]". 31738363Swpaul */ 31838363Swpaul dstp = valbuf; 31938363Swpaul buflen = sizeof (valbuf); 32038363Swpaul n = strlcpy(dstp, keybuf, buflen); 32138363Swpaul if (n >= sizeof (valbuf)) { 32238363Swpaul errno = EMSGSIZE; 32338363Swpaul zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s", 32438363Swpaul keybuf, eid, "Exceeded buffer size"); 32538363Swpaul return (-1); 32638363Swpaul } 32738363Swpaul dstp += n; 32838363Swpaul buflen -= n; 32938363Swpaul 33038363Swpaul *dstp++ = '='; 33138363Swpaul buflen--; 33238363Swpaul 33338363Swpaul if (buflen <= 0) { 33438363Swpaul errno = EMSGSIZE; 33538363Swpaul zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s", 33638363Swpaul keybuf, eid, "Exceeded buffer size"); 33738363Swpaul return (-1); 33838363Swpaul } 33938363Swpaul 34038363Swpaul va_start(vargs, fmt); 34138363Swpaul n = vsnprintf(dstp, buflen, fmt, vargs); 34238363Swpaul va_end(vargs); 34338363Swpaul 34438363Swpaul if ((n < 0) || (n >= buflen)) { 34538363Swpaul errno = EMSGSIZE; 34638363Swpaul zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s", 34738363Swpaul keybuf, eid, "Exceeded buffer size"); 34838363Swpaul return (-1); 34938363Swpaul } else if (zed_strings_add(zsp, keybuf, valbuf) < 0) { 35038363Swpaul zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s", 35138363Swpaul keybuf, eid, strerror(errno)); 35238363Swpaul return (-1); 35338363Swpaul } 35438363Swpaul return (0); 35538363Swpaul} 35638363Swpaul 35738363Swpaulstatic int 35838363Swpaul_zed_event_add_array_err(uint64_t eid, const char *name) 35938363Swpaul{ 36038363Swpaul errno = EMSGSIZE; 36138363Swpaul zed_log_msg(LOG_WARNING, 36238363Swpaul "Failed to convert nvpair \"%s\" for eid=%llu: " 36338363Swpaul "Exceeded buffer size", name, eid); 36440588Swpaul return (-1); 36538363Swpaul} 36638363Swpaul 36738363Swpaulstatic int 36838363Swpaul_zed_event_add_int8_array(uint64_t eid, zed_strings_t *zsp, 36938363Swpaul const char *prefix, nvpair_t *nvp) 37038363Swpaul{ 37138363Swpaul char buf[MAXBUF]; 37238363Swpaul int buflen = sizeof (buf); 37338363Swpaul const char *name; 37438363Swpaul int8_t *i8p; 37538363Swpaul uint_t nelem; 37638363Swpaul uint_t i; 37738363Swpaul char *p; 37838363Swpaul int n; 37938363Swpaul 38038363Swpaul assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT8_ARRAY)); 38138363Swpaul 38238363Swpaul name = nvpair_name(nvp); 38338363Swpaul (void) nvpair_value_int8_array(nvp, &i8p, &nelem); 38438363Swpaul for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) { 38538363Swpaul n = snprintf(p, buflen, "%d ", i8p[i]); 38638363Swpaul if ((n < 0) || (n >= buflen)) 38738363Swpaul return (_zed_event_add_array_err(eid, name)); 38838363Swpaul p += n; 38938363Swpaul buflen -= n; 39038363Swpaul } 39138363Swpaul if (nelem > 0) 39238363Swpaul *--p = '\0'; 39338363Swpaul 39438363Swpaul return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf)); 39538363Swpaul} 39638363Swpaul 39738363Swpaulstatic int 39838363Swpaul_zed_event_add_uint8_array(uint64_t eid, zed_strings_t *zsp, 39938363Swpaul const char *prefix, nvpair_t *nvp) 40038363Swpaul{ 40138363Swpaul char buf[MAXBUF]; 40238363Swpaul int buflen = sizeof (buf); 40338363Swpaul const char *name; 40438363Swpaul uint8_t *u8p; 40538363Swpaul uint_t nelem; 40638363Swpaul uint_t i; 40738363Swpaul char *p; 40838363Swpaul int n; 40938363Swpaul 41038363Swpaul assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT8_ARRAY)); 41138363Swpaul 41238363Swpaul name = nvpair_name(nvp); 41338363Swpaul (void) nvpair_value_uint8_array(nvp, &u8p, &nelem); 41438363Swpaul for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) { 41538363Swpaul n = snprintf(p, buflen, "%u ", u8p[i]); 41638363Swpaul if ((n < 0) || (n >= buflen)) 41738363Swpaul return (_zed_event_add_array_err(eid, name)); 41838363Swpaul p += n; 41938363Swpaul buflen -= n; 42038363Swpaul } 42138363Swpaul if (nelem > 0) 42238363Swpaul *--p = '\0'; 42338363Swpaul 42438363Swpaul return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf)); 42538363Swpaul} 42638363Swpaul 42738363Swpaulstatic int 42838363Swpaul_zed_event_add_int16_array(uint64_t eid, zed_strings_t *zsp, 42938363Swpaul const char *prefix, nvpair_t *nvp) 43038363Swpaul{ 43138363Swpaul char buf[MAXBUF]; 43238363Swpaul int buflen = sizeof (buf); 43338363Swpaul const char *name; 43438363Swpaul int16_t *i16p; 43538363Swpaul uint_t nelem; 43638363Swpaul uint_t i; 43738363Swpaul char *p; 43838363Swpaul int n; 43938363Swpaul 44046204Swpaul assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT16_ARRAY)); 44146204Swpaul 44238363Swpaul name = nvpair_name(nvp); 44338363Swpaul (void) nvpair_value_int16_array(nvp, &i16p, &nelem); 44438363Swpaul for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) { 44538363Swpaul n = snprintf(p, buflen, "%d ", i16p[i]); 44638363Swpaul if ((n < 0) || (n >= buflen)) 44738363Swpaul return (_zed_event_add_array_err(eid, name)); 44838363Swpaul p += n; 44938363Swpaul buflen -= n; 45038363Swpaul } 45138363Swpaul if (nelem > 0) 45238363Swpaul *--p = '\0'; 45338363Swpaul 45438363Swpaul return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf)); 45538363Swpaul} 45638363Swpaul 45738363Swpaulstatic int 45838363Swpaul_zed_event_add_uint16_array(uint64_t eid, zed_strings_t *zsp, 45938363Swpaul const char *prefix, nvpair_t *nvp) 46038363Swpaul{ 46138363Swpaul char buf[MAXBUF]; 46238363Swpaul int buflen = sizeof (buf); 46338363Swpaul const char *name; 46438363Swpaul uint16_t *u16p; 46538363Swpaul uint_t nelem; 46638363Swpaul uint_t i; 46738363Swpaul char *p; 46838363Swpaul int n; 46938363Swpaul 47038363Swpaul assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT16_ARRAY)); 47138363Swpaul 47238363Swpaul name = nvpair_name(nvp); 47338363Swpaul (void) nvpair_value_uint16_array(nvp, &u16p, &nelem); 47438363Swpaul for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) { 47538363Swpaul n = snprintf(p, buflen, "%u ", u16p[i]); 47638363Swpaul if ((n < 0) || (n >= buflen)) 47738363Swpaul return (_zed_event_add_array_err(eid, name)); 47838363Swpaul p += n; 47938363Swpaul buflen -= n; 48038363Swpaul } 48138363Swpaul if (nelem > 0) 48238363Swpaul *--p = '\0'; 48338363Swpaul 48438363Swpaul return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf)); 48538363Swpaul} 48638363Swpaul 48738363Swpaulstatic int 48838363Swpaul_zed_event_add_int32_array(uint64_t eid, zed_strings_t *zsp, 48938363Swpaul const char *prefix, nvpair_t *nvp) 49038363Swpaul{ 49138363Swpaul char buf[MAXBUF]; 49238363Swpaul int buflen = sizeof (buf); 49338363Swpaul const char *name; 49438363Swpaul int32_t *i32p; 49538363Swpaul uint_t nelem; 49638363Swpaul uint_t i; 49738363Swpaul char *p; 49838363Swpaul int n; 49938363Swpaul 50038363Swpaul assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT32_ARRAY)); 50138363Swpaul 50238363Swpaul name = nvpair_name(nvp); 50338363Swpaul (void) nvpair_value_int32_array(nvp, &i32p, &nelem); 50438363Swpaul for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) { 50538363Swpaul n = snprintf(p, buflen, "%d ", i32p[i]); 50638363Swpaul if ((n < 0) || (n >= buflen)) 50738363Swpaul return (_zed_event_add_array_err(eid, name)); 50838363Swpaul p += n; 50938363Swpaul buflen -= n; 51038363Swpaul } 51138363Swpaul if (nelem > 0) 51238363Swpaul *--p = '\0'; 51338363Swpaul 51438363Swpaul return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf)); 51538363Swpaul} 51638363Swpaul 51738363Swpaulstatic int 51838363Swpaul_zed_event_add_uint32_array(uint64_t eid, zed_strings_t *zsp, 51938363Swpaul const char *prefix, nvpair_t *nvp) 52038363Swpaul{ 52138363Swpaul char buf[MAXBUF]; 52238363Swpaul int buflen = sizeof (buf); 52338363Swpaul const char *name; 52438363Swpaul uint32_t *u32p; 52538363Swpaul uint_t nelem; 52638363Swpaul uint_t i; 52738363Swpaul char *p; 52838363Swpaul int n; 52938363Swpaul 53038363Swpaul assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT32_ARRAY)); 53138363Swpaul 53238363Swpaul name = nvpair_name(nvp); 53338363Swpaul (void) nvpair_value_uint32_array(nvp, &u32p, &nelem); 53438363Swpaul for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) { 53538363Swpaul n = snprintf(p, buflen, "%u ", u32p[i]); 53638363Swpaul if ((n < 0) || (n >= buflen)) 53738363Swpaul return (_zed_event_add_array_err(eid, name)); 53838363Swpaul p += n; 53938363Swpaul buflen -= n; 54038363Swpaul } 54138363Swpaul if (nelem > 0) 54245062Swpaul *--p = '\0'; 54345062Swpaul 54438363Swpaul return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf)); 54538363Swpaul} 54638363Swpaul 54738363Swpaulstatic int 54838363Swpaul_zed_event_add_int64_array(uint64_t eid, zed_strings_t *zsp, 54938363Swpaul const char *prefix, nvpair_t *nvp) 55038363Swpaul{ 55138363Swpaul char buf[MAXBUF]; 55238363Swpaul int buflen = sizeof (buf); 55338363Swpaul const char *name; 55438363Swpaul int64_t *i64p; 55538363Swpaul uint_t nelem; 55646514Swpaul uint_t i; 55738363Swpaul char *p; 55838363Swpaul int n; 55938363Swpaul 56038363Swpaul assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT64_ARRAY)); 56138363Swpaul 56238363Swpaul name = nvpair_name(nvp); 56338363Swpaul (void) nvpair_value_int64_array(nvp, &i64p, &nelem); 56438363Swpaul for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) { 56538363Swpaul n = snprintf(p, buflen, "%lld ", (u_longlong_t)i64p[i]); 56638363Swpaul if ((n < 0) || (n >= buflen)) 56738363Swpaul return (_zed_event_add_array_err(eid, name)); 56838363Swpaul p += n; 56938363Swpaul buflen -= n; 57038363Swpaul } 57138363Swpaul if (nelem > 0) 57238363Swpaul *--p = '\0'; 57338363Swpaul 57438363Swpaul return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf)); 57538363Swpaul} 57638363Swpaul 57738363Swpaulstatic int 57838363Swpaul_zed_event_add_uint64_array(uint64_t eid, zed_strings_t *zsp, 57938363Swpaul const char *prefix, nvpair_t *nvp) 58038363Swpaul{ 58138363Swpaul char buf[MAXBUF]; 58238363Swpaul int buflen = sizeof (buf); 58338363Swpaul const char *name; 58438363Swpaul const char *fmt; 58538363Swpaul uint64_t *u64p; 58638363Swpaul uint_t nelem; 58738363Swpaul uint_t i; 58838363Swpaul char *p; 58945062Swpaul int n; 59038363Swpaul 59145062Swpaul assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY)); 59238363Swpaul 59345062Swpaul name = nvpair_name(nvp); 59438363Swpaul fmt = _zed_event_value_is_hex(name) ? "0x%.16llX " : "%llu "; 59545062Swpaul (void) nvpair_value_uint64_array(nvp, &u64p, &nelem); 59645062Swpaul for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) { 59745062Swpaul n = snprintf(p, buflen, fmt, (u_longlong_t)u64p[i]); 59845062Swpaul if ((n < 0) || (n >= buflen)) 59945062Swpaul return (_zed_event_add_array_err(eid, name)); 60045062Swpaul p += n; 60138363Swpaul buflen -= n; 60238363Swpaul } 60338363Swpaul if (nelem > 0) 60438363Swpaul *--p = '\0'; 60538363Swpaul 60638363Swpaul return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf)); 60738363Swpaul} 60838363Swpaul 60938363Swpaulstatic int 61038363Swpaul_zed_event_add_string_array(uint64_t eid, zed_strings_t *zsp, 61138363Swpaul const char *prefix, nvpair_t *nvp) 61238363Swpaul{ 61338363Swpaul char buf[MAXBUF]; 61438363Swpaul int buflen = sizeof (buf); 61538363Swpaul const char *name; 61638363Swpaul const char **strp; 61738363Swpaul uint_t nelem; 61838363Swpaul uint_t i; 61938363Swpaul char *p; 62046204Swpaul int n; 62146204Swpaul 62246204Swpaul assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY)); 62345693Swpaul 62446204Swpaul name = nvpair_name(nvp); 62538363Swpaul (void) nvpair_value_string_array(nvp, &strp, &nelem); 62645601Swpaul for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) { 62740097Swpaul n = snprintf(p, buflen, "%s ", strp[i] ? strp[i] : "<NULL>"); 62846204Swpaul if ((n < 0) || (n >= buflen)) 62945629Swpaul return (_zed_event_add_array_err(eid, name)); 63038363Swpaul p += n; 63138363Swpaul buflen -= n; 63238363Swpaul } 63338363Swpaul if (nelem > 0) 63438363Swpaul *--p = '\0'; 63538363Swpaul 63638363Swpaul return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf)); 63738363Swpaul} 63838363Swpaul 63938363Swpaul/* 64038363Swpaul * Convert the nvpair [nvp] to a string which is added to the environment 64138363Swpaul * of the child process. 64238363Swpaul * Return 0 on success, -1 on error. 64338363Swpaul */ 64438363Swpaulstatic void 64538363Swpaul_zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp) 64638363Swpaul{ 64738363Swpaul const char *name; 64838363Swpaul data_type_t type; 64938363Swpaul const char *prefix = ZEVENT_VAR_PREFIX; 65038363Swpaul boolean_t b; 65138363Swpaul double d; 65238363Swpaul uint8_t i8; 65338363Swpaul uint16_t i16; 65438363Swpaul uint32_t i32; 65538363Swpaul uint64_t i64; 65638363Swpaul const char *str; 65738363Swpaul 65838363Swpaul assert(zsp != NULL); 65938363Swpaul assert(nvp != NULL); 66038363Swpaul 66138363Swpaul name = nvpair_name(nvp); 66238363Swpaul type = nvpair_type(nvp); 66338363Swpaul 66438363Swpaul switch (type) { 66538363Swpaul case DATA_TYPE_BOOLEAN: 66638363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%s", "1"); 66738363Swpaul break; 66838363Swpaul case DATA_TYPE_BOOLEAN_VALUE: 66938363Swpaul (void) nvpair_value_boolean_value(nvp, &b); 67038363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%s", b ? "1" : "0"); 67138363Swpaul break; 67238363Swpaul case DATA_TYPE_BYTE: 67338363Swpaul (void) nvpair_value_byte(nvp, &i8); 67438363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%d", i8); 67538363Swpaul break; 67638363Swpaul case DATA_TYPE_INT8: 67738363Swpaul (void) nvpair_value_int8(nvp, (int8_t *)&i8); 67838363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%d", i8); 67938363Swpaul break; 68038363Swpaul case DATA_TYPE_UINT8: 68138363Swpaul (void) nvpair_value_uint8(nvp, &i8); 68238363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%u", i8); 68338363Swpaul break; 68438363Swpaul case DATA_TYPE_INT16: 68538363Swpaul (void) nvpair_value_int16(nvp, (int16_t *)&i16); 68638363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%d", i16); 68738363Swpaul break; 68838363Swpaul case DATA_TYPE_UINT16: 68938363Swpaul (void) nvpair_value_uint16(nvp, &i16); 69038363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%u", i16); 69138363Swpaul break; 69238363Swpaul case DATA_TYPE_INT32: 69338363Swpaul (void) nvpair_value_int32(nvp, (int32_t *)&i32); 69438363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%d", i32); 69538363Swpaul break; 69638363Swpaul case DATA_TYPE_UINT32: 69738363Swpaul (void) nvpair_value_uint32(nvp, &i32); 69838363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%u", i32); 69938363Swpaul break; 70038363Swpaul case DATA_TYPE_INT64: 70138363Swpaul (void) nvpair_value_int64(nvp, (int64_t *)&i64); 70238363Swpaul _zed_event_add_var(eid, zsp, prefix, name, 70338363Swpaul "%lld", (longlong_t)i64); 70438363Swpaul break; 70538363Swpaul case DATA_TYPE_UINT64: 70638363Swpaul (void) nvpair_value_uint64(nvp, &i64); 70738363Swpaul _zed_event_add_var(eid, zsp, prefix, name, 70838363Swpaul (_zed_event_value_is_hex(name) ? "0x%.16llX" : "%llu"), 70938363Swpaul (u_longlong_t)i64); 71038363Swpaul /* 71138363Swpaul * shadow readable strings for vdev state pairs 71238363Swpaul */ 71338363Swpaul if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE) == 0 || 71438363Swpaul strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE) == 0) { 71538363Swpaul char alt[32]; 71638363Swpaul 71738363Swpaul (void) snprintf(alt, sizeof (alt), "%s_str", name); 71838363Swpaul _zed_event_add_var(eid, zsp, prefix, alt, "%s", 71938363Swpaul zpool_state_to_name(i64, VDEV_AUX_NONE)); 72038363Swpaul } else 72138363Swpaul /* 72238363Swpaul * shadow readable strings for pool state 72338363Swpaul */ 72438363Swpaul if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_POOL_STATE) == 0) { 72538363Swpaul char alt[32]; 72638363Swpaul 72738363Swpaul (void) snprintf(alt, sizeof (alt), "%s_str", name); 72838363Swpaul _zed_event_add_var(eid, zsp, prefix, alt, "%s", 72938363Swpaul zpool_pool_state_to_name(i64)); 73038363Swpaul } 73138363Swpaul break; 73238363Swpaul case DATA_TYPE_DOUBLE: 73338363Swpaul (void) nvpair_value_double(nvp, &d); 73438363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "%g", d); 73538363Swpaul break; 73638363Swpaul case DATA_TYPE_HRTIME: 73738363Swpaul (void) nvpair_value_hrtime(nvp, (hrtime_t *)&i64); 73838363Swpaul _zed_event_add_var(eid, zsp, prefix, name, 73938363Swpaul "%llu", (u_longlong_t)i64); 74038363Swpaul break; 74138363Swpaul case DATA_TYPE_STRING: 74238363Swpaul (void) nvpair_value_string(nvp, &str); 74338363Swpaul _zed_event_add_var(eid, zsp, prefix, name, 74438363Swpaul "%s", (str ? str : "<NULL>")); 74538363Swpaul break; 74638363Swpaul case DATA_TYPE_INT8_ARRAY: 74738363Swpaul _zed_event_add_int8_array(eid, zsp, prefix, nvp); 74838363Swpaul break; 74938363Swpaul case DATA_TYPE_UINT8_ARRAY: 75038363Swpaul _zed_event_add_uint8_array(eid, zsp, prefix, nvp); 75138363Swpaul break; 75238363Swpaul case DATA_TYPE_INT16_ARRAY: 75338363Swpaul _zed_event_add_int16_array(eid, zsp, prefix, nvp); 75438363Swpaul break; 75538363Swpaul case DATA_TYPE_UINT16_ARRAY: 75638363Swpaul _zed_event_add_uint16_array(eid, zsp, prefix, nvp); 75738363Swpaul break; 75838363Swpaul case DATA_TYPE_INT32_ARRAY: 75938363Swpaul _zed_event_add_int32_array(eid, zsp, prefix, nvp); 76038363Swpaul break; 76138363Swpaul case DATA_TYPE_UINT32_ARRAY: 76238363Swpaul _zed_event_add_uint32_array(eid, zsp, prefix, nvp); 76338363Swpaul break; 76438363Swpaul case DATA_TYPE_INT64_ARRAY: 76538363Swpaul _zed_event_add_int64_array(eid, zsp, prefix, nvp); 76638363Swpaul break; 76738363Swpaul case DATA_TYPE_UINT64_ARRAY: 76838363Swpaul _zed_event_add_uint64_array(eid, zsp, prefix, nvp); 76938363Swpaul break; 77038363Swpaul case DATA_TYPE_STRING_ARRAY: 77138363Swpaul _zed_event_add_string_array(eid, zsp, prefix, nvp); 77238363Swpaul break; 77338363Swpaul case DATA_TYPE_NVLIST: 77438363Swpaul case DATA_TYPE_BOOLEAN_ARRAY: 77538363Swpaul case DATA_TYPE_BYTE_ARRAY: 77638363Swpaul case DATA_TYPE_NVLIST_ARRAY: 77738363Swpaul _zed_event_add_var(eid, zsp, prefix, name, "_NOT_IMPLEMENTED_"); 77838363Swpaul break; 77938363Swpaul default: 78038363Swpaul errno = EINVAL; 78138363Swpaul zed_log_msg(LOG_WARNING, 78238363Swpaul "Failed to convert nvpair \"%s\" for eid=%llu: " 78338363Swpaul "Unrecognized type=%u", name, eid, (unsigned int) type); 78438363Swpaul break; 78538363Swpaul } 78638363Swpaul} 78738363Swpaul 78838363Swpaul/* 78938363Swpaul * Restrict various environment variables to safe and sane values 79038363Swpaul * when constructing the environment for the child process, unless 79138363Swpaul * we're running with a custom $PATH (like under the ZFS test suite). 79238363Swpaul * 79338363Swpaul * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1. 79438363Swpaul */ 79538363Swpaulstatic void 79638363Swpaul_zed_event_add_env_restrict(uint64_t eid, zed_strings_t *zsp, 79738363Swpaul const char *path) 79838363Swpaul{ 79938363Swpaul const char *env_restrict[][2] = { 80038363Swpaul { "IFS", " \t\n" }, 80138363Swpaul { "PATH", _PATH_STDPATH }, 80238363Swpaul { "ZDB", SBINDIR "/zdb" }, 80338363Swpaul { "ZED", SBINDIR "/zed" }, 80438363Swpaul { "ZFS", SBINDIR "/zfs" }, 80538363Swpaul { "ZINJECT", SBINDIR "/zinject" }, 80638363Swpaul { "ZPOOL", SBINDIR "/zpool" }, 80738363Swpaul { "ZFS_ALIAS", ZFS_META_ALIAS }, 80838363Swpaul { "ZFS_VERSION", ZFS_META_VERSION }, 80938363Swpaul { "ZFS_RELEASE", ZFS_META_RELEASE }, 81038363Swpaul { NULL, NULL } 81138363Swpaul }; 81245062Swpaul 81345062Swpaul /* 81445062Swpaul * If we have a custom $PATH, use the default ZFS binary locations 81545062Swpaul * instead of the hard-coded ones. 81645062Swpaul */ 81745062Swpaul const char *env_path[][2] = { 81846204Swpaul { "IFS", " \t\n" }, 81946204Swpaul { "PATH", NULL }, /* $PATH copied in later on */ 82046204Swpaul { "ZDB", "zdb" }, 82146204Swpaul { "ZED", "zed" }, 822 { "ZFS", "zfs" }, 823 { "ZINJECT", "zinject" }, 824 { "ZPOOL", "zpool" }, 825 { "ZFS_ALIAS", ZFS_META_ALIAS }, 826 { "ZFS_VERSION", ZFS_META_VERSION }, 827 { "ZFS_RELEASE", ZFS_META_RELEASE }, 828 { NULL, NULL } 829 }; 830 const char *(*pa)[2]; 831 832 assert(zsp != NULL); 833 834 pa = path != NULL ? env_path : env_restrict; 835 836 for (; *(*pa); pa++) { 837 /* Use our custom $PATH if we have one */ 838 if (path != NULL && strcmp((*pa)[0], "PATH") == 0) 839 (*pa)[1] = path; 840 841 _zed_event_add_var(eid, zsp, NULL, (*pa)[0], "%s", (*pa)[1]); 842 } 843} 844 845/* 846 * Preserve specified variables from the parent environment 847 * when constructing the environment for the child process. 848 * 849 * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1. 850 */ 851static void 852_zed_event_add_env_preserve(uint64_t eid, zed_strings_t *zsp) 853{ 854 const char *env_preserve[] = { 855 "TZ", 856 NULL 857 }; 858 const char **keyp; 859 const char *val; 860 861 assert(zsp != NULL); 862 863 for (keyp = env_preserve; *keyp; keyp++) { 864 if ((val = getenv(*keyp))) 865 _zed_event_add_var(eid, zsp, NULL, *keyp, "%s", val); 866 } 867} 868 869/* 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. 873 */ 874static const char * 875_zed_event_get_subclass(const char *class) 876{ 877 const char *p; 878 int i; 879 880 if (!class) 881 return (NULL); 882 883 p = class; 884 for (i = 0; i < 3; i++) { 885 p = strchr(p, '.'); 886 if (!p) 887 break; 888 p++; 889 } 890 return (p); 891} 892 893/* 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. 899 */ 900static void 901_zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[]) 902{ 903 struct tm stp; 904 char buf[32]; 905 906 assert(zsp != NULL); 907 assert(etime != NULL); 908 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]); 913 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"); 920 } else { 921 _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_STRING", 922 "%s", buf); 923 } 924} 925 926 927static void 928_zed_event_update_enc_sysfs_path(nvlist_t *nvl) 929{ 930 const char *vdev_path; 931 932 if (nvlist_lookup_string(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_PATH, 933 &vdev_path) != 0) { 934 return; /* some other kind of event, ignore it */ 935 } 936 937 if (vdev_path == NULL) { 938 return; 939 } 940 941 update_vdev_config_dev_sysfs_path(nvl, vdev_path, 942 FM_EREPORT_PAYLOAD_ZFS_VDEV_ENC_SYSFS_PATH); 943} 944 945/* 946 * Service the next zevent, blocking until one is available. 947 */ 948int 949zed_event_service(struct zed_conf *zcp) 950{ 951 nvlist_t *nvl; 952 nvpair_t *nvp; 953 int n_dropped; 954 zed_strings_t *zsp; 955 uint64_t eid; 956 int64_t *etime; 957 uint_t nelem; 958 const char *class; 959 const char *subclass; 960 int rv; 961 962 if (!zcp) { 963 errno = EINVAL; 964 zed_log_msg(LOG_ERR, "Failed to service zevent: %s", 965 strerror(errno)); 966 return (EINVAL); 967 } 968 rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped, ZEVENT_NONE, 969 zcp->zevent_fd); 970 971 if ((rv != 0) || !nvl) 972 return (errno); 973 974 if (n_dropped > 0) { 975 zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped); 976 _bump_event_queue_length(); 977 } 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)", 987 eid, nelem); 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); 991 } else { 992 /* 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. 1000 */ 1001 _zed_event_update_enc_sysfs_path(nvl); 1002 1003 /* let internal modules see this event first */ 1004 zfs_agent_post_event(class, NULL, nvl); 1005 1006 zsp = zed_strings_create(); 1007 1008 nvp = NULL; 1009 while ((nvp = nvlist_next_nvpair(nvl, nvp))) 1010 _zed_event_add_nvpair(eid, zsp, nvp); 1011 1012 _zed_event_add_env_restrict(eid, zsp, zcp->path); 1013 _zed_event_add_env_preserve(eid, zsp); 1014 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)); 1022 1023 _zed_event_add_time_strings(eid, zsp, etime); 1024 1025 zed_exec_process(eid, class, subclass, zcp, zsp); 1026 1027 zed_conf_write_state(zcp, eid, etime); 1028 1029 zed_strings_destroy(zsp); 1030 } 1031 nvlist_free(nvl); 1032 return (0); 1033} 1034