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