1 /* 2 * This file is part of the ZFS Event Daemon (ZED) 3 * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>. 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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