1 /* 2 * This file is part of the ZFS Event Daemon (ZED). 3 * 4 * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). 5 * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. 6 * Refer to the OpenZFS git commit log for authoritative copyright attribution. 7 * 8 * The contents of this file are subject to the terms of the 9 * Common Development and Distribution License Version 1.0 (CDDL-1.0). 10 * You can obtain a copy of the license from the top-level file 11 * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>. 12 * You may not use this file except in compliance with the license. 13 */ 14 15 #include <assert.h> 16 #include <ctype.h> 17 #include <dirent.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <libgen.h> 21 #include <limits.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 #include <sys/uio.h> 28 #include <unistd.h> 29 #include "zed.h" 30 #include "zed_conf.h" 31 #include "zed_file.h" 32 #include "zed_log.h" 33 #include "zed_strings.h" 34 35 /* 36 * Initialise the configuration with default values. 37 */ 38 void 39 zed_conf_init(struct zed_conf *zcp) 40 { 41 memset(zcp, 0, sizeof (*zcp)); 42 43 /* zcp->zfs_hdl opened in zed_event_init() */ 44 /* zcp->zedlets created in zed_conf_scan_dir() */ 45 46 zcp->pid_fd = -1; /* opened in zed_conf_write_pid() */ 47 zcp->state_fd = -1; /* opened in zed_conf_open_state() */ 48 zcp->zevent_fd = -1; /* opened in zed_event_init() */ 49 50 zcp->max_jobs = 16; 51 zcp->max_zevent_buf_len = 1 << 20; 52 53 if (!(zcp->pid_file = strdup(ZED_PID_FILE)) || 54 !(zcp->zedlet_dir = strdup(ZED_ZEDLET_DIR)) || 55 !(zcp->state_file = strdup(ZED_STATE_FILE))) 56 zed_log_die("Failed to create conf: %s", strerror(errno)); 57 } 58 59 /* 60 * Destroy the configuration [zcp]. 61 * 62 * Note: zfs_hdl & zevent_fd are destroyed via zed_event_fini(). 63 */ 64 void 65 zed_conf_destroy(struct zed_conf *zcp) 66 { 67 if (zcp->state_fd >= 0) { 68 if (close(zcp->state_fd) < 0) 69 zed_log_msg(LOG_WARNING, 70 "Failed to close state file \"%s\": %s", 71 zcp->state_file, strerror(errno)); 72 zcp->state_fd = -1; 73 } 74 if (zcp->pid_file) { 75 if ((unlink(zcp->pid_file) < 0) && (errno != ENOENT)) 76 zed_log_msg(LOG_WARNING, 77 "Failed to remove PID file \"%s\": %s", 78 zcp->pid_file, strerror(errno)); 79 } 80 if (zcp->pid_fd >= 0) { 81 if (close(zcp->pid_fd) < 0) 82 zed_log_msg(LOG_WARNING, 83 "Failed to close PID file \"%s\": %s", 84 zcp->pid_file, strerror(errno)); 85 zcp->pid_fd = -1; 86 } 87 if (zcp->pid_file) { 88 free(zcp->pid_file); 89 zcp->pid_file = NULL; 90 } 91 if (zcp->zedlet_dir) { 92 free(zcp->zedlet_dir); 93 zcp->zedlet_dir = NULL; 94 } 95 if (zcp->state_file) { 96 free(zcp->state_file); 97 zcp->state_file = NULL; 98 } 99 if (zcp->zedlets) { 100 zed_strings_destroy(zcp->zedlets); 101 zcp->zedlets = NULL; 102 } 103 } 104 105 /* 106 * Display command-line help and exit. 107 * 108 * If [got_err] is 0, output to stdout and exit normally; 109 * otherwise, output to stderr and exit with a failure status. 110 */ 111 static void 112 _zed_conf_display_help(const char *prog, boolean_t got_err) 113 { 114 struct opt { const char *o, *d, *v; }; 115 116 FILE *fp = got_err ? stderr : stdout; 117 118 struct opt *oo; 119 struct opt iopts[] = { 120 { .o = "-h", .d = "Display help" }, 121 { .o = "-L", .d = "Display license information" }, 122 { .o = "-V", .d = "Display version information" }, 123 {}, 124 }; 125 struct opt nopts[] = { 126 { .o = "-v", .d = "Be verbose" }, 127 { .o = "-f", .d = "Force daemon to run" }, 128 { .o = "-F", .d = "Run daemon in the foreground" }, 129 { .o = "-I", 130 .d = "Idle daemon until kernel module is (re)loaded" }, 131 { .o = "-M", .d = "Lock all pages in memory" }, 132 { .o = "-P", .d = "$PATH for ZED to use (only used by ZTS)" }, 133 { .o = "-Z", .d = "Zero state file" }, 134 {}, 135 }; 136 struct opt vopts[] = { 137 { .o = "-d DIR", .d = "Read enabled ZEDLETs from DIR.", 138 .v = ZED_ZEDLET_DIR }, 139 { .o = "-p FILE", .d = "Write daemon's PID to FILE.", 140 .v = ZED_PID_FILE }, 141 { .o = "-s FILE", .d = "Write daemon's state to FILE.", 142 .v = ZED_STATE_FILE }, 143 { .o = "-j JOBS", .d = "Start at most JOBS at once.", 144 .v = "16" }, 145 { .o = "-b LEN", .d = "Cap kernel event buffer at LEN entries.", 146 .v = "1048576" }, 147 {}, 148 }; 149 150 fprintf(fp, "Usage: %s [OPTION]...\n", (prog ? prog : "zed")); 151 fprintf(fp, "\n"); 152 for (oo = iopts; oo->o; ++oo) 153 fprintf(fp, " %*s %s\n", -8, oo->o, oo->d); 154 fprintf(fp, "\n"); 155 for (oo = nopts; oo->o; ++oo) 156 fprintf(fp, " %*s %s\n", -8, oo->o, oo->d); 157 fprintf(fp, "\n"); 158 for (oo = vopts; oo->o; ++oo) 159 fprintf(fp, " %*s %s [%s]\n", -8, oo->o, oo->d, oo->v); 160 fprintf(fp, "\n"); 161 162 exit(got_err ? EXIT_FAILURE : EXIT_SUCCESS); 163 } 164 165 /* 166 * Display license information to stdout and exit. 167 */ 168 static void 169 _zed_conf_display_license(void) 170 { 171 printf( 172 "The ZFS Event Daemon (ZED) is distributed under the terms of the\n" 173 " Common Development and Distribution License (CDDL-1.0)\n" 174 " <http://opensource.org/licenses/CDDL-1.0>.\n" 175 "\n" 176 "Developed at Lawrence Livermore National Laboratory" 177 " (LLNL-CODE-403049).\n" 178 "\n"); 179 180 exit(EXIT_SUCCESS); 181 } 182 183 /* 184 * Display version information to stdout and exit. 185 */ 186 static void 187 _zed_conf_display_version(void) 188 { 189 printf("%s-%s-%s\n", 190 ZFS_META_NAME, ZFS_META_VERSION, ZFS_META_RELEASE); 191 192 exit(EXIT_SUCCESS); 193 } 194 195 /* 196 * Copy the [path] string to the [resultp] ptr. 197 * If [path] is not an absolute path, prefix it with the current working dir. 198 * If [resultp] is non-null, free its existing string before assignment. 199 */ 200 static void 201 _zed_conf_parse_path(char **resultp, const char *path) 202 { 203 char buf[PATH_MAX]; 204 205 assert(resultp != NULL); 206 assert(path != NULL); 207 208 if (*resultp) 209 free(*resultp); 210 211 if (path[0] == '/') { 212 *resultp = strdup(path); 213 } else { 214 if (!getcwd(buf, sizeof (buf))) 215 zed_log_die("Failed to get current working dir: %s", 216 strerror(errno)); 217 218 if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf) || 219 strlcat(buf, path, sizeof (buf)) >= sizeof (buf)) 220 zed_log_die("Failed to copy path: %s", 221 strerror(ENAMETOOLONG)); 222 223 *resultp = strdup(buf); 224 } 225 226 if (!*resultp) 227 zed_log_die("Failed to copy path: %s", strerror(ENOMEM)); 228 } 229 230 /* 231 * Parse the command-line options into the configuration [zcp]. 232 */ 233 void 234 zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv) 235 { 236 const char * const opts = ":hLVd:p:P:s:vfFMZIj:b:"; 237 int opt; 238 unsigned long raw; 239 240 if (!zcp || !argv || !argv[0]) 241 zed_log_die("Failed to parse options: Internal error"); 242 243 opterr = 0; /* suppress default getopt err msgs */ 244 245 while ((opt = getopt(argc, argv, opts)) != -1) { 246 switch (opt) { 247 case 'h': 248 _zed_conf_display_help(argv[0], B_FALSE); 249 break; 250 case 'L': 251 _zed_conf_display_license(); 252 break; 253 case 'V': 254 _zed_conf_display_version(); 255 break; 256 case 'd': 257 _zed_conf_parse_path(&zcp->zedlet_dir, optarg); 258 break; 259 case 'I': 260 zcp->do_idle = 1; 261 break; 262 case 'p': 263 _zed_conf_parse_path(&zcp->pid_file, optarg); 264 break; 265 case 'P': 266 _zed_conf_parse_path(&zcp->path, optarg); 267 break; 268 case 's': 269 _zed_conf_parse_path(&zcp->state_file, optarg); 270 break; 271 case 'v': 272 zcp->do_verbose = 1; 273 break; 274 case 'f': 275 zcp->do_force = 1; 276 break; 277 case 'F': 278 zcp->do_foreground = 1; 279 break; 280 case 'M': 281 zcp->do_memlock = 1; 282 break; 283 case 'Z': 284 zcp->do_zero = 1; 285 break; 286 case 'j': 287 errno = 0; 288 raw = strtoul(optarg, NULL, 0); 289 if (errno == ERANGE || raw > INT16_MAX) { 290 zed_log_die("%lu is too many jobs", raw); 291 } if (raw == 0) { 292 zed_log_die("0 jobs makes no sense"); 293 } else { 294 zcp->max_jobs = raw; 295 } 296 break; 297 case 'b': 298 errno = 0; 299 raw = strtoul(optarg, NULL, 0); 300 if (errno == ERANGE || raw > INT32_MAX) { 301 zed_log_die("%lu is too large", raw); 302 } if (raw == 0) { 303 zcp->max_zevent_buf_len = INT32_MAX; 304 } else { 305 zcp->max_zevent_buf_len = raw; 306 } 307 break; 308 case '?': 309 default: 310 if (optopt == '?') 311 _zed_conf_display_help(argv[0], B_FALSE); 312 313 fprintf(stderr, "%s: Invalid option '-%c'\n\n", 314 argv[0], optopt); 315 _zed_conf_display_help(argv[0], B_TRUE); 316 break; 317 } 318 } 319 } 320 321 /* 322 * Scan the [zcp] zedlet_dir for files to exec based on the event class. 323 * Files must be executable by user, but not writable by group or other. 324 * Dotfiles are ignored. 325 * 326 * Return 0 on success with an updated set of zedlets, 327 * or -1 on error with errno set. 328 */ 329 int 330 zed_conf_scan_dir(struct zed_conf *zcp) 331 { 332 zed_strings_t *zedlets; 333 DIR *dirp; 334 struct dirent *direntp; 335 char pathname[PATH_MAX]; 336 struct stat st; 337 int n; 338 339 if (!zcp) { 340 errno = EINVAL; 341 zed_log_msg(LOG_ERR, "Failed to scan zedlet dir: %s", 342 strerror(errno)); 343 return (-1); 344 } 345 zedlets = zed_strings_create(); 346 if (!zedlets) { 347 errno = ENOMEM; 348 zed_log_msg(LOG_WARNING, "Failed to scan dir \"%s\": %s", 349 zcp->zedlet_dir, strerror(errno)); 350 return (-1); 351 } 352 dirp = opendir(zcp->zedlet_dir); 353 if (!dirp) { 354 int errno_bak = errno; 355 zed_log_msg(LOG_WARNING, "Failed to open dir \"%s\": %s", 356 zcp->zedlet_dir, strerror(errno)); 357 zed_strings_destroy(zedlets); 358 errno = errno_bak; 359 return (-1); 360 } 361 while ((direntp = readdir(dirp))) { 362 if (direntp->d_name[0] == '.') 363 continue; 364 365 n = snprintf(pathname, sizeof (pathname), 366 "%s/%s", zcp->zedlet_dir, direntp->d_name); 367 if ((n < 0) || (n >= sizeof (pathname))) { 368 zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s", 369 direntp->d_name, strerror(ENAMETOOLONG)); 370 continue; 371 } 372 if (stat(pathname, &st) < 0) { 373 zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s", 374 pathname, strerror(errno)); 375 continue; 376 } 377 if (!S_ISREG(st.st_mode)) { 378 zed_log_msg(LOG_INFO, 379 "Ignoring \"%s\": not a regular file", 380 direntp->d_name); 381 continue; 382 } 383 if ((st.st_uid != 0) && !zcp->do_force) { 384 zed_log_msg(LOG_NOTICE, 385 "Ignoring \"%s\": not owned by root", 386 direntp->d_name); 387 continue; 388 } 389 if (!(st.st_mode & S_IXUSR)) { 390 zed_log_msg(LOG_INFO, 391 "Ignoring \"%s\": not executable by user", 392 direntp->d_name); 393 continue; 394 } 395 if ((st.st_mode & S_IWGRP) && !zcp->do_force) { 396 zed_log_msg(LOG_NOTICE, 397 "Ignoring \"%s\": writable by group", 398 direntp->d_name); 399 continue; 400 } 401 if ((st.st_mode & S_IWOTH) && !zcp->do_force) { 402 zed_log_msg(LOG_NOTICE, 403 "Ignoring \"%s\": writable by other", 404 direntp->d_name); 405 continue; 406 } 407 if (zed_strings_add(zedlets, NULL, direntp->d_name) < 0) { 408 zed_log_msg(LOG_WARNING, 409 "Failed to register \"%s\": %s", 410 direntp->d_name, strerror(errno)); 411 continue; 412 } 413 if (zcp->do_verbose) 414 zed_log_msg(LOG_INFO, 415 "Registered zedlet \"%s\"", direntp->d_name); 416 } 417 if (closedir(dirp) < 0) { 418 int errno_bak = errno; 419 zed_log_msg(LOG_WARNING, "Failed to close dir \"%s\": %s", 420 zcp->zedlet_dir, strerror(errno)); 421 zed_strings_destroy(zedlets); 422 errno = errno_bak; 423 return (-1); 424 } 425 if (zcp->zedlets) 426 zed_strings_destroy(zcp->zedlets); 427 428 zcp->zedlets = zedlets; 429 return (0); 430 } 431 432 /* 433 * Write the PID file specified in [zcp]. 434 * Return 0 on success, -1 on error. 435 * 436 * This must be called after fork()ing to become a daemon (so the correct PID 437 * is recorded), but before daemonization is complete and the parent process 438 * exits (for synchronization with systemd). 439 */ 440 int 441 zed_conf_write_pid(struct zed_conf *zcp) 442 { 443 char buf[PATH_MAX]; 444 int n; 445 char *p; 446 mode_t mask; 447 int rv; 448 449 if (!zcp || !zcp->pid_file) { 450 errno = EINVAL; 451 zed_log_msg(LOG_ERR, "Failed to create PID file: %s", 452 strerror(errno)); 453 return (-1); 454 } 455 assert(zcp->pid_fd == -1); 456 /* 457 * Create PID file directory if needed. 458 */ 459 n = strlcpy(buf, zcp->pid_file, sizeof (buf)); 460 if (n >= sizeof (buf)) { 461 errno = ENAMETOOLONG; 462 zed_log_msg(LOG_ERR, "Failed to create PID file: %s", 463 strerror(errno)); 464 goto err; 465 } 466 p = strrchr(buf, '/'); 467 if (p) 468 *p = '\0'; 469 470 if ((mkdirp(buf, 0755) < 0) && (errno != EEXIST)) { 471 zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s", 472 buf, strerror(errno)); 473 goto err; 474 } 475 /* 476 * Obtain PID file lock. 477 */ 478 mask = umask(0); 479 umask(mask | 022); 480 zcp->pid_fd = open(zcp->pid_file, O_RDWR | O_CREAT | O_CLOEXEC, 0644); 481 umask(mask); 482 if (zcp->pid_fd < 0) { 483 zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s", 484 zcp->pid_file, strerror(errno)); 485 goto err; 486 } 487 rv = zed_file_lock(zcp->pid_fd); 488 if (rv < 0) { 489 zed_log_msg(LOG_ERR, "Failed to lock PID file \"%s\": %s", 490 zcp->pid_file, strerror(errno)); 491 goto err; 492 } else if (rv > 0) { 493 pid_t pid = zed_file_is_locked(zcp->pid_fd); 494 if (pid < 0) { 495 zed_log_msg(LOG_ERR, 496 "Failed to test lock on PID file \"%s\"", 497 zcp->pid_file); 498 } else if (pid > 0) { 499 zed_log_msg(LOG_ERR, 500 "Found PID %d bound to PID file \"%s\"", 501 pid, zcp->pid_file); 502 } else { 503 zed_log_msg(LOG_ERR, 504 "Inconsistent lock state on PID file \"%s\"", 505 zcp->pid_file); 506 } 507 goto err; 508 } 509 /* 510 * Write PID file. 511 */ 512 n = snprintf(buf, sizeof (buf), "%d\n", (int)getpid()); 513 if ((n < 0) || (n >= sizeof (buf))) { 514 errno = ERANGE; 515 zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s", 516 zcp->pid_file, strerror(errno)); 517 } else if (write(zcp->pid_fd, buf, n) != n) { 518 zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s", 519 zcp->pid_file, strerror(errno)); 520 } else if (fdatasync(zcp->pid_fd) < 0) { 521 zed_log_msg(LOG_ERR, "Failed to sync PID file \"%s\": %s", 522 zcp->pid_file, strerror(errno)); 523 } else { 524 return (0); 525 } 526 527 err: 528 if (zcp->pid_fd >= 0) { 529 (void) close(zcp->pid_fd); 530 zcp->pid_fd = -1; 531 } 532 return (-1); 533 } 534 535 /* 536 * Open and lock the [zcp] state_file. 537 * Return 0 on success, -1 on error. 538 * 539 * FIXME: Move state information into kernel. 540 */ 541 int 542 zed_conf_open_state(struct zed_conf *zcp) 543 { 544 char dirbuf[PATH_MAX]; 545 int n; 546 char *p; 547 int rv; 548 549 if (!zcp || !zcp->state_file) { 550 errno = EINVAL; 551 zed_log_msg(LOG_ERR, "Failed to open state file: %s", 552 strerror(errno)); 553 return (-1); 554 } 555 n = strlcpy(dirbuf, zcp->state_file, sizeof (dirbuf)); 556 if (n >= sizeof (dirbuf)) { 557 errno = ENAMETOOLONG; 558 zed_log_msg(LOG_WARNING, "Failed to open state file: %s", 559 strerror(errno)); 560 return (-1); 561 } 562 p = strrchr(dirbuf, '/'); 563 if (p) 564 *p = '\0'; 565 566 if ((mkdirp(dirbuf, 0755) < 0) && (errno != EEXIST)) { 567 zed_log_msg(LOG_WARNING, 568 "Failed to create directory \"%s\": %s", 569 dirbuf, strerror(errno)); 570 return (-1); 571 } 572 if (zcp->state_fd >= 0) { 573 if (close(zcp->state_fd) < 0) { 574 zed_log_msg(LOG_WARNING, 575 "Failed to close state file \"%s\": %s", 576 zcp->state_file, strerror(errno)); 577 return (-1); 578 } 579 } 580 if (zcp->do_zero) 581 (void) unlink(zcp->state_file); 582 583 zcp->state_fd = open(zcp->state_file, 584 O_RDWR | O_CREAT | O_CLOEXEC, 0644); 585 if (zcp->state_fd < 0) { 586 zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s", 587 zcp->state_file, strerror(errno)); 588 return (-1); 589 } 590 rv = zed_file_lock(zcp->state_fd); 591 if (rv < 0) { 592 zed_log_msg(LOG_WARNING, "Failed to lock state file \"%s\": %s", 593 zcp->state_file, strerror(errno)); 594 return (-1); 595 } 596 if (rv > 0) { 597 pid_t pid = zed_file_is_locked(zcp->state_fd); 598 if (pid < 0) { 599 zed_log_msg(LOG_WARNING, 600 "Failed to test lock on state file \"%s\"", 601 zcp->state_file); 602 } else if (pid > 0) { 603 zed_log_msg(LOG_WARNING, 604 "Found PID %d bound to state file \"%s\"", 605 pid, zcp->state_file); 606 } else { 607 zed_log_msg(LOG_WARNING, 608 "Inconsistent lock state on state file \"%s\"", 609 zcp->state_file); 610 } 611 return (-1); 612 } 613 return (0); 614 } 615 616 /* 617 * Read the opened [zcp] state_file to obtain the eid & etime of the last event 618 * processed. Write the state from the last event to the [eidp] & [etime] args 619 * passed by reference. Note that etime[] is an array of size 2. 620 * Return 0 on success, -1 on error. 621 */ 622 int 623 zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[]) 624 { 625 ssize_t len; 626 struct iovec iov[3]; 627 ssize_t n; 628 629 if (!zcp || !eidp || !etime) { 630 errno = EINVAL; 631 zed_log_msg(LOG_ERR, 632 "Failed to read state file: %s", strerror(errno)); 633 return (-1); 634 } 635 if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t)-1) { 636 zed_log_msg(LOG_WARNING, 637 "Failed to reposition state file offset: %s", 638 strerror(errno)); 639 return (-1); 640 } 641 len = 0; 642 iov[0].iov_base = eidp; 643 len += iov[0].iov_len = sizeof (*eidp); 644 iov[1].iov_base = &etime[0]; 645 len += iov[1].iov_len = sizeof (etime[0]); 646 iov[2].iov_base = &etime[1]; 647 len += iov[2].iov_len = sizeof (etime[1]); 648 649 n = readv(zcp->state_fd, iov, 3); 650 if (n == 0) { 651 *eidp = 0; 652 } else if (n < 0) { 653 zed_log_msg(LOG_WARNING, 654 "Failed to read state file \"%s\": %s", 655 zcp->state_file, strerror(errno)); 656 return (-1); 657 } else if (n != len) { 658 errno = EIO; 659 zed_log_msg(LOG_WARNING, 660 "Failed to read state file \"%s\": Read %zd of %zd bytes", 661 zcp->state_file, n, len); 662 return (-1); 663 } 664 return (0); 665 } 666 667 /* 668 * Write the [eid] & [etime] of the last processed event to the opened 669 * [zcp] state_file. Note that etime[] is an array of size 2. 670 * Return 0 on success, -1 on error. 671 */ 672 int 673 zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[]) 674 { 675 ssize_t len; 676 struct iovec iov[3]; 677 ssize_t n; 678 679 if (!zcp) { 680 errno = EINVAL; 681 zed_log_msg(LOG_ERR, 682 "Failed to write state file: %s", strerror(errno)); 683 return (-1); 684 } 685 if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t)-1) { 686 zed_log_msg(LOG_WARNING, 687 "Failed to reposition state file offset: %s", 688 strerror(errno)); 689 return (-1); 690 } 691 len = 0; 692 iov[0].iov_base = &eid; 693 len += iov[0].iov_len = sizeof (eid); 694 iov[1].iov_base = &etime[0]; 695 len += iov[1].iov_len = sizeof (etime[0]); 696 iov[2].iov_base = &etime[1]; 697 len += iov[2].iov_len = sizeof (etime[1]); 698 699 n = writev(zcp->state_fd, iov, 3); 700 if (n < 0) { 701 zed_log_msg(LOG_WARNING, 702 "Failed to write state file \"%s\": %s", 703 zcp->state_file, strerror(errno)); 704 return (-1); 705 } 706 if (n != len) { 707 errno = EIO; 708 zed_log_msg(LOG_WARNING, 709 "Failed to write state file \"%s\": Wrote %zd of %zd bytes", 710 zcp->state_file, n, len); 711 return (-1); 712 } 713 if (fdatasync(zcp->state_fd) < 0) { 714 zed_log_msg(LOG_WARNING, 715 "Failed to sync state file \"%s\": %s", 716 zcp->state_file, strerror(errno)); 717 return (-1); 718 } 719 return (0); 720 } 721