]> granicus.if.org Git - zfs/blob - cmd/zed/zed_event.c
Fix coverity defects: CID 147587
[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 <sys/fm/fs/zfs.h>
28 #include "zed.h"
29 #include "zed_conf.h"
30 #include "zed_disk_event.h"
31 #include "zed_exec.h"
32 #include "zed_file.h"
33 #include "zed_log.h"
34 #include "zed_strings.h"
35
36 #include "agents/zfs_agents.h"
37
38 #define MAXBUF  4096
39
40 /*
41  * Open the libzfs interface.
42  */
43 void
44 zed_event_init(struct zed_conf *zcp)
45 {
46         if (!zcp)
47                 zed_log_die("Failed zed_event_init: %s", strerror(EINVAL));
48
49         zcp->zfs_hdl = libzfs_init();
50         if (!zcp->zfs_hdl)
51                 zed_log_die("Failed to initialize libzfs");
52
53         zcp->zevent_fd = open(ZFS_DEV, O_RDWR);
54         if (zcp->zevent_fd < 0)
55                 zed_log_die("Failed to open \"%s\": %s",
56                     ZFS_DEV, strerror(errno));
57
58         zfs_agent_init(zcp->zfs_hdl);
59
60         if (zed_disk_event_init() != 0)
61                 zed_log_die("Failed to initialize disk events");
62 }
63
64 /*
65  * Close the libzfs interface.
66  */
67 void
68 zed_event_fini(struct zed_conf *zcp)
69 {
70         if (!zcp)
71                 zed_log_die("Failed zed_event_fini: %s", strerror(EINVAL));
72
73         zed_disk_event_fini();
74         zfs_agent_fini();
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         if (buflen <= 0) {
268                 errno = EMSGSIZE;
269                 zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
270                     keybuf, eid, "Exceeded buffer size");
271                 return (-1);
272         }
273
274         va_start(vargs, fmt);
275         n = vsnprintf(dstp, buflen, fmt, vargs);
276         va_end(vargs);
277
278         if ((n < 0) || (n >= buflen)) {
279                 errno = EMSGSIZE;
280                 zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
281                     keybuf, eid, "Exceeded buffer size");
282                 return (-1);
283         } else if (zed_strings_add(zsp, keybuf, valbuf) < 0) {
284                 zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
285                     keybuf, eid, strerror(errno));
286                 return (-1);
287         }
288         return (0);
289 }
290
291 static int
292 _zed_event_add_array_err(uint64_t eid, const char *name)
293 {
294         errno = EMSGSIZE;
295         zed_log_msg(LOG_WARNING,
296             "Failed to convert nvpair \"%s\" for eid=%llu: "
297             "Exceeded buffer size", name, eid);
298         return (-1);
299 }
300
301 static int
302 _zed_event_add_int8_array(uint64_t eid, zed_strings_t *zsp,
303     const char *prefix, nvpair_t *nvp)
304 {
305         char buf[MAXBUF];
306         int buflen = sizeof (buf);
307         const char *name;
308         int8_t *i8p;
309         uint_t nelem;
310         uint_t i;
311         char *p;
312         int n;
313
314         assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT8_ARRAY));
315
316         name = nvpair_name(nvp);
317         (void) nvpair_value_int8_array(nvp, &i8p, &nelem);
318         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
319                 n = snprintf(p, buflen, "%d ", i8p[i]);
320                 if ((n < 0) || (n >= buflen))
321                         return (_zed_event_add_array_err(eid, name));
322                 p += n;
323                 buflen -= n;
324         }
325         if (nelem > 0)
326                 *--p = '\0';
327
328         return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
329 }
330
331 static int
332 _zed_event_add_uint8_array(uint64_t eid, zed_strings_t *zsp,
333     const char *prefix, nvpair_t *nvp)
334 {
335         char buf[MAXBUF];
336         int buflen = sizeof (buf);
337         const char *name;
338         uint8_t *u8p;
339         uint_t nelem;
340         uint_t i;
341         char *p;
342         int n;
343
344         assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT8_ARRAY));
345
346         name = nvpair_name(nvp);
347         (void) nvpair_value_uint8_array(nvp, &u8p, &nelem);
348         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
349                 n = snprintf(p, buflen, "%u ", u8p[i]);
350                 if ((n < 0) || (n >= buflen))
351                         return (_zed_event_add_array_err(eid, name));
352                 p += n;
353                 buflen -= n;
354         }
355         if (nelem > 0)
356                 *--p = '\0';
357
358         return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
359 }
360
361 static int
362 _zed_event_add_int16_array(uint64_t eid, zed_strings_t *zsp,
363     const char *prefix, nvpair_t *nvp)
364 {
365         char buf[MAXBUF];
366         int buflen = sizeof (buf);
367         const char *name;
368         int16_t *i16p;
369         uint_t nelem;
370         uint_t i;
371         char *p;
372         int n;
373
374         assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT16_ARRAY));
375
376         name = nvpair_name(nvp);
377         (void) nvpair_value_int16_array(nvp, &i16p, &nelem);
378         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
379                 n = snprintf(p, buflen, "%d ", i16p[i]);
380                 if ((n < 0) || (n >= buflen))
381                         return (_zed_event_add_array_err(eid, name));
382                 p += n;
383                 buflen -= n;
384         }
385         if (nelem > 0)
386                 *--p = '\0';
387
388         return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
389 }
390
391 static int
392 _zed_event_add_uint16_array(uint64_t eid, zed_strings_t *zsp,
393     const char *prefix, nvpair_t *nvp)
394 {
395         char buf[MAXBUF];
396         int buflen = sizeof (buf);
397         const char *name;
398         uint16_t *u16p;
399         uint_t nelem;
400         uint_t i;
401         char *p;
402         int n;
403
404         assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT16_ARRAY));
405
406         name = nvpair_name(nvp);
407         (void) nvpair_value_uint16_array(nvp, &u16p, &nelem);
408         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
409                 n = snprintf(p, buflen, "%u ", u16p[i]);
410                 if ((n < 0) || (n >= buflen))
411                         return (_zed_event_add_array_err(eid, name));
412                 p += n;
413                 buflen -= n;
414         }
415         if (nelem > 0)
416                 *--p = '\0';
417
418         return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
419 }
420
421 static int
422 _zed_event_add_int32_array(uint64_t eid, zed_strings_t *zsp,
423     const char *prefix, nvpair_t *nvp)
424 {
425         char buf[MAXBUF];
426         int buflen = sizeof (buf);
427         const char *name;
428         int32_t *i32p;
429         uint_t nelem;
430         uint_t i;
431         char *p;
432         int n;
433
434         assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT32_ARRAY));
435
436         name = nvpair_name(nvp);
437         (void) nvpair_value_int32_array(nvp, &i32p, &nelem);
438         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
439                 n = snprintf(p, buflen, "%d ", i32p[i]);
440                 if ((n < 0) || (n >= buflen))
441                         return (_zed_event_add_array_err(eid, name));
442                 p += n;
443                 buflen -= n;
444         }
445         if (nelem > 0)
446                 *--p = '\0';
447
448         return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
449 }
450
451 static int
452 _zed_event_add_uint32_array(uint64_t eid, zed_strings_t *zsp,
453     const char *prefix, nvpair_t *nvp)
454 {
455         char buf[MAXBUF];
456         int buflen = sizeof (buf);
457         const char *name;
458         uint32_t *u32p;
459         uint_t nelem;
460         uint_t i;
461         char *p;
462         int n;
463
464         assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT32_ARRAY));
465
466         name = nvpair_name(nvp);
467         (void) nvpair_value_uint32_array(nvp, &u32p, &nelem);
468         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
469                 n = snprintf(p, buflen, "%u ", u32p[i]);
470                 if ((n < 0) || (n >= buflen))
471                         return (_zed_event_add_array_err(eid, name));
472                 p += n;
473                 buflen -= n;
474         }
475         if (nelem > 0)
476                 *--p = '\0';
477
478         return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
479 }
480
481 static int
482 _zed_event_add_int64_array(uint64_t eid, zed_strings_t *zsp,
483     const char *prefix, nvpair_t *nvp)
484 {
485         char buf[MAXBUF];
486         int buflen = sizeof (buf);
487         const char *name;
488         int64_t *i64p;
489         uint_t nelem;
490         uint_t i;
491         char *p;
492         int n;
493
494         assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT64_ARRAY));
495
496         name = nvpair_name(nvp);
497         (void) nvpair_value_int64_array(nvp, &i64p, &nelem);
498         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
499                 n = snprintf(p, buflen, "%lld ", (u_longlong_t)i64p[i]);
500                 if ((n < 0) || (n >= buflen))
501                         return (_zed_event_add_array_err(eid, name));
502                 p += n;
503                 buflen -= n;
504         }
505         if (nelem > 0)
506                 *--p = '\0';
507
508         return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
509 }
510
511 static int
512 _zed_event_add_uint64_array(uint64_t eid, zed_strings_t *zsp,
513     const char *prefix, nvpair_t *nvp)
514 {
515         char buf[MAXBUF];
516         int buflen = sizeof (buf);
517         const char *name;
518         const char *fmt;
519         uint64_t *u64p;
520         uint_t nelem;
521         uint_t i;
522         char *p;
523         int n;
524
525         assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY));
526
527         name = nvpair_name(nvp);
528         fmt = _zed_event_value_is_hex(name) ? "0x%.16llX " : "%llu ";
529         (void) nvpair_value_uint64_array(nvp, &u64p, &nelem);
530         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
531                 n = snprintf(p, buflen, fmt, (u_longlong_t)u64p[i]);
532                 if ((n < 0) || (n >= buflen))
533                         return (_zed_event_add_array_err(eid, name));
534                 p += n;
535                 buflen -= n;
536         }
537         if (nelem > 0)
538                 *--p = '\0';
539
540         return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
541 }
542
543 static int
544 _zed_event_add_string_array(uint64_t eid, zed_strings_t *zsp,
545     const char *prefix, nvpair_t *nvp)
546 {
547         char buf[MAXBUF];
548         int buflen = sizeof (buf);
549         const char *name;
550         char **strp;
551         uint_t nelem;
552         uint_t i;
553         char *p;
554         int n;
555
556         assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY));
557
558         name = nvpair_name(nvp);
559         (void) nvpair_value_string_array(nvp, &strp, &nelem);
560         for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
561                 n = snprintf(p, buflen, "%s ", strp[i] ? strp[i] : "<NULL>");
562                 if ((n < 0) || (n >= buflen))
563                         return (_zed_event_add_array_err(eid, name));
564                 p += n;
565                 buflen -= n;
566         }
567         if (nelem > 0)
568                 *--p = '\0';
569
570         return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
571 }
572
573 /*
574  * Convert the nvpair [nvp] to a string which is added to the environment
575  * of the child process.
576  * Return 0 on success, -1 on error.
577  *
578  * FIXME: Refactor with cmd/zpool/zpool_main.c:zpool_do_events_nvprint()?
579  */
580 static void
581 _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
582 {
583         const char *name;
584         data_type_t type;
585         const char *prefix = ZEVENT_VAR_PREFIX;
586         boolean_t b;
587         double d;
588         uint8_t i8;
589         uint16_t i16;
590         uint32_t i32;
591         uint64_t i64;
592         char *str;
593
594         assert(zsp != NULL);
595         assert(nvp != NULL);
596
597         name = nvpair_name(nvp);
598         type = nvpair_type(nvp);
599
600         switch (type) {
601         case DATA_TYPE_BOOLEAN:
602                 _zed_event_add_var(eid, zsp, prefix, name, "%s", "1");
603                 break;
604         case DATA_TYPE_BOOLEAN_VALUE:
605                 (void) nvpair_value_boolean_value(nvp, &b);
606                 _zed_event_add_var(eid, zsp, prefix, name, "%s", b ? "1" : "0");
607                 break;
608         case DATA_TYPE_BYTE:
609                 (void) nvpair_value_byte(nvp, &i8);
610                 _zed_event_add_var(eid, zsp, prefix, name, "%d", i8);
611                 break;
612         case DATA_TYPE_INT8:
613                 (void) nvpair_value_int8(nvp, (int8_t *)&i8);
614                 _zed_event_add_var(eid, zsp, prefix, name, "%d", i8);
615                 break;
616         case DATA_TYPE_UINT8:
617                 (void) nvpair_value_uint8(nvp, &i8);
618                 _zed_event_add_var(eid, zsp, prefix, name, "%u", i8);
619                 break;
620         case DATA_TYPE_INT16:
621                 (void) nvpair_value_int16(nvp, (int16_t *)&i16);
622                 _zed_event_add_var(eid, zsp, prefix, name, "%d", i16);
623                 break;
624         case DATA_TYPE_UINT16:
625                 (void) nvpair_value_uint16(nvp, &i16);
626                 _zed_event_add_var(eid, zsp, prefix, name, "%u", i16);
627                 break;
628         case DATA_TYPE_INT32:
629                 (void) nvpair_value_int32(nvp, (int32_t *)&i32);
630                 _zed_event_add_var(eid, zsp, prefix, name, "%d", i32);
631                 break;
632         case DATA_TYPE_UINT32:
633                 (void) nvpair_value_uint32(nvp, &i32);
634                 _zed_event_add_var(eid, zsp, prefix, name, "%u", i32);
635                 break;
636         case DATA_TYPE_INT64:
637                 (void) nvpair_value_int64(nvp, (int64_t *)&i64);
638                 _zed_event_add_var(eid, zsp, prefix, name,
639                     "%lld", (longlong_t)i64);
640                 break;
641         case DATA_TYPE_UINT64:
642                 (void) nvpair_value_uint64(nvp, &i64);
643                 _zed_event_add_var(eid, zsp, prefix, name,
644                     (_zed_event_value_is_hex(name) ? "0x%.16llX" : "%llu"),
645                     (u_longlong_t)i64);
646                 /*
647                  * shadow readable strings for vdev state pairs
648                  */
649                 if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE) == 0 ||
650                     strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE) == 0) {
651                         char alt[32];
652
653                         (void) snprintf(alt, sizeof (alt), "%s_str", name);
654                         _zed_event_add_var(eid, zsp, prefix, alt, "%s",
655                             zpool_state_to_name(i64, VDEV_AUX_NONE));
656                 }
657                 break;
658         case DATA_TYPE_DOUBLE:
659                 (void) nvpair_value_double(nvp, &d);
660                 _zed_event_add_var(eid, zsp, prefix, name, "%g", d);
661                 break;
662         case DATA_TYPE_HRTIME:
663                 (void) nvpair_value_hrtime(nvp, (hrtime_t *)&i64);
664                 _zed_event_add_var(eid, zsp, prefix, name,
665                     "%llu", (u_longlong_t)i64);
666                 break;
667         case DATA_TYPE_NVLIST:
668                 _zed_event_add_var(eid, zsp, prefix, name,
669                     "%s", "_NOT_IMPLEMENTED_");                 /* FIXME */
670                 break;
671         case DATA_TYPE_STRING:
672                 (void) nvpair_value_string(nvp, &str);
673                 _zed_event_add_var(eid, zsp, prefix, name,
674                     "%s", (str ? str : "<NULL>"));
675                 break;
676         case DATA_TYPE_BOOLEAN_ARRAY:
677                 _zed_event_add_var(eid, zsp, prefix, name,
678                     "%s", "_NOT_IMPLEMENTED_");                 /* FIXME */
679                 break;
680         case DATA_TYPE_BYTE_ARRAY:
681                 _zed_event_add_var(eid, zsp, prefix, name,
682                     "%s", "_NOT_IMPLEMENTED_");                 /* FIXME */
683                 break;
684         case DATA_TYPE_INT8_ARRAY:
685                 _zed_event_add_int8_array(eid, zsp, prefix, nvp);
686                 break;
687         case DATA_TYPE_UINT8_ARRAY:
688                 _zed_event_add_uint8_array(eid, zsp, prefix, nvp);
689                 break;
690         case DATA_TYPE_INT16_ARRAY:
691                 _zed_event_add_int16_array(eid, zsp, prefix, nvp);
692                 break;
693         case DATA_TYPE_UINT16_ARRAY:
694                 _zed_event_add_uint16_array(eid, zsp, prefix, nvp);
695                 break;
696         case DATA_TYPE_INT32_ARRAY:
697                 _zed_event_add_int32_array(eid, zsp, prefix, nvp);
698                 break;
699         case DATA_TYPE_UINT32_ARRAY:
700                 _zed_event_add_uint32_array(eid, zsp, prefix, nvp);
701                 break;
702         case DATA_TYPE_INT64_ARRAY:
703                 _zed_event_add_int64_array(eid, zsp, prefix, nvp);
704                 break;
705         case DATA_TYPE_UINT64_ARRAY:
706                 _zed_event_add_uint64_array(eid, zsp, prefix, nvp);
707                 break;
708         case DATA_TYPE_STRING_ARRAY:
709                 _zed_event_add_string_array(eid, zsp, prefix, nvp);
710                 break;
711         case DATA_TYPE_NVLIST_ARRAY:
712                 _zed_event_add_var(eid, zsp, prefix, name,
713                     "%s", "_NOT_IMPLEMENTED_");                 /* FIXME */
714                 break;
715         default:
716                 errno = EINVAL;
717                 zed_log_msg(LOG_WARNING,
718                     "Failed to convert nvpair \"%s\" for eid=%llu: "
719                     "Unrecognized type=%u", name, eid, (unsigned int) type);
720                 break;
721         }
722 }
723
724 /*
725  * Restrict various environment variables to safe and sane values
726  * when constructing the environment for the child process.
727  *
728  * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
729  */
730 static void
731 _zed_event_add_env_restrict(uint64_t eid, zed_strings_t *zsp)
732 {
733         const char *env_restrict[][2] = {
734                 { "IFS",                " \t\n" },
735                 { "PATH",               _PATH_STDPATH },
736                 { "ZDB",                SBINDIR "/zdb" },
737                 { "ZED",                SBINDIR "/zed" },
738                 { "ZFS",                SBINDIR "/zfs" },
739                 { "ZINJECT",            SBINDIR "/zinject" },
740                 { "ZPOOL",              SBINDIR "/zpool" },
741                 { "ZFS_ALIAS",          ZFS_META_ALIAS },
742                 { "ZFS_VERSION",        ZFS_META_VERSION },
743                 { "ZFS_RELEASE",        ZFS_META_RELEASE },
744                 { NULL,                 NULL }
745         };
746         const char *(*pa)[2];
747
748         assert(zsp != NULL);
749
750         for (pa = env_restrict; *(*pa); pa++) {
751                 _zed_event_add_var(eid, zsp, NULL, (*pa)[0], "%s", (*pa)[1]);
752         }
753 }
754
755 /*
756  * Preserve specified variables from the parent environment
757  * when constructing the environment for the child process.
758  *
759  * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
760  */
761 static void
762 _zed_event_add_env_preserve(uint64_t eid, zed_strings_t *zsp)
763 {
764         const char *env_preserve[] = {
765                 "TZ",
766                 NULL
767         };
768         const char **keyp;
769         const char *val;
770
771         assert(zsp != NULL);
772
773         for (keyp = env_preserve; *keyp; keyp++) {
774                 if ((val = getenv(*keyp)))
775                         _zed_event_add_var(eid, zsp, NULL, *keyp, "%s", val);
776         }
777 }
778
779 /*
780  * Compute the "subclass" by removing the first 3 components of [class]
781  * (which will always be of the form "*.fs.zfs").  Return a pointer inside
782  * the string [class], or NULL if insufficient components exist.
783  */
784 static const char *
785 _zed_event_get_subclass(const char *class)
786 {
787         const char *p;
788         int i;
789
790         if (!class)
791                 return (NULL);
792
793         p = class;
794         for (i = 0; i < 3; i++) {
795                 p = strchr(p, '.');
796                 if (!p)
797                         break;
798                 p++;
799         }
800         return (p);
801 }
802
803 /*
804  * Convert the zevent time from a 2-element array of 64b integers
805  * into a more convenient form:
806  * - TIME_SECS is the second component of the time.
807  * - TIME_NSECS is the nanosecond component of the time.
808  * - TIME_STRING is an almost-RFC3339-compliant string representation.
809  */
810 static void
811 _zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[])
812 {
813         struct tm *stp;
814         char buf[32];
815
816         assert(zsp != NULL);
817         assert(etime != NULL);
818
819         _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_SECS",
820             "%lld", (long long int) etime[0]);
821         _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_NSECS",
822             "%lld", (long long int) etime[1]);
823
824         if (!(stp = localtime((const time_t *) &etime[0]))) {
825                 zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
826                     ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "localtime error");
827         } else if (!strftime(buf, sizeof (buf), "%Y-%m-%d %H:%M:%S%z", stp)) {
828                 zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
829                     ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "strftime error");
830         } else {
831                 _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_STRING",
832                     "%s", buf);
833         }
834 }
835
836 /*
837  * Service the next zevent, blocking until one is available.
838  */
839 void
840 zed_event_service(struct zed_conf *zcp)
841 {
842         nvlist_t *nvl;
843         nvpair_t *nvp;
844         int n_dropped;
845         zed_strings_t *zsp;
846         uint64_t eid;
847         int64_t *etime;
848         uint_t nelem;
849         char *class;
850         const char *subclass;
851         int rv;
852
853         if (!zcp) {
854                 errno = EINVAL;
855                 zed_log_msg(LOG_ERR, "Failed to service zevent: %s",
856                     strerror(errno));
857                 return;
858         }
859         rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped, ZEVENT_NONE,
860             zcp->zevent_fd);
861
862         if ((rv != 0) || !nvl)
863                 return;
864
865         if (n_dropped > 0) {
866                 zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
867                 /*
868                  * FIXME: Increase max size of event nvlist in
869                  * /sys/module/zfs/parameters/zfs_zevent_len_max ?
870                  */
871         }
872         if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
873                 zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
874         } else if (nvlist_lookup_int64_array(
875             nvl, "time", &etime, &nelem) != 0) {
876                 zed_log_msg(LOG_WARNING,
877                     "Failed to lookup zevent time (eid=%llu)", eid);
878         } else if (nelem != 2) {
879                 zed_log_msg(LOG_WARNING,
880                     "Failed to lookup zevent time (eid=%llu, nelem=%u)",
881                     eid, nelem);
882         } else if (nvlist_lookup_string(nvl, "class", &class) != 0) {
883                 zed_log_msg(LOG_WARNING,
884                     "Failed to lookup zevent class (eid=%llu)", eid);
885         } else {
886                 /* let internal modules see this event first */
887                 zfs_agent_post_event(class, NULL, nvl);
888
889                 zsp = zed_strings_create();
890
891                 nvp = NULL;
892                 while ((nvp = nvlist_next_nvpair(nvl, nvp)))
893                         _zed_event_add_nvpair(eid, zsp, nvp);
894
895                 _zed_event_add_env_restrict(eid, zsp);
896                 _zed_event_add_env_preserve(eid, zsp);
897
898                 _zed_event_add_var(eid, zsp, ZED_VAR_PREFIX, "PID",
899                     "%d", (int)getpid());
900                 _zed_event_add_var(eid, zsp, ZED_VAR_PREFIX, "ZEDLET_DIR",
901                     "%s", zcp->zedlet_dir);
902                 subclass = _zed_event_get_subclass(class);
903                 _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "SUBCLASS",
904                     "%s", (subclass ? subclass : class));
905
906                 _zed_event_add_time_strings(eid, zsp, etime);
907
908                 zed_exec_process(eid, class, subclass,
909                     zcp->zedlet_dir, zcp->zedlets, zsp, zcp->zevent_fd);
910
911                 zed_conf_write_state(zcp, eid, etime);
912
913                 zed_strings_destroy(zsp);
914         }
915         nvlist_free(nvl);
916 }