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