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