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