]> granicus.if.org Git - zfs/blob - cmd/zed/zed_conf.c
Replace zed's use of malloc with calloc
[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 = calloc(1, sizeof (*zcp));
55         if (!zcp)
56                 goto nomem;
57
58         zcp->syslog_facility = LOG_DAEMON;
59         zcp->min_events = ZED_MIN_EVENTS;
60         zcp->max_events = ZED_MAX_EVENTS;
61         zcp->scripts = NULL;            /* created via zed_conf_scan_dir() */
62         zcp->state_fd = -1;             /* opened via zed_conf_open_state() */
63         zcp->zfs_hdl = NULL;            /* opened via zed_event_init() */
64         zcp->zevent_fd = -1;            /* opened via zed_event_init() */
65
66         if (!(zcp->conf_file = strdup(ZED_CONF_FILE)))
67                 goto nomem;
68
69         if (!(zcp->pid_file = strdup(ZED_PID_FILE)))
70                 goto nomem;
71
72         if (!(zcp->script_dir = strdup(ZED_SCRIPT_DIR)))
73                 goto nomem;
74
75         if (!(zcp->state_file = strdup(ZED_STATE_FILE)))
76                 goto nomem;
77
78         return (zcp);
79
80 nomem:
81         zed_log_die("Failed to create conf: %s", strerror(errno));
82         return (NULL);
83 }
84
85 /*
86  * Destroy the configuration [zcp].
87  *
88  * Note: zfs_hdl & zevent_fd are destroyed via zed_event_fini().
89  */
90 void
91 zed_conf_destroy(struct zed_conf *zcp)
92 {
93         if (!zcp)
94                 return;
95
96         if (zcp->state_fd >= 0) {
97                 if (close(zcp->state_fd) < 0)
98                         zed_log_msg(LOG_WARNING,
99                             "Failed to close state file \"%s\": %s",
100                             zcp->state_file, strerror(errno));
101         }
102         if (zcp->pid_file) {
103                 if ((unlink(zcp->pid_file) < 0) && (errno != ENOENT))
104                         zed_log_msg(LOG_WARNING,
105                             "Failed to remove PID file \"%s\": %s",
106                             zcp->pid_file, strerror(errno));
107         }
108         if (zcp->conf_file)
109                 free(zcp->conf_file);
110
111         if (zcp->pid_file)
112                 free(zcp->pid_file);
113
114         if (zcp->script_dir)
115                 free(zcp->script_dir);
116
117         if (zcp->state_file)
118                 free(zcp->state_file);
119
120         if (zcp->scripts)
121                 zed_strings_destroy(zcp->scripts);
122
123         free(zcp);
124 }
125
126 /*
127  * Display command-line help and exit.
128  *
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  *
311  * FIXME: Not yet implemented.
312  */
313 void
314 zed_conf_parse_file(struct zed_conf *zcp)
315 {
316         if (!zcp)
317                 zed_log_die("Failed to parse config: %s", strerror(EINVAL));
318 }
319
320 /*
321  * Scan the [zcp] script_dir for files to exec based on the event class.
322  * Files must be executable by user, but not writable by group or other.
323  * Dotfiles are ignored.
324  *
325  * Return 0 on success with an updated set of scripts,
326  * or -1 on error with errno set.
327  *
328  * FIXME: Check if script_dir and all parent dirs are secure.
329  */
330 int
331 zed_conf_scan_dir(struct zed_conf *zcp)
332 {
333         zed_strings_t *scripts;
334         DIR *dirp;
335         struct dirent *direntp;
336         char pathname[PATH_MAX];
337         struct stat st;
338         int n;
339
340         if (!zcp) {
341                 errno = EINVAL;
342                 zed_log_msg(LOG_ERR, "Failed to scan script dir: %s",
343                     strerror(errno));
344                 return (-1);
345         }
346         scripts = zed_strings_create();
347         if (!scripts) {
348                 errno = ENOMEM;
349                 zed_log_msg(LOG_WARNING, "Failed to scan dir \"%s\": %s",
350                     zcp->script_dir, strerror(errno));
351                 return (-1);
352         }
353         dirp = opendir(zcp->script_dir);
354         if (!dirp) {
355                 int errno_bak = errno;
356                 zed_log_msg(LOG_WARNING, "Failed to open dir \"%s\": %s",
357                     zcp->script_dir, strerror(errno));
358                 zed_strings_destroy(scripts);
359                 errno = errno_bak;
360                 return (-1);
361         }
362         while ((direntp = readdir(dirp))) {
363                 if (direntp->d_name[0] == '.')
364                         continue;
365
366                 n = snprintf(pathname, sizeof (pathname),
367                     "%s/%s", zcp->script_dir, direntp->d_name);
368                 if ((n < 0) || (n >= sizeof (pathname))) {
369                         zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s",
370                             direntp->d_name, strerror(ENAMETOOLONG));
371                         continue;
372                 }
373                 if (stat(pathname, &st) < 0) {
374                         zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s",
375                             pathname, strerror(errno));
376                         continue;
377                 }
378                 if (!S_ISREG(st.st_mode)) {
379                         zed_log_msg(LOG_INFO,
380                             "Ignoring \"%s\": not a regular file",
381                             direntp->d_name);
382                         continue;
383                 }
384                 if ((st.st_uid != 0) && !zcp->do_force) {
385                         zed_log_msg(LOG_NOTICE,
386                             "Ignoring \"%s\": not owned by root",
387                             direntp->d_name);
388                         continue;
389                 }
390                 if (!(st.st_mode & S_IXUSR)) {
391                         zed_log_msg(LOG_INFO,
392                             "Ignoring \"%s\": not executable by user",
393                             direntp->d_name);
394                         continue;
395                 }
396                 if ((st.st_mode & S_IWGRP) & !zcp->do_force) {
397                         zed_log_msg(LOG_NOTICE,
398                             "Ignoring \"%s\": writable by group",
399                             direntp->d_name);
400                         continue;
401                 }
402                 if ((st.st_mode & S_IWOTH) & !zcp->do_force) {
403                         zed_log_msg(LOG_NOTICE,
404                             "Ignoring \"%s\": writable by other",
405                             direntp->d_name);
406                         continue;
407                 }
408                 if (zed_strings_add(scripts, direntp->d_name) < 0) {
409                         zed_log_msg(LOG_WARNING,
410                             "Failed to register \"%s\": %s",
411                             direntp->d_name, strerror(errno));
412                         continue;
413                 }
414                 if (zcp->do_verbose)
415                         zed_log_msg(LOG_INFO,
416                             "Registered script \"%s\"", direntp->d_name);
417         }
418         if (closedir(dirp) < 0) {
419                 int errno_bak = errno;
420                 zed_log_msg(LOG_WARNING, "Failed to close dir \"%s\": %s",
421                     zcp->script_dir, strerror(errno));
422                 zed_strings_destroy(scripts);
423                 errno = errno_bak;
424                 return (-1);
425         }
426         if (zcp->scripts)
427                 zed_strings_destroy(zcp->scripts);
428
429         zcp->scripts = scripts;
430         return (0);
431 }
432
433 /*
434  * Write the PID file specified in [zcp].
435  * Return 0 on success, -1 on error.
436  *
437  * This must be called after fork()ing to become a daemon (so the correct PID
438  * is recorded), but before daemonization is complete and the parent process
439  * exits (for synchronization with systemd).
440  *
441  * FIXME: Only update the PID file after verifying the PID previously stored
442  * in the PID file no longer exists or belongs to a foreign process
443  * in order to ensure the daemon cannot be started more than once.
444  * (This check is currently done by zed_conf_open_state().)
445  */
446 int
447 zed_conf_write_pid(struct zed_conf *zcp)
448 {
449         char dirbuf[PATH_MAX];
450         mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
451         int n;
452         char *p;
453         mode_t mask;
454         FILE *fp;
455
456         if (!zcp || !zcp->pid_file) {
457                 errno = EINVAL;
458                 zed_log_msg(LOG_ERR, "Failed to write PID file: %s",
459                     strerror(errno));
460                 return (-1);
461         }
462         n = strlcpy(dirbuf, zcp->pid_file, sizeof (dirbuf));
463         if (n >= sizeof (dirbuf)) {
464                 errno = ENAMETOOLONG;
465                 zed_log_msg(LOG_WARNING, "Failed to write PID file: %s",
466                     strerror(errno));
467                 return (-1);
468         }
469         p = strrchr(dirbuf, '/');
470         if (p)
471                 *p = '\0';
472
473         if ((mkdirp(dirbuf, dirmode) < 0) && (errno != EEXIST)) {
474                 zed_log_msg(LOG_WARNING,
475                     "Failed to create directory \"%s\": %s",
476                     dirbuf, strerror(errno));
477                 return (-1);
478         }
479         (void) unlink(zcp->pid_file);
480
481         mask = umask(0);
482         umask(mask | 022);
483         fp = fopen(zcp->pid_file, "w");
484         umask(mask);
485
486         if (!fp) {
487                 zed_log_msg(LOG_WARNING, "Failed to open PID file \"%s\": %s",
488                     zcp->pid_file, strerror(errno));
489         } else if (fprintf(fp, "%d\n", (int) getpid()) == EOF) {
490                 zed_log_msg(LOG_WARNING, "Failed to write PID file \"%s\": %s",
491                     zcp->pid_file, strerror(errno));
492         } else if (fclose(fp) == EOF) {
493                 zed_log_msg(LOG_WARNING, "Failed to close PID file \"%s\": %s",
494                     zcp->pid_file, strerror(errno));
495         } else {
496                 return (0);
497         }
498         (void) unlink(zcp->pid_file);
499         return (-1);
500 }
501
502 /*
503  * Open and lock the [zcp] state_file.
504  * Return 0 on success, -1 on error.
505  *
506  * FIXME: If state_file exists, verify ownership & permissions.
507  * FIXME: Move lock to pid_file instead.
508  */
509 int
510 zed_conf_open_state(struct zed_conf *zcp)
511 {
512         char dirbuf[PATH_MAX];
513         mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
514         int n;
515         char *p;
516         int rv;
517
518         if (!zcp || !zcp->state_file) {
519                 errno = EINVAL;
520                 zed_log_msg(LOG_ERR, "Failed to open state file: %s",
521                     strerror(errno));
522                 return (-1);
523         }
524         n = strlcpy(dirbuf, zcp->state_file, sizeof (dirbuf));
525         if (n >= sizeof (dirbuf)) {
526                 errno = ENAMETOOLONG;
527                 zed_log_msg(LOG_WARNING, "Failed to open state file: %s",
528                     strerror(errno));
529                 return (-1);
530         }
531         p = strrchr(dirbuf, '/');
532         if (p)
533                 *p = '\0';
534
535         if ((mkdirp(dirbuf, dirmode) < 0) && (errno != EEXIST)) {
536                 zed_log_msg(LOG_WARNING,
537                     "Failed to create directory \"%s\": %s",
538                     dirbuf, strerror(errno));
539                 return (-1);
540         }
541         if (zcp->state_fd >= 0) {
542                 if (close(zcp->state_fd) < 0) {
543                         zed_log_msg(LOG_WARNING,
544                             "Failed to close state file \"%s\": %s",
545                             zcp->state_file, strerror(errno));
546                         return (-1);
547                 }
548         }
549         if (zcp->do_zero)
550                 (void) unlink(zcp->state_file);
551
552         zcp->state_fd = open(zcp->state_file,
553             (O_RDWR | O_CREAT), (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
554         if (zcp->state_fd < 0) {
555                 zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s",
556                     zcp->state_file, strerror(errno));
557                 return (-1);
558         }
559         rv = zed_file_lock(zcp->state_fd);
560         if (rv < 0) {
561                 zed_log_msg(LOG_WARNING, "Failed to lock state file \"%s\": %s",
562                     zcp->state_file, strerror(errno));
563                 return (-1);
564         }
565         if (rv > 0) {
566                 pid_t pid = zed_file_is_locked(zcp->state_fd);
567                 if (pid < 0) {
568                         zed_log_msg(LOG_WARNING,
569                             "Failed to test lock on state file \"%s\"",
570                             zcp->state_file);
571                 } else if (pid > 0) {
572                         zed_log_msg(LOG_WARNING,
573                             "Found PID %d bound to state file \"%s\"",
574                             pid, zcp->state_file);
575                 } else {
576                         zed_log_msg(LOG_WARNING,
577                             "Inconsistent lock state on state file \"%s\"",
578                             zcp->state_file);
579                 }
580                 return (-1);
581         }
582         return (0);
583 }
584
585 /*
586  * Read the opened [zcp] state_file to obtain the eid & etime of the last event
587  * processed.  Write the state from the last event to the [eidp] & [etime] args
588  * passed by reference.  Note that etime[] is an array of size 2.
589  * Return 0 on success, -1 on error.
590  */
591 int
592 zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[])
593 {
594         ssize_t len;
595         struct iovec iov[3];
596         ssize_t n;
597
598         if (!zcp || !eidp || !etime) {
599                 errno = EINVAL;
600                 zed_log_msg(LOG_ERR,
601                     "Failed to read state file: %s", strerror(errno));
602                 return (-1);
603         }
604         if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t) -1) {
605                 zed_log_msg(LOG_WARNING,
606                     "Failed to reposition state file offset: %s",
607                     strerror(errno));
608                 return (-1);
609         }
610         len = 0;
611         iov[0].iov_base = eidp;
612         len += iov[0].iov_len = sizeof (*eidp);
613         iov[1].iov_base = &etime[0];
614         len += iov[1].iov_len = sizeof (etime[0]);
615         iov[2].iov_base = &etime[1];
616         len += iov[2].iov_len = sizeof (etime[1]);
617
618         n = readv(zcp->state_fd, iov, 3);
619         if (n == 0) {
620                 *eidp = 0;
621         } else if (n < 0) {
622                 zed_log_msg(LOG_WARNING,
623                     "Failed to read state file \"%s\": %s",
624                     zcp->state_file, strerror(errno));
625                 return (-1);
626         } else if (n != len) {
627                 errno = EIO;
628                 zed_log_msg(LOG_WARNING,
629                     "Failed to read state file \"%s\": Read %d of %d bytes",
630                     zcp->state_file, n, len);
631                 return (-1);
632         }
633         return (0);
634 }
635
636 /*
637  * Write the [eid] & [etime] of the last processed event to the opened
638  * [zcp] state_file.  Note that etime[] is an array of size 2.
639  * Return 0 on success, -1 on error.
640  */
641 int
642 zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[])
643 {
644         ssize_t len;
645         struct iovec iov[3];
646         ssize_t n;
647
648         if (!zcp) {
649                 errno = EINVAL;
650                 zed_log_msg(LOG_ERR,
651                     "Failed to write state file: %s", strerror(errno));
652                 return (-1);
653         }
654         if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t) -1) {
655                 zed_log_msg(LOG_WARNING,
656                     "Failed to reposition state file offset: %s",
657                     strerror(errno));
658                 return (-1);
659         }
660         len = 0;
661         iov[0].iov_base = &eid;
662         len += iov[0].iov_len = sizeof (eid);
663         iov[1].iov_base = &etime[0];
664         len += iov[1].iov_len = sizeof (etime[0]);
665         iov[2].iov_base = &etime[1];
666         len += iov[2].iov_len = sizeof (etime[1]);
667
668         n = writev(zcp->state_fd, iov, 3);
669         if (n < 0) {
670                 zed_log_msg(LOG_WARNING,
671                     "Failed to write state file \"%s\": %s",
672                     zcp->state_file, strerror(errno));
673                 return (-1);
674         }
675         if (n != len) {
676                 errno = EIO;
677                 zed_log_msg(LOG_WARNING,
678                     "Failed to write state file \"%s\": Wrote %d of %d bytes",
679                     zcp->state_file, n, len);
680                 return (-1);
681         }
682         if (fdatasync(zcp->state_fd) < 0) {
683                 zed_log_msg(LOG_WARNING,
684                     "Failed to sync state file \"%s\": %s",
685                     zcp->state_file, strerror(errno));
686                 return (-1);
687         }
688         return (0);
689 }