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