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