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