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