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