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