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