The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/cmd/zed/zed_event.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: c31e94033f23ab1c88af9ab51eee9c86


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.