]> git.proxmox.com Git - mirror_zfs-debian.git/blob - cmd/zed/zed_event.c
390235019b368be883793f306e8f3c729a989315
[mirror_zfs-debian.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 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 } else
657 /*
658 * shadow readable strings for pool state
659 */
660 if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_POOL_STATE) == 0) {
661 char alt[32];
662
663 (void) snprintf(alt, sizeof (alt), "%s_str", name);
664 _zed_event_add_var(eid, zsp, prefix, alt, "%s",
665 zpool_pool_state_to_name(i64));
666 }
667 break;
668 case DATA_TYPE_DOUBLE:
669 (void) nvpair_value_double(nvp, &d);
670 _zed_event_add_var(eid, zsp, prefix, name, "%g", d);
671 break;
672 case DATA_TYPE_HRTIME:
673 (void) nvpair_value_hrtime(nvp, (hrtime_t *)&i64);
674 _zed_event_add_var(eid, zsp, prefix, name,
675 "%llu", (u_longlong_t)i64);
676 break;
677 case DATA_TYPE_NVLIST:
678 _zed_event_add_var(eid, zsp, prefix, name,
679 "%s", "_NOT_IMPLEMENTED_"); /* FIXME */
680 break;
681 case DATA_TYPE_STRING:
682 (void) nvpair_value_string(nvp, &str);
683 _zed_event_add_var(eid, zsp, prefix, name,
684 "%s", (str ? str : "<NULL>"));
685 break;
686 case DATA_TYPE_BOOLEAN_ARRAY:
687 _zed_event_add_var(eid, zsp, prefix, name,
688 "%s", "_NOT_IMPLEMENTED_"); /* FIXME */
689 break;
690 case DATA_TYPE_BYTE_ARRAY:
691 _zed_event_add_var(eid, zsp, prefix, name,
692 "%s", "_NOT_IMPLEMENTED_"); /* FIXME */
693 break;
694 case DATA_TYPE_INT8_ARRAY:
695 _zed_event_add_int8_array(eid, zsp, prefix, nvp);
696 break;
697 case DATA_TYPE_UINT8_ARRAY:
698 _zed_event_add_uint8_array(eid, zsp, prefix, nvp);
699 break;
700 case DATA_TYPE_INT16_ARRAY:
701 _zed_event_add_int16_array(eid, zsp, prefix, nvp);
702 break;
703 case DATA_TYPE_UINT16_ARRAY:
704 _zed_event_add_uint16_array(eid, zsp, prefix, nvp);
705 break;
706 case DATA_TYPE_INT32_ARRAY:
707 _zed_event_add_int32_array(eid, zsp, prefix, nvp);
708 break;
709 case DATA_TYPE_UINT32_ARRAY:
710 _zed_event_add_uint32_array(eid, zsp, prefix, nvp);
711 break;
712 case DATA_TYPE_INT64_ARRAY:
713 _zed_event_add_int64_array(eid, zsp, prefix, nvp);
714 break;
715 case DATA_TYPE_UINT64_ARRAY:
716 _zed_event_add_uint64_array(eid, zsp, prefix, nvp);
717 break;
718 case DATA_TYPE_STRING_ARRAY:
719 _zed_event_add_string_array(eid, zsp, prefix, nvp);
720 break;
721 case DATA_TYPE_NVLIST_ARRAY:
722 _zed_event_add_var(eid, zsp, prefix, name,
723 "%s", "_NOT_IMPLEMENTED_"); /* FIXME */
724 break;
725 default:
726 errno = EINVAL;
727 zed_log_msg(LOG_WARNING,
728 "Failed to convert nvpair \"%s\" for eid=%llu: "
729 "Unrecognized type=%u", name, eid, (unsigned int) type);
730 break;
731 }
732 }
733
734 /*
735 * Restrict various environment variables to safe and sane values
736 * when constructing the environment for the child process.
737 *
738 * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
739 */
740 static void
741 _zed_event_add_env_restrict(uint64_t eid, zed_strings_t *zsp)
742 {
743 const char *env_restrict[][2] = {
744 { "IFS", " \t\n" },
745 { "PATH", _PATH_STDPATH },
746 { "ZDB", SBINDIR "/zdb" },
747 { "ZED", SBINDIR "/zed" },
748 { "ZFS", SBINDIR "/zfs" },
749 { "ZINJECT", SBINDIR "/zinject" },
750 { "ZPOOL", SBINDIR "/zpool" },
751 { "ZFS_ALIAS", ZFS_META_ALIAS },
752 { "ZFS_VERSION", ZFS_META_VERSION },
753 { "ZFS_RELEASE", ZFS_META_RELEASE },
754 { NULL, NULL }
755 };
756 const char *(*pa)[2];
757
758 assert(zsp != NULL);
759
760 for (pa = env_restrict; *(*pa); pa++) {
761 _zed_event_add_var(eid, zsp, NULL, (*pa)[0], "%s", (*pa)[1]);
762 }
763 }
764
765 /*
766 * Preserve specified variables from the parent environment
767 * when constructing the environment for the child process.
768 *
769 * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
770 */
771 static void
772 _zed_event_add_env_preserve(uint64_t eid, zed_strings_t *zsp)
773 {
774 const char *env_preserve[] = {
775 "TZ",
776 NULL
777 };
778 const char **keyp;
779 const char *val;
780
781 assert(zsp != NULL);
782
783 for (keyp = env_preserve; *keyp; keyp++) {
784 if ((val = getenv(*keyp)))
785 _zed_event_add_var(eid, zsp, NULL, *keyp, "%s", val);
786 }
787 }
788
789 /*
790 * Compute the "subclass" by removing the first 3 components of [class]
791 * (which will always be of the form "*.fs.zfs"). Return a pointer inside
792 * the string [class], or NULL if insufficient components exist.
793 */
794 static const char *
795 _zed_event_get_subclass(const char *class)
796 {
797 const char *p;
798 int i;
799
800 if (!class)
801 return (NULL);
802
803 p = class;
804 for (i = 0; i < 3; i++) {
805 p = strchr(p, '.');
806 if (!p)
807 break;
808 p++;
809 }
810 return (p);
811 }
812
813 /*
814 * Convert the zevent time from a 2-element array of 64b integers
815 * into a more convenient form:
816 * - TIME_SECS is the second component of the time.
817 * - TIME_NSECS is the nanosecond component of the time.
818 * - TIME_STRING is an almost-RFC3339-compliant string representation.
819 */
820 static void
821 _zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[])
822 {
823 struct tm *stp;
824 char buf[32];
825
826 assert(zsp != NULL);
827 assert(etime != NULL);
828
829 _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_SECS",
830 "%lld", (long long int) etime[0]);
831 _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_NSECS",
832 "%lld", (long long int) etime[1]);
833
834 if (!(stp = localtime((const time_t *) &etime[0]))) {
835 zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
836 ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "localtime error");
837 } else if (!strftime(buf, sizeof (buf), "%Y-%m-%d %H:%M:%S%z", stp)) {
838 zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
839 ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "strftime error");
840 } else {
841 _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_STRING",
842 "%s", buf);
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 zfs_agent_post_event(class, NULL, 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
916 _zed_event_add_time_strings(eid, zsp, etime);
917
918 zed_exec_process(eid, class, subclass,
919 zcp->zedlet_dir, zcp->zedlets, zsp, zcp->zevent_fd);
920
921 zed_conf_write_state(zcp, eid, etime);
922
923 zed_strings_destroy(zsp);
924 }
925 nvlist_free(nvl);
926 }