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