]> granicus.if.org Git - zfs/blob - cmd/zed/zed_event.c
Initial implementation of zed (ZFS Event Daemon)
[zfs] / cmd / zed / zed_event.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license from the top-level
9  * OPENSOLARIS.LICENSE or <http://opensource.org/licenses/CDDL-1.0>.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each file
14  * and include the License file from the top-level OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21
22 /*
23  * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
24  * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
25  */
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <libzfs.h>                     /* FIXME: Replace with libzfs_core. */
31 #include <paths.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/zfs_ioctl.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include "zed.h"
40 #include "zed_conf.h"
41 #include "zed_exec.h"
42 #include "zed_file.h"
43 #include "zed_log.h"
44 #include "zed_strings.h"
45
46 /*
47  * Open the libzfs interface.
48  */
49 void
50 zed_event_init(struct zed_conf *zcp)
51 {
52         if (!zcp)
53                 zed_log_die("Failed zed_event_init: %s", strerror(EINVAL));
54
55         zcp->zfs_hdl = libzfs_init();
56         if (!zcp->zfs_hdl)
57                 zed_log_die("Failed to initialize libzfs");
58
59         zcp->zevent_fd = open(ZFS_DEV, O_RDWR);
60         if (zcp->zevent_fd < 0)
61                 zed_log_die("Failed to open \"%s\": %s",
62                     ZFS_DEV, strerror(errno));
63 }
64
65 /*
66  * Close the libzfs interface.
67  */
68 void
69 zed_event_fini(struct zed_conf *zcp)
70 {
71         if (!zcp)
72                 zed_log_die("Failed zed_event_fini: %s", strerror(EINVAL));
73
74         if (zcp->zevent_fd >= 0) {
75                 if (close(zcp->zevent_fd) < 0)
76                         zed_log_msg(LOG_WARNING, "Failed to close \"%s\": %s",
77                             ZFS_DEV, strerror(errno));
78
79                 zcp->zevent_fd = -1;
80         }
81         if (zcp->zfs_hdl) {
82                 libzfs_fini(zcp->zfs_hdl);
83                 zcp->zfs_hdl = NULL;
84         }
85 }
86
87 /*
88  * Seek to the event specified by [saved_eid] and [saved_etime].
89  *   This protects against processing a given event more than once.
90  * Return 0 upon a successful seek to the specified event, or -1 otherwise.
91  * A zevent is considered to be uniquely specified by its (eid,time) tuple.
92  *   The unsigned 64b eid is set to 1 when the kernel module is loaded, and
93  *   incremented by 1 for each new event.  Since the state file can persist
94  *   across a kernel module reload, the time must be checked to ensure a match.
95  */
96 int
97 zed_event_seek(struct zed_conf *zcp, uint64_t saved_eid, int64_t saved_etime[])
98 {
99         uint64_t eid;
100         int found;
101         nvlist_t *nvl;
102         int n_dropped;
103         int64_t *etime;
104         uint_t nelem;
105         int rv;
106
107         if (!zcp) {
108                 errno = EINVAL;
109                 zed_log_msg(LOG_ERR, "Failed to seek zevent: %s",
110                     strerror(errno));
111                 return (-1);
112         }
113         eid = 0;
114         found = 0;
115         while ((eid < saved_eid) && !found) {
116                 rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped,
117                     ZEVENT_NONBLOCK, zcp->zevent_fd);
118
119                 if ((rv != 0) || !nvl)
120                         break;
121
122                 if (n_dropped > 0) {
123                         zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
124                         /*
125                          * FIXME: Increase max size of event nvlist in
126                          *   /sys/module/zfs/parameters/zfs_zevent_len_max ?
127                          */
128                 }
129                 if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
130                         zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
131                 } else if (nvlist_lookup_int64_array(nvl, "time",
132                     &etime, &nelem) != 0) {
133                         zed_log_msg(LOG_WARNING,
134                             "Failed to lookup zevent time (eid=%llu)", eid);
135                 } else if (nelem != 2) {
136                         zed_log_msg(LOG_WARNING,
137                             "Failed to lookup zevent time (eid=%llu, nelem=%u)",
138                             eid, nelem);
139                 } else if ((eid != saved_eid) ||
140                     (etime[0] != saved_etime[0]) ||
141                     (etime[1] != saved_etime[1])) {
142                         /* no-op */
143                 } else {
144                         found = 1;
145                 }
146                 free(nvl);
147         }
148         if (!found && (saved_eid > 0)) {
149                 if (zpool_events_seek(zcp->zfs_hdl, ZEVENT_SEEK_START,
150                     zcp->zevent_fd) < 0)
151                         zed_log_msg(LOG_WARNING, "Failed to seek to eid=0");
152                 else
153                         eid = 0;
154         }
155         zed_log_msg(LOG_NOTICE, "Processing events since eid=%llu", eid);
156         return (found ? 0 : -1);
157 }
158
159 static int
160 _zed_event_convert_int8_array(char *buf, int buflen, nvpair_t *nvp)
161 {
162         int8_t *i8p;
163         uint_t nelem;
164         uint_t i;
165         char *p;
166         int n;
167
168         assert(buf != NULL);
169
170         (void) nvpair_value_int8_array(nvp, &i8p, &nelem);
171         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
172                 n = snprintf(p, buflen, "%d ", i8p[i]);
173                 if ((n < 0) || (n >= buflen)) {
174                         *buf = '\0';
175                         return (-1);
176                 }
177                 p += n;
178                 buflen -= n;
179         }
180         if (nelem > 0)
181                 *--p = '\0';
182
183         return (p - buf);
184 }
185
186 static int
187 _zed_event_convert_uint8_array(char *buf, int buflen, nvpair_t *nvp)
188 {
189         uint8_t *u8p;
190         uint_t nelem;
191         uint_t i;
192         char *p;
193         int n;
194
195         assert(buf != NULL);
196
197         (void) nvpair_value_uint8_array(nvp, &u8p, &nelem);
198         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
199                 n = snprintf(p, buflen, "%u ", u8p[i]);
200                 if ((n < 0) || (n >= buflen)) {
201                         *buf = '\0';
202                         return (-1);
203                 }
204                 p += n;
205                 buflen -= n;
206         }
207         if (nelem > 0)
208                 *--p = '\0';
209
210         return (p - buf);
211 }
212
213 static int
214 _zed_event_convert_int16_array(char *buf, int buflen, nvpair_t *nvp)
215 {
216         int16_t *i16p;
217         uint_t nelem;
218         uint_t i;
219         char *p;
220         int n;
221
222         assert(buf != NULL);
223
224         (void) nvpair_value_int16_array(nvp, &i16p, &nelem);
225         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
226                 n = snprintf(p, buflen, "%d ", i16p[i]);
227                 if ((n < 0) || (n >= buflen)) {
228                         *buf = '\0';
229                         return (-1);
230                 }
231                 p += n;
232                 buflen -= n;
233         }
234         if (nelem > 0)
235                 *--p = '\0';
236
237         return (p - buf);
238 }
239
240 static int
241 _zed_event_convert_uint16_array(char *buf, int buflen, nvpair_t *nvp)
242 {
243         uint16_t *u16p;
244         uint_t nelem;
245         uint_t i;
246         char *p;
247         int n;
248
249         assert(buf != NULL);
250
251         (void) nvpair_value_uint16_array(nvp, &u16p, &nelem);
252         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
253                 n = snprintf(p, buflen, "%u ", u16p[i]);
254                 if ((n < 0) || (n >= buflen)) {
255                         *buf = '\0';
256                         return (-1);
257                 }
258                 p += n;
259                 buflen -= n;
260         }
261         if (nelem > 0)
262                 *--p = '\0';
263
264         return (p - buf);
265 }
266
267 static int
268 _zed_event_convert_int32_array(char *buf, int buflen, nvpair_t *nvp)
269 {
270         int32_t *i32p;
271         uint_t nelem;
272         uint_t i;
273         char *p;
274         int n;
275
276         assert(buf != NULL);
277
278         (void) nvpair_value_int32_array(nvp, &i32p, &nelem);
279         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
280                 n = snprintf(p, buflen, "%d ", i32p[i]);
281                 if ((n < 0) || (n >= buflen)) {
282                         *buf = '\0';
283                         return (-1);
284                 }
285                 p += n;
286                 buflen -= n;
287         }
288         if (nelem > 0)
289                 *--p = '\0';
290
291         return (p - buf);
292 }
293
294 static int
295 _zed_event_convert_uint32_array(char *buf, int buflen, nvpair_t *nvp)
296 {
297         uint32_t *u32p;
298         uint_t nelem;
299         uint_t i;
300         char *p;
301         int n;
302
303         assert(buf != NULL);
304
305         (void) nvpair_value_uint32_array(nvp, &u32p, &nelem);
306         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
307                 n = snprintf(p, buflen, "%u ", u32p[i]);
308                 if ((n < 0) || (n >= buflen)) {
309                         *buf = '\0';
310                         return (-1);
311                 }
312                 p += n;
313                 buflen -= n;
314         }
315         if (nelem > 0)
316                 *--p = '\0';
317
318         return (p - buf);
319 }
320
321 static int
322 _zed_event_convert_int64_array(char *buf, int buflen, nvpair_t *nvp)
323 {
324         int64_t *i64p;
325         uint_t nelem;
326         uint_t i;
327         char *p;
328         int n;
329
330         assert(buf != NULL);
331
332         (void) nvpair_value_int64_array(nvp, &i64p, &nelem);
333         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
334                 n = snprintf(p, buflen, "%lld ", (u_longlong_t) i64p[i]);
335                 if ((n < 0) || (n >= buflen)) {
336                         *buf = '\0';
337                         return (-1);
338                 }
339                 p += n;
340                 buflen -= n;
341         }
342         if (nelem > 0)
343                 *--p = '\0';
344
345         return (p - buf);
346 }
347
348 static int
349 _zed_event_convert_uint64_array(char *buf, int buflen, nvpair_t *nvp,
350     const char *fmt)
351 {
352         uint64_t *u64p;
353         uint_t nelem;
354         uint_t i;
355         char *p;
356         int n;
357
358         assert(buf != NULL);
359
360         (void) nvpair_value_uint64_array(nvp, &u64p, &nelem);
361         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
362                 n = snprintf(p, buflen, fmt, (u_longlong_t) u64p[i]);
363                 if ((n < 0) || (n >= buflen)) {
364                         *buf = '\0';
365                         return (-1);
366                 }
367                 p += n;
368                 buflen -= n;
369         }
370         if (nelem > 0)
371                 *--p = '\0';
372
373         return (p - buf);
374 }
375
376 static int
377 _zed_event_convert_string_array(char *buf, int buflen, nvpair_t *nvp)
378 {
379         char **strp;
380         uint_t nelem;
381         uint_t i;
382         char *p;
383         int n;
384
385         assert(buf != NULL);
386
387         (void) nvpair_value_string_array(nvp, &strp, &nelem);
388         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
389                 n = snprintf(p, buflen, "%s ", strp[i] ? strp[i] : "<NULL>");
390                 if ((n < 0) || (n >= buflen)) {
391                         *buf = '\0';
392                         return (-1);
393                 }
394                 p += n;
395                 buflen -= n;
396         }
397         if (nelem > 0)
398                 *--p = '\0';
399
400         return (p - buf);
401 }
402
403 /*
404  * Return non-zero if nvpair [name] should be formatted in hex; o/w, return 0.
405  */
406 static int
407 _zed_event_value_is_hex(const char *name)
408 {
409         const char *hex_suffix[] = {
410                 "_guid",
411                 "_guids",
412                 NULL
413         };
414         const char **pp;
415         char *p;
416
417         if (!name)
418                 return (0);
419
420         for (pp = hex_suffix; *pp; pp++) {
421                 p = strstr(name, *pp);
422                 if (p && strlen(p) == strlen(*pp))
423                         return (1);
424         }
425         return (0);
426 }
427
428 /*
429  * Convert the nvpair [nvp] to a string which is added to the environment
430  *   of the child process.
431  * Return 0 on success, -1 on error.
432  * FIXME: Refactor with cmd/zpool/zpool_main.c:zpool_do_events_nvprint()?
433  */
434 static void
435 _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
436 {
437         const char *name;
438         data_type_t type;
439         char buf[4096];
440         int buflen;
441         int n;
442         char *p;
443         const char *q;
444         const char *fmt;
445
446         boolean_t b;
447         double d;
448         uint8_t i8;
449         uint16_t i16;
450         uint32_t i32;
451         uint64_t i64;
452         char *str;
453
454         assert(zsp != NULL);
455         assert(nvp != NULL);
456
457         name = nvpair_name(nvp);
458         type = nvpair_type(nvp);
459         buflen = sizeof (buf);
460
461         /* Copy NAME prefix for ZED zevent namespace. */
462         n = strlcpy(buf, ZEVENT_VAR_PREFIX, sizeof (buf));
463         if (n >= sizeof (buf)) {
464                 zed_log_msg(LOG_WARNING,
465                     "Failed to convert nvpair \"%s\" for eid=%llu: %s",
466                     name, eid, "Exceeded buffer size");
467                 return;
468         }
469         buflen -= n;
470         p = buf + n;
471
472         /* Convert NAME to alphanumeric uppercase. */
473         for (q = name; *q && (buflen > 0); q++) {
474                 *p++ = isalnum(*q) ? toupper(*q) : '_';
475                 buflen--;
476         }
477
478         /* Separate NAME from VALUE. */
479         if (buflen > 0) {
480                 *p++ = '=';
481                 buflen--;
482         }
483         *p = '\0';
484
485         /* Convert VALUE. */
486         switch (type) {
487         case DATA_TYPE_BOOLEAN:
488                 n = snprintf(p, buflen, "%s", "1");
489                 break;
490         case DATA_TYPE_BOOLEAN_VALUE:
491                 (void) nvpair_value_boolean_value(nvp, &b);
492                 n = snprintf(p, buflen, "%s", b ? "1" : "0");
493                 break;
494         case DATA_TYPE_BYTE:
495                 (void) nvpair_value_byte(nvp, &i8);
496                 n = snprintf(p, buflen, "%d", i8);
497                 break;
498         case DATA_TYPE_INT8:
499                 (void) nvpair_value_int8(nvp, (int8_t *) &i8);
500                 n = snprintf(p, buflen, "%d", i8);
501                 break;
502         case DATA_TYPE_UINT8:
503                 (void) nvpair_value_uint8(nvp, &i8);
504                 n = snprintf(p, buflen, "%u", i8);
505                 break;
506         case DATA_TYPE_INT16:
507                 (void) nvpair_value_int16(nvp, (int16_t *) &i16);
508                 n = snprintf(p, buflen, "%d", i16);
509                 break;
510         case DATA_TYPE_UINT16:
511                 (void) nvpair_value_uint16(nvp, &i16);
512                 n = snprintf(p, buflen, "%u", i16);
513                 break;
514         case DATA_TYPE_INT32:
515                 (void) nvpair_value_int32(nvp, (int32_t *) &i32);
516                 n = snprintf(p, buflen, "%d", i32);
517                 break;
518         case DATA_TYPE_UINT32:
519                 (void) nvpair_value_uint32(nvp, &i32);
520                 n = snprintf(p, buflen, "%u", i32);
521                 break;
522         case DATA_TYPE_INT64:
523                 (void) nvpair_value_int64(nvp, (int64_t *) &i64);
524                 n = snprintf(p, buflen, "%lld", (longlong_t) i64);
525                 break;
526         case DATA_TYPE_UINT64:
527                 (void) nvpair_value_uint64(nvp, &i64);
528                 fmt = _zed_event_value_is_hex(name) ? "0x%.16llX" : "%llu";
529                 n = snprintf(p, buflen, fmt, (u_longlong_t) i64);
530                 break;
531         case DATA_TYPE_DOUBLE:
532                 (void) nvpair_value_double(nvp, &d);
533                 n = snprintf(p, buflen, "%g", d);
534                 break;
535         case DATA_TYPE_HRTIME:
536                 (void) nvpair_value_hrtime(nvp, (hrtime_t *) &i64);
537                 n = snprintf(p, buflen, "%llu", (u_longlong_t) i64);
538                 break;
539         case DATA_TYPE_NVLIST:
540                 /* FIXME */
541                 n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
542                 break;
543         case DATA_TYPE_STRING:
544                 (void) nvpair_value_string(nvp, &str);
545                 n = snprintf(p, buflen, "%s", (str ? str : "<NULL>"));
546                 break;
547         case DATA_TYPE_BOOLEAN_ARRAY:
548                 /* FIXME */
549                 n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
550                 break;
551         case DATA_TYPE_BYTE_ARRAY:
552                 /* FIXME */
553                 n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
554                 break;
555         case DATA_TYPE_INT8_ARRAY:
556                 n = _zed_event_convert_int8_array(p, buflen, nvp);
557                 break;
558         case DATA_TYPE_UINT8_ARRAY:
559                 n = _zed_event_convert_uint8_array(p, buflen, nvp);
560                 break;
561         case DATA_TYPE_INT16_ARRAY:
562                 n = _zed_event_convert_int16_array(p, buflen, nvp);
563                 break;
564         case DATA_TYPE_UINT16_ARRAY:
565                 n = _zed_event_convert_uint16_array(p, buflen, nvp);
566                 break;
567         case DATA_TYPE_INT32_ARRAY:
568                 n = _zed_event_convert_int32_array(p, buflen, nvp);
569                 break;
570         case DATA_TYPE_UINT32_ARRAY:
571                 n = _zed_event_convert_uint32_array(p, buflen, nvp);
572                 break;
573         case DATA_TYPE_INT64_ARRAY:
574                 n = _zed_event_convert_int64_array(p, buflen, nvp);
575                 break;
576         case DATA_TYPE_UINT64_ARRAY:
577                 fmt = _zed_event_value_is_hex(name) ? "0x%.16llX " : "%llu ";
578                 n = _zed_event_convert_uint64_array(p, buflen, nvp, fmt);
579                 break;
580         case DATA_TYPE_STRING_ARRAY:
581                 n = _zed_event_convert_string_array(p, buflen, nvp);
582                 break;
583         case DATA_TYPE_NVLIST_ARRAY:
584                 /* FIXME */
585                 n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
586                 break;
587         default:
588                 zed_log_msg(LOG_WARNING,
589                     "Failed to convert nvpair \"%s\" for eid=%llu: "
590                     "Unrecognized type=%u", name, eid, (unsigned int) type);
591                 return;
592         }
593         if ((n < 0) || (n >= sizeof (buf))) {
594                 zed_log_msg(LOG_WARNING,
595                     "Failed to convert nvpair \"%s\" for eid=%llu: %s",
596                     name, eid, "Exceeded buffer size");
597                 return;
598         }
599         if (zed_strings_add(zsp, buf) < 0) {
600                 zed_log_msg(LOG_WARNING,
601                     "Failed to convert nvpair \"%s\" for eid=%llu: %s",
602                     name, eid, strerror(ENOMEM));
603                 return;
604         }
605 }
606
607 /*
608  * Add the environment variable specified by the format string [fmt].
609  */
610 static void
611 _zed_event_add_var(uint64_t eid, zed_strings_t *zsp, const char *fmt, ...)
612 {
613         char buf[4096];
614         va_list vargs;
615         int n;
616         const char *p;
617         size_t namelen;
618
619         assert(zsp != NULL);
620         assert(fmt != NULL);
621
622         va_start(vargs, fmt);
623         n = vsnprintf(buf, sizeof (buf), fmt, vargs);
624         va_end(vargs);
625         p = strchr(buf, '=');
626         namelen = (p) ? p - buf : strlen(buf);
627
628         if ((n < 0) || (n >= sizeof (buf))) {
629                 zed_log_msg(LOG_WARNING, "Failed to add %.*s for eid=%llu: %s",
630                     namelen, buf, eid, "Exceeded buffer size");
631         } else if (!p) {
632                 zed_log_msg(LOG_WARNING, "Failed to add %.*s for eid=%llu: %s",
633                     namelen, buf, eid, "Missing assignment");
634         } else if (zed_strings_add(zsp, buf) < 0) {
635                 zed_log_msg(LOG_WARNING, "Failed to add %.*s for eid=%llu: %s",
636                     namelen, buf, eid, strerror(ENOMEM));
637         }
638 }
639
640 /*
641  * Restrict various environment variables to safe and sane values
642  *   when constructing the environment for the child process.
643  * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
644  */
645 static void
646 _zed_event_add_env_restrict(uint64_t eid, zed_strings_t *zsp)
647 {
648         const char *env_restrict[] = {
649                 "IFS= \t\n",
650                 "PATH=" _PATH_STDPATH,
651                 "ZDB=" SBINDIR "/zdb",
652                 "ZED=" SBINDIR "/zed",
653                 "ZFS=" SBINDIR "/zfs",
654                 "ZINJECT=" SBINDIR "/zinject",
655                 "ZPOOL=" SBINDIR "/zpool",
656                 "ZFS_ALIAS=" ZFS_META_ALIAS,
657                 "ZFS_VERSION=" ZFS_META_VERSION,
658                 "ZFS_RELEASE=" ZFS_META_RELEASE,
659                 NULL
660         };
661         const char **pp;
662
663         assert(zsp != NULL);
664
665         for (pp = env_restrict; *pp; pp++) {
666                 _zed_event_add_var(eid, zsp, "%s", *pp);
667         }
668 }
669
670 /*
671  * Preserve specified variables from the parent environment
672  *   when constructing the environment for the child process.
673  * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
674  */
675 static void
676 _zed_event_add_env_preserve(uint64_t eid, zed_strings_t *zsp)
677 {
678         const char *env_preserve[] = {
679                 "TZ",
680                 NULL
681         };
682         const char **pp;
683         const char *p;
684
685         assert(zsp != NULL);
686
687         for (pp = env_preserve; *pp; pp++) {
688                 if ((p = getenv(*pp)))
689                         _zed_event_add_var(eid, zsp, "%s=%s", *pp, p);
690         }
691 }
692
693 /*
694  * Compute the "subclass" by removing the first 3 components of [class]
695  *   (which seem to always be either "ereport.fs.zfs" or "resource.fs.zfs").
696  * Return a pointer inside the string [class], or NULL if insufficient
697  *   components exist.
698  */
699 static const char *
700 _zed_event_get_subclass(const char *class)
701 {
702         const char *p;
703         int i;
704
705         if (!class)
706                 return (NULL);
707
708         p = class;
709         for (i = 0; i < 3; i++) {
710                 p = strchr(p, '.');
711                 if (!p)
712                         break;
713                 p++;
714         }
715         return (p);
716 }
717
718 /*
719  * Convert the zevent time from a 2-element array of 64b integers
720  *   into a more convenient form:
721  * TIME_SECS is the second component of the time.
722  * TIME_NSECS is the nanosecond component of the time.
723  * TIME_STRING is an almost-RFC3339-compliant string representation.
724  */
725 static void
726 _zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[])
727 {
728         struct tm *stp;
729         char buf[32];
730
731         assert(zsp != NULL);
732         assert(etime != NULL);
733
734         _zed_event_add_var(eid, zsp, "%s%s=%lld",
735             ZEVENT_VAR_PREFIX, "TIME_SECS", (long long int) etime[0]);
736         _zed_event_add_var(eid, zsp, "%s%s=%lld",
737             ZEVENT_VAR_PREFIX, "TIME_NSECS", (long long int) etime[1]);
738
739         if (!(stp = localtime((const time_t *) &etime[0]))) {
740                 zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
741                     ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "localtime error");
742         } else if (!strftime(buf, sizeof (buf), "%Y-%m-%d %H:%M:%S%z", stp)) {
743                 zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
744                     ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "strftime error");
745         } else {
746                 _zed_event_add_var(eid, zsp, "%s%s=%s",
747                     ZEVENT_VAR_PREFIX, "TIME_STRING", buf);
748         }
749 }
750
751 /*
752  * Service the next zevent, blocking until one is available.
753  */
754 void
755 zed_event_service(struct zed_conf *zcp)
756 {
757         nvlist_t *nvl;
758         nvpair_t *nvp;
759         int n_dropped;
760         zed_strings_t *zsp;
761         uint64_t eid;
762         int64_t *etime;
763         uint_t nelem;
764         char *class;
765         const char *subclass;
766         int rv;
767
768         if (!zcp) {
769                 errno = EINVAL;
770                 zed_log_msg(LOG_ERR, "Failed to service zevent: %s",
771                     strerror(errno));
772                 return;
773         }
774         rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped, ZEVENT_NONE,
775             zcp->zevent_fd);
776
777         if ((rv != 0) || !nvl)
778                 return;
779
780         if (n_dropped > 0) {
781                 zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
782                 /*
783                  * FIXME: Increase max size of event nvlist in
784                  *   /sys/module/zfs/parameters/zfs_zevent_len_max ?
785                  */
786         }
787         if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
788                 zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
789         } else if (nvlist_lookup_int64_array(
790             nvl, "time", &etime, &nelem) != 0) {
791                 zed_log_msg(LOG_WARNING,
792                     "Failed to lookup zevent time (eid=%llu)", eid);
793         } else if (nelem != 2) {
794                 zed_log_msg(LOG_WARNING,
795                     "Failed to lookup zevent time (eid=%llu, nelem=%u)",
796                     eid, nelem);
797         } else if (nvlist_lookup_string(nvl, "class", &class) != 0) {
798                 zed_log_msg(LOG_WARNING,
799                     "Failed to lookup zevent class (eid=%llu)", eid);
800         } else {
801                 zsp = zed_strings_create();
802
803                 nvp = NULL;
804                 while ((nvp = nvlist_next_nvpair(nvl, nvp)))
805                         _zed_event_add_nvpair(eid, zsp, nvp);
806
807                 _zed_event_add_env_restrict(eid, zsp);
808                 _zed_event_add_env_preserve(eid, zsp);
809
810                 _zed_event_add_var(eid, zsp, "%s%s=%d",
811                     ZED_VAR_PREFIX, "PID", (int) getpid());
812                 _zed_event_add_var(eid, zsp, "%s%s=%s",
813                     ZED_VAR_PREFIX, "SCRIPT_DIR", zcp->script_dir);
814
815                 subclass = _zed_event_get_subclass(class);
816                 _zed_event_add_var(eid, zsp, "%s%s=%s",
817                     ZEVENT_VAR_PREFIX, "SUBCLASS",
818                     (subclass ? subclass : class));
819                 _zed_event_add_time_strings(eid, zsp, etime);
820
821                 zed_exec_process(eid, class, subclass,
822                     zcp->script_dir, zcp->scripts, zsp, zcp->zevent_fd);
823
824                 zed_conf_write_state(zcp, eid, etime);
825
826                 zed_strings_destroy(zsp);
827         }
828         nvlist_free(nvl);
829 }