Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/cmd/zed/zed_conf.c
48380 views
1
// SPDX-License-Identifier: CDDL-1.0
2
/*
3
* This file is part of the ZFS Event Daemon (ZED).
4
*
5
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
6
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
7
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
8
*
9
* The contents of this file are subject to the terms of the
10
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
11
* You can obtain a copy of the license from the top-level file
12
* "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
13
* You may not use this file except in compliance with the license.
14
*/
15
16
#include <assert.h>
17
#include <ctype.h>
18
#include <dirent.h>
19
#include <errno.h>
20
#include <fcntl.h>
21
#include <libgen.h>
22
#include <limits.h>
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <sys/types.h>
27
#include <sys/stat.h>
28
#include <sys/uio.h>
29
#include <unistd.h>
30
#include "zed.h"
31
#include "zed_conf.h"
32
#include "zed_file.h"
33
#include "zed_log.h"
34
#include "zed_strings.h"
35
36
/*
37
* Initialise the configuration with default values.
38
*/
39
void
40
zed_conf_init(struct zed_conf *zcp)
41
{
42
memset(zcp, 0, sizeof (*zcp));
43
44
/* zcp->zfs_hdl opened in zed_event_init() */
45
/* zcp->zedlets created in zed_conf_scan_dir() */
46
47
zcp->pid_fd = -1; /* opened in zed_conf_write_pid() */
48
zcp->state_fd = -1; /* opened in zed_conf_open_state() */
49
zcp->zevent_fd = -1; /* opened in zed_event_init() */
50
51
zcp->max_jobs = 16;
52
zcp->max_zevent_buf_len = 1 << 20;
53
54
if (!(zcp->pid_file = strdup(ZED_PID_FILE)) ||
55
!(zcp->zedlet_dir = strdup(ZED_ZEDLET_DIR)) ||
56
!(zcp->state_file = strdup(ZED_STATE_FILE)))
57
zed_log_die("Failed to create conf: %s", strerror(errno));
58
}
59
60
/*
61
* Destroy the configuration [zcp].
62
*
63
* Note: zfs_hdl & zevent_fd are destroyed via zed_event_fini().
64
*/
65
void
66
zed_conf_destroy(struct zed_conf *zcp)
67
{
68
if (zcp->state_fd >= 0) {
69
if (close(zcp->state_fd) < 0)
70
zed_log_msg(LOG_WARNING,
71
"Failed to close state file \"%s\": %s",
72
zcp->state_file, strerror(errno));
73
zcp->state_fd = -1;
74
}
75
if (zcp->pid_file) {
76
if ((unlink(zcp->pid_file) < 0) && (errno != ENOENT))
77
zed_log_msg(LOG_WARNING,
78
"Failed to remove PID file \"%s\": %s",
79
zcp->pid_file, strerror(errno));
80
}
81
if (zcp->pid_fd >= 0) {
82
if (close(zcp->pid_fd) < 0)
83
zed_log_msg(LOG_WARNING,
84
"Failed to close PID file \"%s\": %s",
85
zcp->pid_file, strerror(errno));
86
zcp->pid_fd = -1;
87
}
88
if (zcp->pid_file) {
89
free(zcp->pid_file);
90
zcp->pid_file = NULL;
91
}
92
if (zcp->zedlet_dir) {
93
free(zcp->zedlet_dir);
94
zcp->zedlet_dir = NULL;
95
}
96
if (zcp->state_file) {
97
free(zcp->state_file);
98
zcp->state_file = NULL;
99
}
100
if (zcp->zedlets) {
101
zed_strings_destroy(zcp->zedlets);
102
zcp->zedlets = NULL;
103
}
104
}
105
106
/*
107
* Display command-line help and exit.
108
*
109
* If [got_err] is 0, output to stdout and exit normally;
110
* otherwise, output to stderr and exit with a failure status.
111
*/
112
static void
113
_zed_conf_display_help(const char *prog, boolean_t got_err)
114
{
115
struct opt { const char *o, *d, *v; };
116
117
FILE *fp = got_err ? stderr : stdout;
118
119
struct opt *oo;
120
struct opt iopts[] = {
121
{ .o = "-h", .d = "Display help" },
122
{ .o = "-L", .d = "Display license information" },
123
{ .o = "-V", .d = "Display version information" },
124
{},
125
};
126
struct opt nopts[] = {
127
{ .o = "-v", .d = "Be verbose" },
128
{ .o = "-f", .d = "Force daemon to run" },
129
{ .o = "-F", .d = "Run daemon in the foreground" },
130
{ .o = "-I",
131
.d = "Idle daemon until kernel module is (re)loaded" },
132
{ .o = "-M", .d = "Lock all pages in memory" },
133
{ .o = "-P", .d = "$PATH for ZED to use (only used by ZTS)" },
134
{ .o = "-Z", .d = "Zero state file" },
135
{},
136
};
137
struct opt vopts[] = {
138
{ .o = "-d DIR", .d = "Read enabled ZEDLETs from DIR.",
139
.v = ZED_ZEDLET_DIR },
140
{ .o = "-p FILE", .d = "Write daemon's PID to FILE.",
141
.v = ZED_PID_FILE },
142
{ .o = "-s FILE", .d = "Write daemon's state to FILE.",
143
.v = ZED_STATE_FILE },
144
{ .o = "-j JOBS", .d = "Start at most JOBS at once.",
145
.v = "16" },
146
{ .o = "-b LEN", .d = "Cap kernel event buffer at LEN entries.",
147
.v = "1048576" },
148
{},
149
};
150
151
fprintf(fp, "Usage: %s [OPTION]...\n", (prog ? prog : "zed"));
152
fprintf(fp, "\n");
153
for (oo = iopts; oo->o; ++oo)
154
fprintf(fp, " %*s %s\n", -8, oo->o, oo->d);
155
fprintf(fp, "\n");
156
for (oo = nopts; oo->o; ++oo)
157
fprintf(fp, " %*s %s\n", -8, oo->o, oo->d);
158
fprintf(fp, "\n");
159
for (oo = vopts; oo->o; ++oo)
160
fprintf(fp, " %*s %s [%s]\n", -8, oo->o, oo->d, oo->v);
161
fprintf(fp, "\n");
162
163
exit(got_err ? EXIT_FAILURE : EXIT_SUCCESS);
164
}
165
166
/*
167
* Display license information to stdout and exit.
168
*/
169
static void
170
_zed_conf_display_license(void)
171
{
172
printf(
173
"The ZFS Event Daemon (ZED) is distributed under the terms of the\n"
174
" Common Development and Distribution License (CDDL-1.0)\n"
175
" <http://opensource.org/licenses/CDDL-1.0>.\n"
176
"\n"
177
"Developed at Lawrence Livermore National Laboratory"
178
" (LLNL-CODE-403049).\n"
179
"\n");
180
181
exit(EXIT_SUCCESS);
182
}
183
184
/*
185
* Display version information to stdout and exit.
186
*/
187
static void
188
_zed_conf_display_version(void)
189
{
190
printf("%s-%s-%s\n",
191
ZFS_META_NAME, ZFS_META_VERSION, ZFS_META_RELEASE);
192
193
exit(EXIT_SUCCESS);
194
}
195
196
/*
197
* Copy the [path] string to the [resultp] ptr.
198
* If [path] is not an absolute path, prefix it with the current working dir.
199
* If [resultp] is non-null, free its existing string before assignment.
200
*/
201
static void
202
_zed_conf_parse_path(char **resultp, const char *path)
203
{
204
char buf[PATH_MAX];
205
206
assert(resultp != NULL);
207
assert(path != NULL);
208
209
if (*resultp)
210
free(*resultp);
211
212
if (path[0] == '/') {
213
*resultp = strdup(path);
214
} else {
215
if (!getcwd(buf, sizeof (buf)))
216
zed_log_die("Failed to get current working dir: %s",
217
strerror(errno));
218
219
if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf) ||
220
strlcat(buf, path, sizeof (buf)) >= sizeof (buf))
221
zed_log_die("Failed to copy path: %s",
222
strerror(ENAMETOOLONG));
223
224
*resultp = strdup(buf);
225
}
226
227
if (!*resultp)
228
zed_log_die("Failed to copy path: %s", strerror(ENOMEM));
229
}
230
231
/*
232
* Parse the command-line options into the configuration [zcp].
233
*/
234
void
235
zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
236
{
237
const char * const opts = ":hLVd:p:P:s:vfFMZIj:b:";
238
int opt;
239
unsigned long raw;
240
241
if (!zcp || !argv || !argv[0])
242
zed_log_die("Failed to parse options: Internal error");
243
244
opterr = 0; /* suppress default getopt err msgs */
245
246
while ((opt = getopt(argc, argv, opts)) != -1) {
247
switch (opt) {
248
case 'h':
249
_zed_conf_display_help(argv[0], B_FALSE);
250
break;
251
case 'L':
252
_zed_conf_display_license();
253
break;
254
case 'V':
255
_zed_conf_display_version();
256
break;
257
case 'd':
258
_zed_conf_parse_path(&zcp->zedlet_dir, optarg);
259
break;
260
case 'I':
261
zcp->do_idle = 1;
262
break;
263
case 'p':
264
_zed_conf_parse_path(&zcp->pid_file, optarg);
265
break;
266
case 'P':
267
_zed_conf_parse_path(&zcp->path, optarg);
268
break;
269
case 's':
270
_zed_conf_parse_path(&zcp->state_file, optarg);
271
break;
272
case 'v':
273
zcp->do_verbose = 1;
274
break;
275
case 'f':
276
zcp->do_force = 1;
277
break;
278
case 'F':
279
zcp->do_foreground = 1;
280
break;
281
case 'M':
282
zcp->do_memlock = 1;
283
break;
284
case 'Z':
285
zcp->do_zero = 1;
286
break;
287
case 'j':
288
errno = 0;
289
raw = strtoul(optarg, NULL, 0);
290
if (errno == ERANGE || raw > INT16_MAX) {
291
zed_log_die("%lu is too many jobs", raw);
292
} if (raw == 0) {
293
zed_log_die("0 jobs makes no sense");
294
} else {
295
zcp->max_jobs = raw;
296
}
297
break;
298
case 'b':
299
errno = 0;
300
raw = strtoul(optarg, NULL, 0);
301
if (errno == ERANGE || raw > INT32_MAX) {
302
zed_log_die("%lu is too large", raw);
303
} if (raw == 0) {
304
zcp->max_zevent_buf_len = INT32_MAX;
305
} else {
306
zcp->max_zevent_buf_len = raw;
307
}
308
break;
309
case '?':
310
default:
311
if (optopt == '?')
312
_zed_conf_display_help(argv[0], B_FALSE);
313
314
fprintf(stderr, "%s: Invalid option '-%c'\n\n",
315
argv[0], optopt);
316
_zed_conf_display_help(argv[0], B_TRUE);
317
break;
318
}
319
}
320
}
321
322
/*
323
* Scan the [zcp] zedlet_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 zedlets,
328
* or -1 on error with errno set.
329
*/
330
int
331
zed_conf_scan_dir(struct zed_conf *zcp)
332
{
333
zed_strings_t *zedlets;
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 zedlet dir: %s",
343
strerror(errno));
344
return (-1);
345
}
346
zedlets = zed_strings_create();
347
if (!zedlets) {
348
errno = ENOMEM;
349
zed_log_msg(LOG_WARNING, "Failed to scan dir \"%s\": %s",
350
zcp->zedlet_dir, strerror(errno));
351
return (-1);
352
}
353
dirp = opendir(zcp->zedlet_dir);
354
if (!dirp) {
355
int errno_bak = errno;
356
zed_log_msg(LOG_WARNING, "Failed to open dir \"%s\": %s",
357
zcp->zedlet_dir, strerror(errno));
358
zed_strings_destroy(zedlets);
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->zedlet_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(zedlets, NULL, 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 zedlet \"%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->zedlet_dir, strerror(errno));
422
zed_strings_destroy(zedlets);
423
errno = errno_bak;
424
return (-1);
425
}
426
if (zcp->zedlets)
427
zed_strings_destroy(zcp->zedlets);
428
429
zcp->zedlets = zedlets;
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
int
442
zed_conf_write_pid(struct zed_conf *zcp)
443
{
444
char buf[PATH_MAX];
445
int n;
446
char *p;
447
mode_t mask;
448
int rv;
449
450
if (!zcp || !zcp->pid_file) {
451
errno = EINVAL;
452
zed_log_msg(LOG_ERR, "Failed to create PID file: %s",
453
strerror(errno));
454
return (-1);
455
}
456
assert(zcp->pid_fd == -1);
457
/*
458
* Create PID file directory if needed.
459
*/
460
n = strlcpy(buf, zcp->pid_file, sizeof (buf));
461
if (n >= sizeof (buf)) {
462
errno = ENAMETOOLONG;
463
zed_log_msg(LOG_ERR, "Failed to create PID file: %s",
464
strerror(errno));
465
goto err;
466
}
467
p = strrchr(buf, '/');
468
if (p)
469
*p = '\0';
470
471
if ((mkdirp(buf, 0755) < 0) && (errno != EEXIST)) {
472
zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s",
473
buf, strerror(errno));
474
goto err;
475
}
476
/*
477
* Obtain PID file lock.
478
*/
479
mask = umask(0);
480
umask(mask | 022);
481
zcp->pid_fd = open(zcp->pid_file, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
482
umask(mask);
483
if (zcp->pid_fd < 0) {
484
zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s",
485
zcp->pid_file, strerror(errno));
486
goto err;
487
}
488
rv = zed_file_lock(zcp->pid_fd);
489
if (rv < 0) {
490
zed_log_msg(LOG_ERR, "Failed to lock PID file \"%s\": %s",
491
zcp->pid_file, strerror(errno));
492
goto err;
493
} else if (rv > 0) {
494
pid_t pid = zed_file_is_locked(zcp->pid_fd);
495
if (pid < 0) {
496
zed_log_msg(LOG_ERR,
497
"Failed to test lock on PID file \"%s\"",
498
zcp->pid_file);
499
} else if (pid > 0) {
500
zed_log_msg(LOG_ERR,
501
"Found PID %d bound to PID file \"%s\"",
502
pid, zcp->pid_file);
503
} else {
504
zed_log_msg(LOG_ERR,
505
"Inconsistent lock state on PID file \"%s\"",
506
zcp->pid_file);
507
}
508
goto err;
509
}
510
/*
511
* Write PID file.
512
*/
513
n = snprintf(buf, sizeof (buf), "%d\n", (int)getpid());
514
if ((n < 0) || (n >= sizeof (buf))) {
515
errno = ERANGE;
516
zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
517
zcp->pid_file, strerror(errno));
518
} else if (write(zcp->pid_fd, buf, n) != n) {
519
zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
520
zcp->pid_file, strerror(errno));
521
} else if (fdatasync(zcp->pid_fd) < 0) {
522
zed_log_msg(LOG_ERR, "Failed to sync PID file \"%s\": %s",
523
zcp->pid_file, strerror(errno));
524
} else {
525
return (0);
526
}
527
528
err:
529
if (zcp->pid_fd >= 0) {
530
(void) close(zcp->pid_fd);
531
zcp->pid_fd = -1;
532
}
533
return (-1);
534
}
535
536
/*
537
* Open and lock the [zcp] state_file.
538
* Return 0 on success, -1 on error.
539
*
540
* FIXME: Move state information into kernel.
541
*/
542
int
543
zed_conf_open_state(struct zed_conf *zcp)
544
{
545
char dirbuf[PATH_MAX];
546
int n;
547
char *p;
548
int rv;
549
550
if (!zcp || !zcp->state_file) {
551
errno = EINVAL;
552
zed_log_msg(LOG_ERR, "Failed to open state file: %s",
553
strerror(errno));
554
return (-1);
555
}
556
n = strlcpy(dirbuf, zcp->state_file, sizeof (dirbuf));
557
if (n >= sizeof (dirbuf)) {
558
errno = ENAMETOOLONG;
559
zed_log_msg(LOG_WARNING, "Failed to open state file: %s",
560
strerror(errno));
561
return (-1);
562
}
563
p = strrchr(dirbuf, '/');
564
if (p)
565
*p = '\0';
566
567
if ((mkdirp(dirbuf, 0755) < 0) && (errno != EEXIST)) {
568
zed_log_msg(LOG_WARNING,
569
"Failed to create directory \"%s\": %s",
570
dirbuf, strerror(errno));
571
return (-1);
572
}
573
if (zcp->state_fd >= 0) {
574
if (close(zcp->state_fd) < 0) {
575
zed_log_msg(LOG_WARNING,
576
"Failed to close state file \"%s\": %s",
577
zcp->state_file, strerror(errno));
578
return (-1);
579
}
580
}
581
if (zcp->do_zero)
582
(void) unlink(zcp->state_file);
583
584
zcp->state_fd = open(zcp->state_file,
585
O_RDWR | O_CREAT | O_CLOEXEC, 0644);
586
if (zcp->state_fd < 0) {
587
zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s",
588
zcp->state_file, strerror(errno));
589
return (-1);
590
}
591
rv = zed_file_lock(zcp->state_fd);
592
if (rv < 0) {
593
zed_log_msg(LOG_WARNING, "Failed to lock state file \"%s\": %s",
594
zcp->state_file, strerror(errno));
595
return (-1);
596
}
597
if (rv > 0) {
598
pid_t pid = zed_file_is_locked(zcp->state_fd);
599
if (pid < 0) {
600
zed_log_msg(LOG_WARNING,
601
"Failed to test lock on state file \"%s\"",
602
zcp->state_file);
603
} else if (pid > 0) {
604
zed_log_msg(LOG_WARNING,
605
"Found PID %d bound to state file \"%s\"",
606
pid, zcp->state_file);
607
} else {
608
zed_log_msg(LOG_WARNING,
609
"Inconsistent lock state on state file \"%s\"",
610
zcp->state_file);
611
}
612
return (-1);
613
}
614
return (0);
615
}
616
617
/*
618
* Read the opened [zcp] state_file to obtain the eid & etime of the last event
619
* processed. Write the state from the last event to the [eidp] & [etime] args
620
* passed by reference. Note that etime[] is an array of size 2.
621
* Return 0 on success, -1 on error.
622
*/
623
int
624
zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[])
625
{
626
ssize_t len;
627
struct iovec iov[3];
628
ssize_t n;
629
630
if (!zcp || !eidp || !etime) {
631
errno = EINVAL;
632
zed_log_msg(LOG_ERR,
633
"Failed to read state file: %s", strerror(errno));
634
return (-1);
635
}
636
if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t)-1) {
637
zed_log_msg(LOG_WARNING,
638
"Failed to reposition state file offset: %s",
639
strerror(errno));
640
return (-1);
641
}
642
len = 0;
643
iov[0].iov_base = eidp;
644
len += iov[0].iov_len = sizeof (*eidp);
645
iov[1].iov_base = &etime[0];
646
len += iov[1].iov_len = sizeof (etime[0]);
647
iov[2].iov_base = &etime[1];
648
len += iov[2].iov_len = sizeof (etime[1]);
649
650
n = readv(zcp->state_fd, iov, 3);
651
if (n == 0) {
652
*eidp = 0;
653
} else if (n < 0) {
654
zed_log_msg(LOG_WARNING,
655
"Failed to read state file \"%s\": %s",
656
zcp->state_file, strerror(errno));
657
return (-1);
658
} else if (n != len) {
659
errno = EIO;
660
zed_log_msg(LOG_WARNING,
661
"Failed to read state file \"%s\": Read %zd of %zd bytes",
662
zcp->state_file, n, len);
663
return (-1);
664
}
665
return (0);
666
}
667
668
/*
669
* Write the [eid] & [etime] of the last processed event to the opened
670
* [zcp] state_file. Note that etime[] is an array of size 2.
671
* Return 0 on success, -1 on error.
672
*/
673
int
674
zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[])
675
{
676
ssize_t len;
677
struct iovec iov[3];
678
ssize_t n;
679
680
if (!zcp) {
681
errno = EINVAL;
682
zed_log_msg(LOG_ERR,
683
"Failed to write state file: %s", strerror(errno));
684
return (-1);
685
}
686
if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t)-1) {
687
zed_log_msg(LOG_WARNING,
688
"Failed to reposition state file offset: %s",
689
strerror(errno));
690
return (-1);
691
}
692
len = 0;
693
iov[0].iov_base = &eid;
694
len += iov[0].iov_len = sizeof (eid);
695
iov[1].iov_base = &etime[0];
696
len += iov[1].iov_len = sizeof (etime[0]);
697
iov[2].iov_base = &etime[1];
698
len += iov[2].iov_len = sizeof (etime[1]);
699
700
n = writev(zcp->state_fd, iov, 3);
701
if (n < 0) {
702
zed_log_msg(LOG_WARNING,
703
"Failed to write state file \"%s\": %s",
704
zcp->state_file, strerror(errno));
705
return (-1);
706
}
707
if (n != len) {
708
errno = EIO;
709
zed_log_msg(LOG_WARNING,
710
"Failed to write state file \"%s\": Wrote %zd of %zd bytes",
711
zcp->state_file, n, len);
712
return (-1);
713
}
714
if (fdatasync(zcp->state_fd) < 0) {
715
zed_log_msg(LOG_WARNING,
716
"Failed to sync state file \"%s\": %s",
717
zcp->state_file, strerror(errno));
718
return (-1);
719
}
720
return (0);
721
}
722
723