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