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