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