1/*
2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
4 */
5
6/*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 	- Redistributions of source code must retain the above copyright
15 *	  notice, this list of conditions and the following disclaimer.
16 *
17 * 	- Redistributions in binary form must reproduce the above copyright
18 *	  notice, this list of conditions and the following disclaimer in
19 *	  the documentation and/or other materials provided with the
20 *	  distribution.
21 *
22 *	- Neither the name of The Storage Networking Industry Association (SNIA)
23 *	  nor the names of its contributors may be used to endorse or promote
24 *	  products derived from this software without specific prior written
25 *	  permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39/* Copyright (c) 2007, The Storage Networking Industry Association. */
40/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41
42#include <sys/types.h>
43#include <sys/param.h>
44#include <sys/lwp.h>
45#include <sys/fs/zfs.h>
46#include <sys/mtio.h>
47#include <sys/time.h>
48#include <unistd.h>
49#include <errno.h>
50#include <stdlib.h>
51#include <string.h>
52#include <ctype.h>
53#include <libzfs.h>
54#include <stdio.h>
55#include "ndmpd_common.h"
56#include "ndmpd.h"
57
58typedef struct {
59	char nzs_findprop[ZFS_MAXPROPLEN]; /* prop substring to find */
60	char nzs_snapname[ZFS_MAX_DATASET_NAME_LEN]; /* snap's name */
61	char nzs_snapprop[ZFS_MAXPROPLEN]; /* snap's prop value */
62	char nzs_snapskip[ZFS_MAXPROPLEN]; /* snap to skip */
63	uint32_t nzs_prop_major;	   /* property major version */
64	uint32_t nzs_prop_minor;	   /* property minor version */
65} ndmpd_zfs_snapfind_t;
66
67mutex_t ndmpd_zfs_fd_lock;
68
69static int ndmpd_zfs_open_fds(ndmpd_zfs_args_t *);
70static void ndmpd_zfs_close_fds(ndmpd_zfs_args_t *);
71
72static void ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *, int);
73
74static int ndmpd_zfs_header_write(ndmpd_session_t *);
75static int ndmpd_zfs_header_read(ndmpd_zfs_args_t *);
76
77static int ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *);
78static int ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *);
79
80static int ndmpd_zfs_restore(ndmpd_zfs_args_t *);
81static int ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *);
82static int ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *);
83
84static int ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *, int **, int **);
85
86static int ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *, u_longlong_t);
87
88static boolean_t ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *);
89static int ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *, char *, int);
90static int ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *);
91
92static boolean_t ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *);
93static int ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *);
94static int ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *);
95
96static int ndmpd_zfs_getenv(ndmpd_zfs_args_t *);
97static int ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *);
98static int ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *);
99static int ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *);
100static int ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *);
101static int ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *);
102static int ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *);
103
104static boolean_t ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *, char *);
105static boolean_t ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *);
106static int ndmpd_zfs_send_fhist(ndmpd_zfs_args_t *);
107
108static int ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *);
109static int ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *, int);
110static int ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *);
111static int ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *,
112    boolean_t, ndmpd_zfs_snapfind_t *);
113static boolean_t ndmpd_zfs_snapshot_ndmpd_generated(char *);
114static int ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *, ndmpd_zfs_snapfind_t *);
115
116static int ndmpd_zfs_snapshot_prop_find(zfs_handle_t *, void *);
117static int ndmpd_zfs_snapshot_prop_get(zfs_handle_t *, char *);
118static int ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *);
119static int ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *, char *,
120    boolean_t *);
121static int ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *, char *, int,
122    boolean_t);
123static int ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *,
124    ndmpd_zfs_snapfind_t *);
125static boolean_t ndmpd_zfs_prop_version_check(char *, uint32_t *, uint32_t *);
126
127static int ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *, char *, int);
128
129static void ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *);
130
131static int ndmpd_zfs_backup(ndmpd_zfs_args_t *);
132
133/*
134 * Syntax for com.sun.ndmp:incr property value:
135 *	#.#.n|u/$LEVEL.$DMP_NAME.$ZFS_MODE(/ ...)
136 *
137 * where
138 *	#.# is the version number
139 *	'n' means ndmp-generated; 'u' means user-supplied
140 *	$LEVEL: backup (incremental) level [0-9]
141 *	$DMP_NAME: set name [default: "level"]
142 *	$ZFS_MODE: d | r | p [for dataset, recursive, or package]
143 *
144 * Examples:
145 *
146 * 	0.0.n/0.bob.p
147 * 	0.0.u/1.bob.p/0.jane.d
148 *
149 * Note: NDMPD_ZFS_SUBPROP_MAX is calculated based on ZFS_MAXPROPLEN
150 */
151
152#define	NDMPD_ZFS_PROP_INCR "com.sun.ndmp:incr"
153#define	NDMPD_ZFS_SUBPROP_MAX	28
154
155/*
156 * NDMPD_ZFS_LOG_ZERR
157 *
158 * As coded, there should be no races in the retrieval of the ZFS errno
159 * from the ndmpd_zfs_args->nz_zlibh.  I.e., for a given ndmpd_zfs backup
160 * or restore, there should only ever be one ZFS library call taking place
161 * at any one moment in time.
162 */
163
164#define	NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, ...) {			\
165	NDMP_LOG(LOG_ERR, __VA_ARGS__);					\
166	NDMP_LOG(LOG_ERR, "%s--%s",					\
167	    libzfs_error_action((ndmpd_zfs_args)->nz_zlibh),           	\
168	    libzfs_error_description((ndmpd_zfs_args)->nz_zlibh));     	\
169	ndmpd_zfs_zerr_dma_log((ndmpd_zfs_args));			\
170}
171
172int
173ndmpd_zfs_init(ndmpd_session_t *session)
174{
175	ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
176	int version = session->ns_protocol_version;
177
178	bzero(ndmpd_zfs_args, sizeof (*ndmpd_zfs_args));
179
180	if ((version < NDMPV3) || (version > NDMPV4)) {
181		NDMP_LOG(LOG_ERR, "Unknown or unsupported version %d", version);
182		return (-1);
183	}
184
185	if ((ndmpd_zfs_args->nz_zlibh = libzfs_init()) == NULL) {
186		NDMP_LOG(LOG_ERR, "libzfs init error [%d]", errno);
187		return (-1);
188	}
189
190	if (ndmpd_zfs_open_fds(ndmpd_zfs_args) < 0) {
191		NDMP_LOG(LOG_ERR, "open_fds() failure(): %d\n", errno);
192		return (-1);
193	}
194
195	ndmpd_zfs_args->nz_bufsize = ndmp_buffer_get_size(session);
196	ndmpd_zfs_args->nz_window_len = session->ns_mover.md_window_length;
197
198	ndmpd_zfs_args->nz_nlp = ndmp_get_nlp(session);
199
200	assert(ndmpd_zfs_args->nz_nlp != NULL);
201
202	ndmpd_zfs_args->nz_nlp->nlp_bytes_total = 0;
203
204	session->ns_data.dd_module.dm_module_cookie = ndmpd_zfs_args;
205	session->ns_data.dd_data_size = 0;
206	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
207	session->ns_data.dd_module.dm_stats.ms_est_time_remaining  = 0;
208
209	session->ns_data.dd_bytes_left_to_read = 0;
210	session->ns_data.dd_position = 0;
211	session->ns_data.dd_discard_length = 0;
212	session->ns_data.dd_read_offset = 0;
213	session->ns_data.dd_read_length = 0;
214
215	ndmpd_zfs_params->mp_get_env_func = ndmpd_api_get_env;
216	ndmpd_zfs_params->mp_add_env_func = ndmpd_api_add_env;
217	ndmpd_zfs_params->mp_set_env_func = ndmpd_api_set_env;
218	ndmpd_zfs_params->mp_dispatch_func = ndmpd_api_dispatch;
219	ndmpd_zfs_params->mp_daemon_cookie = (void *)session;
220	ndmpd_zfs_params->mp_protocol_version = session->ns_protocol_version;
221	ndmpd_zfs_params->mp_stats = &session->ns_data.dd_module.dm_stats;
222	ndmpd_zfs_params->mp_add_file_handler_func =
223	    ndmpd_api_add_file_handler;
224	ndmpd_zfs_params->mp_remove_file_handler_func =
225	    ndmpd_api_remove_file_handler;
226	ndmpd_zfs_params->mp_seek_func = 0;
227
228	switch (version) {
229	case NDMPV3:
230		ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
231		ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
232		ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
233		ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
234		ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v3;
235		ndmpd_zfs_params->mp_file_recovered_func =
236		    ndmpd_api_file_recovered_v3;
237		break;
238	case NDMPV4:
239		ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
240		ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
241		ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
242		ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
243		ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v4;
244		ndmpd_zfs_params->mp_file_recovered_func =
245		    ndmpd_api_file_recovered_v4;
246		break;
247	default:
248		/* error already returned above for this case */
249		break;
250	}
251
252	return (0);
253}
254
255void
256ndmpd_zfs_fini(ndmpd_zfs_args_t *ndmpd_zfs_args)
257{
258	libzfs_fini(ndmpd_zfs_args->nz_zlibh);
259
260	ndmpd_zfs_close_fds(ndmpd_zfs_args);
261}
262
263static int
264ndmpd_zfs_open_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
265{
266	int err;
267
268	err = pipe(ndmpd_zfs_args->nz_pipe_fd);
269	if (err)
270		NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n", strerror(errno));
271
272	return (err);
273}
274
275/*
276 * ndmpd_zfs_close_fds()
277 *
278 * In the abort case, use dup2() to redirect the end of the pipe that is
279 * being written to (to a new pipe).  Close the ends of the new pipe to cause
280 * EPIPE to be returned to the writing thread.  This will cause the writer
281 * and reader to terminate without having any of the writer's data erroneously
282 * go to any reopened descriptor.
283 */
284
285static void
286ndmpd_zfs_close_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
287{
288	ndmpd_session_t *session = (ndmpd_session_t *)
289	    (ndmpd_zfs_params->mp_daemon_cookie);
290	int pipe_end;
291	int fds[2];
292
293	if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE) {
294		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
295		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
296		return;
297	}
298
299	(void) mutex_lock(&ndmpd_zfs_fd_lock);
300
301	if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) {
302		pipe_end = PIPE_ZFS;
303	} else {
304		pipe_end = PIPE_TAPE;
305	}
306
307	if (ndmpd_zfs_args->nz_pipe_fd[pipe_end] != -1) {
308		if (pipe(fds) != 0) {
309			(void) mutex_unlock(&ndmpd_zfs_fd_lock);
310			NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n",
311			    strerror(errno));
312			return;
313		}
314
315		(void) dup2(fds[0], ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
316		(void) close(fds[0]);
317		(void) close(fds[1]);
318
319		ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
320	}
321
322	(void) mutex_unlock(&ndmpd_zfs_fd_lock);
323}
324
325static void
326ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *ndmpd_zfs_args, int pipe_end)
327{
328	(void) mutex_lock(&ndmpd_zfs_fd_lock);
329	(void) close(ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
330	ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
331	(void) mutex_unlock(&ndmpd_zfs_fd_lock);
332}
333
334static int
335ndmpd_zfs_header_write(ndmpd_session_t *session)
336{
337	ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
338	int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
339	ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
340	char *buf;
341
342	buf = ndmp_malloc(bufsize);
343	if (buf == NULL) {
344		NDMP_LOG(LOG_DEBUG, "buf NULL");
345		return (-1);
346	}
347
348	(void) strlcpy(tape_header->nzh_magic, NDMPUTF8MAGIC,
349	    sizeof (NDMPUTF8MAGIC));
350	tape_header->nzh_major = LE_32(NDMPD_ZFS_MAJOR_VERSION);
351	tape_header->nzh_minor = LE_32(NDMPD_ZFS_MINOR_VERSION);
352	tape_header->nzh_hdrlen = LE_32(bufsize);
353
354	bzero(buf, bufsize);
355	(void) memcpy(buf, tape_header, sizeof (ndmpd_zfs_header_t));
356
357	NDMP_LOG(LOG_DEBUG, "header (major, minor, length): %u %u %u",
358	    NDMPD_ZFS_MAJOR_VERSION,
359	    NDMPD_ZFS_MINOR_VERSION,
360	    bufsize);
361
362	if (MOD_WRITE(ndmpd_zfs_params, buf, bufsize) != 0) {
363		free(buf);
364		NDMP_LOG(LOG_ERR, "MOD_WRITE error");
365		return (-1);
366	}
367
368	free(buf);
369
370	session->ns_data.dd_module.dm_stats.ms_bytes_processed = bufsize;
371
372	return (0);
373}
374
375static int
376ndmpd_zfs_header_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
377{
378	int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
379	ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
380	uint32_t hdrlen;
381	int32_t header_left;
382	int err;
383	char *buf;
384
385	buf = ndmp_malloc(bufsize);
386	if (buf == NULL) {
387		NDMP_LOG(LOG_DEBUG, "buf NULL");
388		return (-1);
389	}
390
391	bzero(buf, bufsize);
392
393	/*
394	 * Read nz_bufsize worth of bytes first (the size of a mover record).
395	 */
396
397	err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
398
399	if (err != 0) {
400		NDMP_LOG(LOG_ERR, "MOD_READ error: %d", err);
401		free(buf);
402		return (-1);
403	}
404
405	(void) memcpy(tape_header, buf, sizeof (ndmpd_zfs_header_t));
406
407	if (strcmp(tape_header->nzh_magic, NDMPUTF8MAGIC) != 0) {
408		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
409		    "bad magic string\n");
410		goto _err;
411	}
412
413	if (tape_header->nzh_major > LE_32(NDMPD_ZFS_MAJOR_VERSION)) {
414		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
415		    "major number larger than supported: (%d %d)\n",
416		    LE_32(tape_header->nzh_major), NDMPD_ZFS_MAJOR_VERSION);
417		goto _err;
418	}
419
420	/*
421	 * Major version 0 (regardless of minor version):
422	 * Header must be a multiple of the mover record size.
423	 */
424
425	hdrlen = LE_32(tape_header->nzh_hdrlen);
426	if (hdrlen > bufsize) {
427		header_left = hdrlen - bufsize;
428		while (header_left > 0) {
429			err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
430			if (err == -1) {
431				ndmpd_zfs_dma_log(ndmpd_zfs_args,
432				    NDMP_LOG_ERROR, "bad header\n");
433				goto _err;
434			}
435			header_left -= bufsize;
436		}
437	}
438
439	NDMP_LOG(LOG_DEBUG, "tape header: %s; %u %u; %u ",
440	    tape_header->nzh_magic,
441	    LE_32(tape_header->nzh_major),
442	    LE_32(tape_header->nzh_minor),
443	    LE_32(tape_header->nzh_hdrlen));
444
445	ndmpd_zfs_args->nz_nlp->nlp_bytes_total = hdrlen;
446
447	free(buf);
448	return (0);
449
450_err:
451
452	NDMP_LOG(LOG_ERR, "tape header: %s; %u %u; %u ",
453	    tape_header->nzh_magic,
454	    LE_32(tape_header->nzh_major),
455	    LE_32(tape_header->nzh_minor),
456	    LE_32(tape_header->nzh_hdrlen));
457
458	free(buf);
459	return (-1);
460}
461
462int
463ndmpd_zfs_backup_starter(void *arg)
464{
465	ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
466	ndmpd_session_t *session = (ndmpd_session_t *)
467	    (ndmpd_zfs_params->mp_daemon_cookie);
468	int cleanup_err = 0;
469	int err = 0;
470
471	ndmp_session_ref(session);
472
473	if (ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args) != 0) {
474		err = -1;
475		goto _done;
476	}
477
478	err = ndmpd_zfs_backup(ndmpd_zfs_args);
479
480	cleanup_err = ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args, err);
481
482	NDMP_LOG(LOG_DEBUG,
483	    "data bytes_total(including header):%llu",
484	    session->ns_data.dd_module.dm_stats.ms_bytes_processed);
485
486	if (err == 0)
487		err = ndmpd_zfs_send_fhist(ndmpd_zfs_args);
488
489_done:
490	NS_DEC(nbk);
491	MOD_DONE(ndmpd_zfs_params, err ? err : cleanup_err);
492	ndmp_session_unref(session);
493	ndmpd_zfs_fini(ndmpd_zfs_args);
494
495	return (err);
496}
497
498static int
499ndmpd_zfs_send_fhist(ndmpd_zfs_args_t *ndmpd_zfs_args)
500{
501	ndmpd_session_t *session = (ndmpd_session_t *)
502	    (ndmpd_zfs_params->mp_daemon_cookie);
503	struct stat64 st;
504	char *envp;
505
506	envp = MOD_GETENV(ndmpd_zfs_params, "HIST");
507	if (!envp)
508		return (0);
509
510	if (!(strchr("YT", toupper(*envp)))) {
511		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
512		    "HIST is not set.  No file history will be "
513		    "generated.\n");
514		return (0);
515	}
516
517	/* Build up a sample root dir stat */
518	(void) memset(&st, 0, sizeof (struct stat64));
519	st.st_mode = S_IFDIR | 0777;
520	st.st_mtime = st.st_atime = st.st_ctime = time(NULL);
521	st.st_uid = st.st_gid = 0;
522	st.st_size = 1;
523	st.st_nlink = 1;
524
525	if (ndmpd_api_file_history_dir_v3(session, ".", ROOT_INODE,
526	    ROOT_INODE) != 0)
527		return (-1);
528	if (ndmpd_api_file_history_dir_v3(session, "..", ROOT_INODE,
529	    ROOT_INODE) != 0)
530		return (-1);
531	if (ndmpd_api_file_history_node_v3(session, ROOT_INODE, &st, 0) != 0)
532		return (-1);
533
534	ndmpd_file_history_cleanup(session, TRUE);
535	return (0);
536}
537
538static int
539ndmpd_zfs_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
540{
541	ndmpd_session_t *session = (ndmpd_session_t *)
542	    (ndmpd_zfs_params->mp_daemon_cookie);
543	int *read_err = NULL;
544	int *write_err = NULL;
545	int result = 0;
546	int err;
547
548	if (session->ns_eof)
549		return (-1);
550
551	if (!session->ns_data.dd_abort) {
552		if (ndmpd_zfs_header_write(session)) {
553			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
554			    "ndmpd_zfs header write error\n");
555			return (-1);
556		}
557
558		err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
559		    &read_err, &write_err);
560
561		if (err || read_err || write_err || session->ns_eof)
562			result = EPIPE;
563	}
564
565	if (session->ns_data.dd_abort) {
566		ndmpd_audit_backup(session->ns_connection,
567		    ndmpd_zfs_args->nz_dataset,
568		    session->ns_data.dd_data_addr.addr_type,
569		    ndmpd_zfs_args->nz_dataset, EINTR);
570		NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
571		    ndmpd_zfs_args->nz_dataset);
572
573		(void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
574		err = -1;
575	} else {
576		ndmpd_audit_backup(session->ns_connection,
577		    ndmpd_zfs_args->nz_dataset,
578		    session->ns_data.dd_data_addr.addr_type,
579		    ndmpd_zfs_args->nz_dataset, result);
580
581		err = ndmpd_zfs_post_backup(ndmpd_zfs_args);
582		if (err || result)
583			err = -1;
584
585		if (err == 0)  {
586			NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished.",
587			    ndmpd_zfs_args->nz_dataset);
588		} else {
589			NDMP_LOG(LOG_DEBUG, "An error occurred while backing up"
590			    " \"%s\"", ndmpd_zfs_args->nz_dataset);
591		}
592	}
593
594	return (err);
595}
596
597/*
598 * ndmpd_zfs_backup_send_read()
599 *
600 * This routine executes zfs_send() to create the backup data stream.
601 * The value of ZFS_MODE determines the type of zfs_send():
602 * 	dataset ('d'): Only the dataset specified (i.e., top level) is backed up
603 * 	recursive ('r'): The dataset and its child file systems are backed up
604 * 	package ('p'): Same as 'r', except all intermediate snapshots are also
605 *			backed up
606 *
607 * Volumes do not have descednants, so 'd' and 'r' produce equivalent results.
608 */
609
610static int
611ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
612{
613	ndmpd_session_t *session = (ndmpd_session_t *)
614	    (ndmpd_zfs_params->mp_daemon_cookie);
615	sendflags_t flags = { 0 };
616	char *fromsnap = NULL;
617	zfs_handle_t *zhp;
618	int err;
619
620	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
621	    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
622
623	if (!zhp) {
624		if (!session->ns_data.dd_abort)
625			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
626		return (-1);
627	}
628
629	switch (ndmpd_zfs_args->nz_zfs_mode) {
630	case ('d'):
631		flags.props = B_TRUE;
632		break;
633	case ('r'):
634		flags.replicate = B_TRUE;
635		break;
636	case ('p'):
637		flags.doall = B_TRUE;
638		flags.replicate = B_TRUE;
639		break;
640	default:
641		NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c",
642		    ndmpd_zfs_args->nz_zfs_mode);
643		zfs_close(zhp);
644		return (-1);
645	}
646
647	if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
648		if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') {
649			NDMP_LOG(LOG_ERR, "no fromsnap");
650			zfs_close(zhp);
651			return (-1);
652		}
653		fromsnap = ndmpd_zfs_args->nz_fromsnap;
654	}
655
656	err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, &flags,
657	    ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL);
658
659	if (err && !session->ns_data.dd_abort)
660		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err);
661
662	zfs_close(zhp);
663
664	return (err);
665}
666
667/*
668 * ndmpd_zfs_backup_tape_write()
669 *
670 * The data begins on a mover record boundary (because
671 * the header is the size of a mover record--i.e.
672 * ndmpd_zfs_args->nz_bufsize).
673 */
674
675static int
676ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
677{
678	ndmpd_session_t *session = (ndmpd_session_t *)
679	    (ndmpd_zfs_params->mp_daemon_cookie);
680	int bufsize = ndmpd_zfs_args->nz_bufsize;
681	u_longlong_t *bytes_totalp;
682	int count;
683	char *buf;
684
685	buf = ndmp_malloc(bufsize);
686	if (buf == NULL) {
687		NDMP_LOG(LOG_DEBUG, "buf NULL");
688		return (-1);
689	}
690
691	bytes_totalp =
692	    &(session->ns_data.dd_module.dm_stats.ms_bytes_processed);
693
694	for (;;) {
695		bzero(buf, bufsize);
696
697		count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
698		    bufsize);
699
700		if (count == 0) /* EOF */ {
701			NDMP_LOG(LOG_DEBUG,
702			    "zfs_send stream size: %llu bytes; "
703			    "full backup size (including header): %llu",
704			    *bytes_totalp - bufsize, *bytes_totalp);
705			free(buf);
706
707			return (ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args,
708			    *bytes_totalp));
709		}
710
711		if (count == -1) {
712			NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)",
713			    errno);
714			free(buf);
715			return (-1);
716		}
717		NS_ADD(rdisk, count);
718
719		if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) {
720			(void) ndmpd_zfs_abort((void *) ndmpd_zfs_args);
721			NDMP_LOG(LOG_ERR, "MOD_WRITE error");
722			free(buf);
723			return (-1);
724		}
725
726		*bytes_totalp += count;
727	}
728	/* NOTREACHED */
729}
730
731static int
732ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args,
733    u_longlong_t bytes_total)
734{
735	char zfs_backup_size[32];
736	int err;
737
738	(void) snprintf(zfs_backup_size, sizeof (zfs_backup_size), "%llu",
739	    bytes_total);
740
741	err = MOD_ADDENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE", zfs_backup_size);
742
743	if (err) {
744		NDMP_LOG(LOG_ERR, "Failed to add ZFS_BACKUP_SIZE env");
745		return (-1);
746	}
747
748	NDMP_LOG(LOG_DEBUG, "Added ZFS_BACKUP_SIZE env: %s", zfs_backup_size);
749
750	return (0);
751}
752
753int
754ndmpd_zfs_restore_starter(void *arg)
755{
756	ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
757	ndmpd_session_t *session = (ndmpd_session_t *)
758	    (ndmpd_zfs_params->mp_daemon_cookie);
759	int err;
760
761	ndmp_session_ref(session);
762
763	err = ndmpd_zfs_restore(ndmpd_zfs_args);
764
765	MOD_DONE(ndmpd_zfs_params, err);
766
767	NS_DEC(nrs);
768
769	ndmp_session_unref(session);
770
771	ndmpd_zfs_fini(ndmpd_zfs_args);
772
773	return (err);
774}
775
776static int
777ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
778{
779	ndmpd_session_t *session = (ndmpd_session_t *)
780	    (ndmpd_zfs_params->mp_daemon_cookie);
781	int *read_err = NULL;
782	int *write_err = NULL;
783	int result = 0;
784	int err;
785
786	if (!session->ns_data.dd_abort) {
787		if (ndmpd_zfs_header_read(ndmpd_zfs_args)) {
788			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
789			    "ndmpd_zfs header read error\n");
790			return (-1);
791		}
792
793		err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
794		    &write_err, &read_err);
795
796		if (err || read_err || write_err || session->ns_eof)
797			result = EIO;
798	}
799
800	if (session->ns_data.dd_abort) {
801		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
802		    ndmpd_zfs_args->nz_dataset);
803		ndmpd_audit_restore(session->ns_connection,
804		    ndmpd_zfs_args->nz_dataset,
805		    session->ns_data.dd_data_addr.addr_type,
806		    ndmpd_zfs_args->nz_dataset, EINTR);
807		(void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
808		err = -1;
809	} else {
810		ndmpd_audit_restore(session->ns_connection,
811		    ndmpd_zfs_args->nz_dataset,
812		    session->ns_data.dd_data_addr.addr_type,
813		    ndmpd_zfs_args->nz_dataset, result);
814		err = ndmpd_zfs_post_restore(ndmpd_zfs_args);
815		if (err || result)
816			err = -1;
817
818		if (err == 0) {
819			NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished",
820			    ndmpd_zfs_args->nz_dataset);
821		} else {
822			NDMP_LOG(LOG_DEBUG, "An error occurred while restoring"
823			    " to \"%s\"", ndmpd_zfs_args->nz_dataset);
824		}
825	}
826
827	return (err);
828}
829
830static int
831ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
832{
833	ndmpd_session_t *session = (ndmpd_session_t *)
834	    (ndmpd_zfs_params->mp_daemon_cookie);
835	int bufsize = ndmpd_zfs_args->nz_bufsize;
836	u_longlong_t backup_size = ndmpd_zfs_args->nz_zfs_backup_size;
837	u_longlong_t *bytes_totalp;
838	u_longlong_t bytes;
839	char *buf;
840	int count;
841	int err;
842
843	buf = ndmp_malloc(bufsize);
844	if (buf == NULL) {
845		NDMP_LOG(LOG_DEBUG, "buf NULL");
846		return (-1);
847	}
848
849	bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total;
850
851	while (*bytes_totalp < backup_size) {
852
853		bytes = backup_size - *bytes_totalp;
854
855		if (bytes >= bufsize)
856			bytes = bufsize;
857
858		err = MOD_READ(ndmpd_zfs_params, buf, bytes);
859
860		if (err != 0) {
861			NDMP_LOG(LOG_ERR, "MOD_READ error: %d; returning -1",
862			    err);
863			free(buf);
864			return (-1);
865		}
866
867		count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
868		    bytes);
869
870		if (count != bytes) {
871			NDMP_LOG(LOG_ERR, "count (%d) != bytes (%d)",
872			    count, bytes);
873
874			if (count == -1) {
875				NDMP_LOG(LOG_ERR, "pipe write error: errno: %d",
876				    errno);
877
878				if (session->ns_data.dd_abort)
879					NDMP_LOG(LOG_DEBUG, "abort set");
880			}
881
882			free(buf);
883			return (-1);
884		}
885
886		NS_ADD(wdisk, count);
887
888		*bytes_totalp += count;
889	}
890
891	free(buf);
892	return (0);
893}
894
895/*
896 * ndmpd_zfs_restore_recv_write()
897 *
898 * This routine executes zfs_receive() to restore the backup.
899 */
900
901static int
902ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
903{
904	ndmpd_session_t *session = (ndmpd_session_t *)
905	    (ndmpd_zfs_params->mp_daemon_cookie);
906	recvflags_t flags;
907	int err;
908
909	bzero(&flags, sizeof (recvflags_t));
910
911	flags.nomount = B_TRUE;
912
913	NDMP_LOG(LOG_DEBUG, "nz_zfs_force: %d\n", ndmpd_zfs_args->nz_zfs_force);
914
915	if (ndmpd_zfs_args->nz_zfs_force)
916		flags.force = B_TRUE;
917
918	err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
919	    NULL, &flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL);
920
921	if (err && !session->ns_data.dd_abort)
922		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err);
923
924	return (err);
925}
926
927/*
928 * ndmpd_zfs_reader_writer()
929 *
930 * Two separate threads are used for actual backup or restore.
931 */
932
933static int
934ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args,
935    int **sendrecv_errp, int **tape_errp)
936{
937	funct_t sendrecv_func;
938	funct_t tape_func;
939	int sendrecv_err;
940	int tape_err;
941
942	switch (ndmpd_zfs_params->mp_operation) {
943	case NDMP_DATA_OP_BACKUP:
944		sendrecv_func = (funct_t)ndmpd_zfs_backup_send_read;
945		tape_func = (funct_t)ndmpd_zfs_backup_tape_write;
946		break;
947	case NDMP_DATA_OP_RECOVER:
948		sendrecv_func = (funct_t)ndmpd_zfs_restore_recv_write;
949		tape_func = (funct_t)ndmpd_zfs_restore_tape_read;
950		break;
951	}
952
953	sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread,
954	    NULL, sendrecv_func, ndmpd_zfs_args);
955
956	if (sendrecv_err == 0) {
957		tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread,
958		    NULL, tape_func, ndmpd_zfs_args);
959
960		if (tape_err) {
961			/*
962			 * The close of the tape side of the pipe will cause
963			 * nz_sendrecv_thread to error in the zfs_send/recv()
964			 * call and to return.  Hence we do not need
965			 * to explicitly cancel the sendrecv_thread here
966			 * (the pthread_join() below is sufficient).
967			 */
968
969			(void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]);
970			NDMP_LOG(LOG_ERR, "Could not start tape thread; "
971			    "aborting z-op");
972		}
973
974		(void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread,
975		    (void **) sendrecv_errp);
976	}
977
978	if ((tape_err == 0) &&
979	    (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER))
980		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
981
982	ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
983
984	if ((sendrecv_err == 0) && (tape_err == 0)) {
985		(void) pthread_join(ndmpd_zfs_args->nz_tape_thread,
986		    (void **) tape_errp);
987	}
988
989	if ((tape_err == 0) &&
990	    (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP))
991		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
992
993	return (sendrecv_err ? sendrecv_err : tape_err);
994}
995
996int
997ndmpd_zfs_abort(void *arg)
998{
999	ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
1000	char str[8];
1001
1002	if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)
1003		(void) strlcpy(str, "backup", 8);
1004	else
1005		(void) strlcpy(str, "recover", 8);
1006
1007	NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation",
1008	    str);
1009
1010	ndmpd_zfs_close_fds(ndmpd_zfs_args);
1011
1012	return (0);
1013}
1014
1015/*
1016 * ndmpd_zfs_pre_backup()
1017 *
1018 * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL.
1019 * This ensures that ndmp_include_zfs() will fail, which is
1020 * a requirement for "zfs"-type backup.
1021 */
1022
1023int
1024ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
1025{
1026	ndmpd_session_t *session = (ndmpd_session_t *)
1027	    (ndmpd_zfs_params->mp_daemon_cookie);
1028	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1029	int err;
1030
1031	if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL)
1032		return (0);
1033
1034	(void) memset(nctxp, 0, sizeof (ndmp_context_t));
1035	nctxp->nc_plversion = ndmp_pl->np_plversion;
1036	nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
1037	nctxp->nc_ddata = (void *) session;
1038	nctxp->nc_params = ndmpd_zfs_params;
1039
1040	err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp,
1041	    ndmpd_zfs_args->nz_dataset);
1042
1043	if (err != 0) {
1044		NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m");
1045		(void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
1046	}
1047
1048	return (err);
1049}
1050
1051int
1052ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
1053{
1054	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1055	int err = 0;
1056
1057	if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL)
1058		return (0);
1059
1060	err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err);
1061
1062	if (err == -1)
1063		NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
1064
1065	return (err);
1066}
1067
1068int
1069ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
1070{
1071	ndmpd_session_t *session = (ndmpd_session_t *)
1072	    (ndmpd_zfs_params->mp_daemon_cookie);
1073	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1074	char bkpath[ZFS_MAX_DATASET_NAME_LEN];
1075	int err;
1076
1077	if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL)
1078		return (0);
1079
1080	err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath,
1081	    ZFS_MAX_DATASET_NAME_LEN);
1082
1083	if (err != 0) {
1084		NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err);
1085		return (-1);
1086	}
1087
1088	err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args);
1089
1090	if (err != 0) {
1091		NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err);
1092		return (-1);
1093	}
1094
1095	(void) memset(nctxp, 0, sizeof (ndmp_context_t));
1096	nctxp->nc_ddata = (void *) session;
1097	nctxp->nc_params = ndmpd_zfs_params;
1098
1099	err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath,
1100	    ndmpd_zfs_args->nz_dataset);
1101
1102	if (err != 0) {
1103		NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
1104		return (-1);
1105	}
1106
1107	return (0);
1108}
1109
1110int
1111ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
1112{
1113	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1114	int err = 0;
1115
1116	if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL)
1117		return (0);
1118
1119	err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err);
1120
1121	if (err == -1)
1122		NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
1123
1124	return (err);
1125}
1126
1127boolean_t
1128ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1129{
1130	ndmpd_zfs_snapfind_t snapdata;
1131
1132	if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0)
1133		return (B_FALSE);
1134
1135	if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args))
1136		return (B_FALSE);
1137
1138	if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
1139		(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
1140		    snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE);
1141
1142		snapdata.nzs_snapname[0] = '\0';
1143		snapdata.nzs_snapprop[0] = '\0';
1144
1145		if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata))
1146			return (B_FALSE);
1147
1148		if (snapdata.nzs_snapname[0] == '\0') { /* not found */
1149			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1150			    "Snapshot for level %d does not exist\n",
1151			    ndmpd_zfs_args->nz_level-1);
1152			return (B_FALSE);
1153		}
1154
1155		(void) strlcpy(ndmpd_zfs_args->nz_fromsnap,
1156		    snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN);
1157	}
1158
1159	return (B_TRUE);
1160}
1161
1162/*
1163 * ndmpd_zfs_backup_pathvalid()
1164 *
1165 * Make sure the path is of an existing dataset
1166 */
1167
1168static boolean_t
1169ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1170{
1171	char zpath[ZFS_MAX_DATASET_NAME_LEN];
1172	char propstr[ZFS_MAXPROPLEN];
1173	zfs_handle_t *zhp;
1174	zfs_type_t ztype = 0;
1175	int err;
1176
1177	if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
1178	    ZFS_MAX_DATASET_NAME_LEN) != 0)
1179		return (B_FALSE);
1180
1181	if (ndmpd_zfs_args->nz_snapname[0] != '\0') {
1182		zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath,
1183		    ZFS_TYPE_SNAPSHOT);
1184
1185		if (!zhp) {
1186			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args,
1187			    "zfs_open (snap)");
1188			ndmpd_zfs_args->nz_snapname[0] = '\0';
1189			ndmpd_zfs_args->nz_dataset[0] = '\0';
1190			return (B_FALSE);
1191		}
1192
1193		err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
1194
1195		zfs_close(zhp);
1196
1197		if (err) {
1198			NDMP_LOG(LOG_DEBUG,
1199			    "ndmpd_zfs_snapshot_prop_get failed");
1200			return (-1);
1201		}
1202
1203		if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) {
1204			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1205			    "cannot use an ndmpd-generated snapshot\n");
1206			return (B_FALSE);
1207		}
1208	}
1209
1210	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
1211	    ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET);
1212
1213	if (zhp) {
1214		ztype = zfs_get_type(zhp);
1215		zfs_close(zhp);
1216	}
1217
1218	if ((ztype == ZFS_TYPE_VOLUME) ||
1219	    (ztype == ZFS_TYPE_FILESYSTEM)) {
1220		ndmpd_zfs_args->nz_type = ztype;
1221		return (B_TRUE);
1222	}
1223
1224	ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1225	    "Invalid file system or volume.\n");
1226
1227	return (B_FALSE);
1228}
1229
1230/*
1231 * ndmpd_zfs_backup_getpath()
1232 *
1233 * Retrieve the backup path from the environment, which should
1234 * be of the form "/dataset[@snap]".  The leading slash is required
1235 * by certain DMA's but can otherwise be ignored.
1236 *
1237 * (Note: "dataset" can consist of more than one component,
1238 * e.g. "pool", "pool/volume", "pool/fs/fs2".)
1239 *
1240 * The dataset name and the snapshot name (if any) will be
1241 * stored in ndmpd_zfs_args.
1242 */
1243
1244static int
1245ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath,
1246    int zlen)
1247{
1248	char *env_path;
1249	char *at;
1250
1251	env_path = get_backup_path_v3(ndmpd_zfs_params);
1252	if (env_path == NULL)
1253		return (-1);
1254
1255	if (env_path[0] != '/') {
1256		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1257		    "Invalid path: %s (leading slash required)\n", env_path);
1258		return (-1);
1259	}
1260
1261	(void) strlcpy(zpath, &env_path[1], zlen);
1262	(void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1],
1263	    ZFS_MAX_DATASET_NAME_LEN);
1264
1265	at = strchr(ndmpd_zfs_args->nz_dataset, '@');
1266	if (at) {
1267		*at = '\0';
1268		(void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at,
1269		    ZFS_MAX_DATASET_NAME_LEN);
1270	} else {
1271		ndmpd_zfs_args->nz_snapname[0] = '\0';
1272	}
1273
1274	(void) trim_whitespace(ndmpd_zfs_args->nz_dataset);
1275
1276	return (0);
1277}
1278
1279static int
1280ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1281{
1282	return (ndmpd_zfs_getenv(ndmpd_zfs_args));
1283}
1284
1285boolean_t
1286ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1287{
1288	if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0)
1289		return (B_FALSE);
1290
1291	if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args))
1292		return (B_FALSE);
1293
1294	return (B_TRUE);
1295}
1296
1297static boolean_t
1298ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1299{
1300	zfs_handle_t *zhp;
1301	char *at;
1302
1303	if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0)
1304		return (B_FALSE);
1305
1306	at = strchr(ndmpd_zfs_args->nz_dataset, '@');
1307
1308	if (at) {
1309		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
1310		    "%s ignored in restore path\n", at);
1311		*at = '\0';
1312	}
1313
1314	ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
1315
1316	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
1317	    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
1318
1319	if (zhp) {
1320		zfs_close(zhp);
1321
1322		if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
1323			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1324			    "Restore dataset exists.\n"
1325			    "A nonexistent dataset must be specified "
1326			    "for 'zfs' non-incremental restore.\n");
1327			return (B_FALSE);
1328		}
1329	}
1330
1331	NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset);
1332
1333	return (B_TRUE);
1334}
1335
1336/*
1337 * ndmpd_zfs_restore_getpath()
1338 *
1339 * Be sure to not include the leading slash, which is required for
1340 * compatibility with backup applications (NBU) but which is not part
1341 * of the ZFS syntax.  (Note that this done explicitly in all paths
1342 * below except those calling ndmpd_zfs_backup_getpath(), because it is
1343 * already stripped in that function.)
1344 *
1345 * In addition, the DMA might add a trailing slash to the path.
1346 * Strip all such slashes.
1347 */
1348
1349static int
1350ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args)
1351{
1352	int version = ndmpd_zfs_params->mp_protocol_version;
1353	char zpath[ZFS_MAX_DATASET_NAME_LEN];
1354	mem_ndmp_name_v3_t *namep_v3;
1355	char *dataset = ndmpd_zfs_args->nz_dataset;
1356	char *nm;
1357	char *p;
1358	int len;
1359	int err;
1360
1361	namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0);
1362
1363	if (namep_v3 == NULL) {
1364		NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]");
1365		return (-1);
1366	}
1367
1368	if (namep_v3->nm3_dpath) {
1369		if (namep_v3->nm3_dpath[0] != '/') {
1370			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1371			    "Invalid path: %s (leading slash required)\n",
1372			    namep_v3->nm3_dpath);
1373			return (-1);
1374		}
1375
1376		(void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]),
1377		    ZFS_MAX_DATASET_NAME_LEN);
1378
1379		if (namep_v3->nm3_newnm) {
1380			(void) strlcat(dataset, "/", ZFS_MAX_DATASET_NAME_LEN);
1381			(void) strlcat(dataset, namep_v3->nm3_newnm,
1382			    ZFS_MAX_DATASET_NAME_LEN);
1383
1384		} else {
1385			if (version == NDMPV3) {
1386				/*
1387				 * The following does not apply for V4.
1388				 *
1389				 * Find the last component of nm3_opath.
1390				 * nm3_opath has no trailing '/'.
1391				 */
1392				p = strrchr(namep_v3->nm3_opath, '/');
1393				nm = p? p : namep_v3->nm3_opath;
1394				(void) strlcat(dataset, "/",
1395				    ZFS_MAX_DATASET_NAME_LEN);
1396				(void) strlcat(dataset, nm,
1397				    ZFS_MAX_DATASET_NAME_LEN);
1398			}
1399		}
1400	} else {
1401		err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
1402		    ZFS_MAX_DATASET_NAME_LEN);
1403		if (err)
1404			return (err);
1405	}
1406
1407	len = strlen(dataset);
1408	while (dataset[len-1] == '/') {
1409		dataset[len-1] = '\0';
1410		len--;
1411	}
1412
1413	return (0);
1414}
1415
1416static int
1417ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1418{
1419	if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args) != 0)
1420		return (-1);
1421
1422	return (ndmpd_zfs_getenv(ndmpd_zfs_args));
1423}
1424
1425static int
1426ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1427{
1428
1429	if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0)
1430		return (-1);
1431
1432	if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0)
1433		return (-1);
1434
1435	if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0)
1436		return (-1);
1437
1438	if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0)
1439		return (-1);
1440
1441	if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0)
1442		return (-1);
1443
1444	return (0);
1445}
1446
1447static int
1448ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args)
1449{
1450	char *envp;
1451
1452	envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE");
1453
1454	if (envp == NULL) {
1455		NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, "
1456		    "defaulting to recursive");
1457		ndmpd_zfs_args->nz_zfs_mode = 'r';
1458		return (0);
1459	}
1460
1461	if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) {
1462		ndmpd_zfs_args->nz_zfs_mode = 'd';
1463	} else if ((strcmp(envp, "recursive") == 0) ||
1464	    (strcmp(envp, "r") == 0)) {
1465		ndmpd_zfs_args->nz_zfs_mode = 'r';
1466	} else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) {
1467		ndmpd_zfs_args->nz_zfs_mode = 'p';
1468	} else {
1469		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1470		    "Invalid ZFS_MODE value \"%s\".\n", envp);
1471		return (-1);
1472	}
1473
1474	NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"",
1475	    ndmpd_zfs_args->nz_zfs_mode);
1476
1477	return (0);
1478}
1479
1480/*
1481 * ndmpd_zfs_getenv_zfs_force()
1482 *
1483 * If SMF property zfs-force-override is set to "yes" or "no", this
1484 * value will override any value of NDMP environment variable ZFS_FORCE
1485 * as set by the DMA admin (or override the default of 'n', if ZFS_FORCE
1486 * is not set).  By default, zfs-force-override is "off", which means it
1487 * will not override ZFS_FORCE.
1488 */
1489
1490static int
1491ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args)
1492{
1493	char *envp_force;
1494	char *override;
1495
1496	override = ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE);
1497
1498	if (strcasecmp(override, "yes") == 0) {
1499		ndmpd_zfs_args->nz_zfs_force = B_TRUE;
1500		NDMP_LOG(LOG_NOTICE,
1501		    "SMF property zfs-force-override set to 'yes', "
1502		    "overriding ZFS_FORCE");
1503		return (0);
1504	}
1505
1506	if (strcasecmp(override, "no") == 0) {
1507		ndmpd_zfs_args->nz_zfs_force = B_FALSE;
1508		NDMP_LOG(LOG_NOTICE,
1509		    "SMF property zfs-force-override set to 'no', "
1510		    "overriding ZFS_FORCE");
1511		return (0);
1512	}
1513
1514	if (strcasecmp(override, "off") != 0) {
1515		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1516		    "SMF property zfs-force-override set to invalid value of "
1517		    "'%s'; treating it as 'off'.", override);
1518	}
1519
1520	envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE");
1521
1522	if (envp_force == NULL) {
1523		NDMP_LOG(LOG_DEBUG,
1524		    "env(ZFS_FORCE) not specified, defaulting to FALSE");
1525		ndmpd_zfs_args->nz_zfs_force = B_FALSE;
1526		return (0);
1527	}
1528
1529	/*
1530	 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1531	 */
1532
1533	if (strchr("tTyY", *envp_force))
1534		ndmpd_zfs_args->nz_zfs_force = B_TRUE;
1535
1536	NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force);
1537
1538	return (0);
1539}
1540
1541static int
1542ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args)
1543{
1544	char *envp;
1545
1546	envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL");
1547
1548	if (envp == NULL) {
1549		NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, "
1550		    "defaulting to 0");
1551		ndmpd_zfs_args->nz_level = 0;
1552		return (0);
1553	}
1554
1555	if (envp[1] != '\0') {
1556		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1557		    "Invalid backup level \"%s\".\n", envp);
1558		return (-1);
1559	}
1560
1561	if (!isdigit(*envp)) {
1562		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1563		    "Invalid backup level \"%s\".\n", envp);
1564		return (-1);
1565	}
1566
1567	ndmpd_zfs_args->nz_level = atoi(envp);
1568
1569	NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"",
1570	    ndmpd_zfs_args->nz_level);
1571
1572	return (0);
1573}
1574
1575static int
1576ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args)
1577{
1578	char *envp_update;
1579
1580	envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE");
1581
1582	if (envp_update == NULL) {
1583		NDMP_LOG(LOG_DEBUG,
1584		    "env(UPDATE) not specified, defaulting to TRUE");
1585		ndmpd_zfs_args->nz_update = B_TRUE;
1586		return (0);
1587	}
1588
1589	/*
1590	 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1591	 */
1592
1593	if (strchr("tTyY", *envp_update))
1594		ndmpd_zfs_args->nz_update = B_TRUE;
1595
1596	NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update);
1597
1598	return (0);
1599}
1600
1601static int
1602ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args)
1603{
1604	char *envp;
1605
1606	envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME");
1607
1608	if (envp == NULL) {
1609		NDMP_LOG(LOG_DEBUG,
1610		    "env(DMP_NAME) not specified, defaulting to 'level'");
1611		(void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level",
1612		    NDMPD_ZFS_DMP_NAME_MAX);
1613		return (0);
1614	}
1615
1616	if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp))
1617		return (-1);
1618
1619	(void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp,
1620	    NDMPD_ZFS_DMP_NAME_MAX);
1621
1622	NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp);
1623
1624	return (0);
1625}
1626
1627static int
1628ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args)
1629{
1630	char *zfs_backup_size;
1631
1632	zfs_backup_size = MOD_GETENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE");
1633
1634	if (zfs_backup_size == NULL) {
1635		NDMP_LOG(LOG_ERR, "ZFS_BACKUP_SIZE env is NULL");
1636		return (-1);
1637	}
1638
1639	NDMP_LOG(LOG_DEBUG, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size);
1640
1641	(void) sscanf(zfs_backup_size, "%llu",
1642	    &ndmpd_zfs_args->nz_zfs_backup_size);
1643
1644	return (0);
1645}
1646
1647/*
1648 * ndmpd_zfs_dmp_name_valid()
1649 *
1650 * This function verifies that the dmp_name is valid.
1651 *
1652 * The dmp_name is restricted to alphanumeric characters plus
1653 * the underscore and hyphen, and must be 31 characters or less.
1654 * This is due to its use in the NDMPD_ZFS_PROP_INCR property
1655 * and in the ZFS snapshot name (if an ndmpd-generated snapshot
1656 * is required).
1657 */
1658
1659static boolean_t
1660ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name)
1661{
1662	char *c;
1663
1664	if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) {
1665		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1666		    "DMP_NAME %s is longer than %d\n",
1667		    dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1);
1668		return (B_FALSE);
1669	}
1670
1671	for (c = dmp_name; *c != '\0'; c++) {
1672		if (!isalpha(*c) && !isdigit(*c) &&
1673		    (*c != '_') && (*c != '-')) {
1674			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1675			    "DMP_NAME %s contains illegal character %c\n",
1676			    dmp_name, *c);
1677			return (B_FALSE);
1678		}
1679	}
1680
1681	NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name);
1682	return (B_TRUE);
1683}
1684
1685/*
1686 * ndmpd_zfs_is_incremental()
1687 *
1688 * This can only be called after ndmpd_zfs_getenv_level()
1689 * has been called.
1690 */
1691
1692static boolean_t
1693ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args)
1694{
1695	return (ndmpd_zfs_args->nz_level != 0);
1696}
1697
1698/*
1699 * ndmpd_zfs_snapshot_prepare()
1700 *
1701 * If no snapshot was supplied by the user, create a snapshot
1702 * for use by ndmpd.
1703 */
1704
1705static int
1706ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args)
1707{
1708	ndmpd_session_t *session = (ndmpd_session_t *)
1709	    (ndmpd_zfs_params->mp_daemon_cookie);
1710	boolean_t recursive = B_FALSE;
1711	int zfs_err = 0;
1712
1713	if (session->ns_data.dd_abort) {
1714		NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
1715		    ndmpd_zfs_args->nz_dataset);
1716		return (-1);
1717	}
1718
1719	if (ndmpd_zfs_args->nz_snapname[0] == '\0') {
1720		ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE;
1721
1722		if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) {
1723			ndmpd_zfs_args->nz_snapname[0] = '\0';
1724
1725			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1726			    "Error creating snapshot for %s\n",
1727			    ndmpd_zfs_args->nz_dataset);
1728
1729			return (-1);
1730		}
1731	}
1732
1733	if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) {
1734		NDMP_LOG(LOG_DEBUG,
1735		    "ndmpd_zfs_snapshot_prop_add error\n");
1736
1737		if (ndmpd_zfs_args->nz_ndmpd_snap) {
1738
1739			if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1740				recursive = B_TRUE;
1741
1742			(void) snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1743			    ndmpd_zfs_args->nz_snapname, recursive, B_FALSE,
1744			    &zfs_err);
1745		}
1746
1747		return (-1);
1748	}
1749
1750	return (0);
1751}
1752
1753/*
1754 * ndmpd_zfs_snapshot_cleanup()
1755 *
1756 * If UPDATE = y, find the old snapshot (if any) corresponding to
1757 * {LEVEL, DMP_NAME, ZFS_MODE}. If it was ndmpd-generated,
1758 * remove the snapshot.  Otherwise, update its NDMPD_ZFS_PROP_INCR
1759 * property to remove {L, D, Z}.
1760 *
1761 * If UPDATE = n, if an ndmpd-generated snapshot was used for backup,
1762 * remove the snapshot.  Otherwise, update its NDMPD_ZFS_PROP_INCR
1763 * property to remove {L, D, Z}.
1764 */
1765
1766static int
1767ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err)
1768{
1769	ndmpd_session_t *session = (ndmpd_session_t *)
1770	    (ndmpd_zfs_params->mp_daemon_cookie);
1771	ndmpd_zfs_snapfind_t snapdata;
1772	boolean_t ndmpd_generated = B_FALSE;
1773
1774	bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t));
1775
1776	(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
1777	    snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE);
1778
1779	if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) {
1780		/*
1781		 * Find the existing snapshot, if any, to "unuse."
1782		 * Indicate that the current snapshot used for backup
1783		 * should be skipped in the search.  (The search is
1784		 * sorted by creation time but this cannot be relied
1785		 * upon for user-supplied snapshots.)
1786		 */
1787
1788		(void) snprintf(snapdata.nzs_snapskip, ZFS_MAX_DATASET_NAME_LEN,
1789		    "%s", ndmpd_zfs_args->nz_snapname);
1790
1791		if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) {
1792			NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n");
1793			goto _remove_tmp_snap;
1794		}
1795
1796		if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */
1797			ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated
1798			    (snapdata.nzs_snapprop);
1799
1800			if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
1801			    ndmpd_generated, &snapdata) != 0) {
1802				NDMP_LOG(LOG_DEBUG,
1803				    "ndmpd_zfs_snapshot_unuse error\n");
1804				goto _remove_tmp_snap;
1805			}
1806		}
1807
1808		if (session->ns_data.dd_abort)
1809			goto _remove_tmp_snap;
1810
1811		return (0);
1812	}
1813
1814_remove_tmp_snap:
1815
1816	(void) snprintf(snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN, "%s",
1817	    ndmpd_zfs_args->nz_snapname);
1818
1819	(void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop,
1820	    ZFS_MAXPROPLEN);
1821
1822	snapdata.nzs_snapskip[0] = '\0';
1823
1824	if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
1825	    ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) {
1826		NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n");
1827		return (-1);
1828	}
1829
1830	if (!ndmpd_zfs_args->nz_update)
1831		return (0);
1832
1833	return (-1);
1834}
1835
1836static int
1837ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args)
1838{
1839	boolean_t recursive = B_FALSE;
1840
1841	if (ndmpd_zfs_snapname_create(ndmpd_zfs_args,
1842	    ndmpd_zfs_args->nz_snapname, ZFS_MAX_DATASET_NAME_LEN - 1) < 0) {
1843		NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s",
1844		    errno, ndmpd_zfs_args->nz_dataset);
1845		return (-1);
1846	}
1847
1848	if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1849		recursive = B_TRUE;
1850
1851	if (snapshot_create(ndmpd_zfs_args->nz_dataset,
1852	    ndmpd_zfs_args->nz_snapname, recursive, B_FALSE) != 0) {
1853		NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s",
1854		    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
1855		return (-1);
1856	}
1857
1858	NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s",
1859	    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
1860
1861	return (0);
1862}
1863
1864/*
1865 * ndmpd_zfs_snapshot_unuse()
1866 *
1867 * Given a pre-existing snapshot of the given {L, D, Z}:
1868 * If snapshot is ndmpd-generated, remove snapshot.
1869 * If not ndmpd-generated, or if the ndmpd-generated snapshot
1870 * cannot be destroyed, remove the {L, D, Z} substring from the
1871 * snapshot's NDMPD_ZFS_PROP_INCR property.
1872 *
1873 * In the event of a failure, it may be that two snapshots will
1874 * have the {L, D, Z} property set on them.  This is not desirable,
1875 * so return an error and log the failure.
1876 */
1877
1878static int
1879ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args,
1880    boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p)
1881{
1882	boolean_t recursive = B_FALSE;
1883	int zfs_err = 0;
1884	int err = 0;
1885
1886	if (ndmpd_generated) {
1887		if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1888			recursive = B_TRUE;
1889
1890		err = snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1891		    snapdata_p->nzs_snapname, recursive, B_FALSE, &zfs_err);
1892
1893		if (err) {
1894			NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;"
1895			    " err: %d; zfs_err: %d",
1896			    ndmpd_zfs_args->nz_dataset,
1897			    snapdata_p->nzs_snapname, err, zfs_err);
1898			return (-1);
1899		}
1900	}
1901
1902	if (!ndmpd_generated || zfs_err) {
1903		if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p))
1904			return (-1);
1905	}
1906
1907	return (0);
1908}
1909
1910static boolean_t
1911ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop)
1912{
1913	char origin;
1914
1915	(void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin);
1916
1917	return (origin == 'n');
1918}
1919
1920/*
1921 * ndmpd_zfs_snapshot_find()
1922 *
1923 * Find a snapshot with a particular value for
1924 * the NDMPD_ZFS_PROP_INCR property.
1925 */
1926
1927static int
1928ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args,
1929    ndmpd_zfs_snapfind_t *snapdata)
1930{
1931	zfs_handle_t *zhp;
1932	int err;
1933
1934	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
1935	    ndmpd_zfs_args->nz_type);
1936
1937	if (!zhp) {
1938		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
1939		return (-1);
1940	}
1941
1942	err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find,
1943	    snapdata);
1944
1945	zfs_close(zhp);
1946
1947	if (err) {
1948		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d",
1949		    err);
1950		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1951		    "Error iterating snapshots\n");
1952		return (-1);
1953	}
1954
1955	return (0);
1956}
1957
1958/*
1959 * ndmpd_zfs_snapshot_prop_find()
1960 *
1961 * Find a snapshot with a particular value for
1962 * NDMPD_ZFS_PROP_INCR.  Fill in data for the first one
1963 * found (sorted by creation time).  However, skip the
1964 * the snapshot indicated in nzs_snapskip, if any.
1965 */
1966
1967static int
1968ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg)
1969{
1970	ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg;
1971	char propstr[ZFS_MAXPROPLEN];
1972	char findprop_plus_slash[ZFS_MAXPROPLEN];
1973	char *justsnap;
1974	int err = 0;
1975
1976	if (snapdata_p->nzs_snapname[0] != '\0') {
1977		NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s",
1978		    (char *)zfs_get_name(zhp));
1979		goto _done;
1980	}
1981
1982	err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
1983
1984	if (err) {
1985		NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed");
1986		goto _done;
1987	}
1988
1989	if (propstr[0] == '\0') {
1990		NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set",
1991		    (char *)zfs_get_name(zhp));
1992		goto _done;
1993	}
1994
1995	(void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
1996	    snapdata_p->nzs_findprop);
1997
1998	if (!strstr((const char *)propstr,
1999	    (const char *)findprop_plus_slash)) {
2000		NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)",
2001		    (char *)zfs_get_name(zhp), propstr,
2002		    snapdata_p->nzs_findprop);
2003		goto _done;
2004	}
2005
2006	if (!ndmpd_zfs_prop_version_check(propstr,
2007	    &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) {
2008		NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)",
2009		    (char *)zfs_get_name(zhp),  propstr,
2010		    snapdata_p->nzs_findprop);
2011		NDMP_LOG(LOG_DEBUG, "did not pass version check");
2012		goto _done;
2013	}
2014
2015	justsnap = strchr(zfs_get_name(zhp), '@') + 1;
2016
2017	if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) {
2018		(void) strlcpy(snapdata_p->nzs_snapname, justsnap,
2019		    ZFS_MAX_DATASET_NAME_LEN);
2020
2021		(void) strlcpy(snapdata_p->nzs_snapprop, propstr,
2022		    ZFS_MAXPROPLEN);
2023
2024		NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n",
2025		    snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop);
2026	}
2027
2028_done:
2029	zfs_close(zhp);
2030	return (err);
2031}
2032
2033/*
2034 * ndmpd_zfs_snapshot_prop_get()
2035 *
2036 * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot
2037 */
2038
2039static int
2040ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr)
2041{
2042	nvlist_t *userprop;
2043	nvlist_t *propval;
2044	char *strval;
2045	int err;
2046
2047	propstr[0] = '\0';
2048
2049	userprop = zfs_get_user_props(zhp);
2050
2051	if (userprop == NULL)
2052		return (0);
2053
2054	err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval);
2055
2056	if (err != 0) {
2057		if (err == ENOENT)
2058			return (0);
2059
2060		NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err);
2061
2062		return (-1);
2063	}
2064
2065	err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
2066
2067	if (err != 0) {
2068		if (err == ENOENT)
2069			return (0);
2070
2071		NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err);
2072
2073		return (-1);
2074	}
2075
2076	(void) strlcpy(propstr, strval, ZFS_MAXPROPLEN);
2077
2078	return (0);
2079}
2080
2081/*
2082 * ndmpd_zfs_snapshot_prop_add()
2083 *
2084 * Update snapshot's NDMPD_ZFS_PROP_INCR property with
2085 * the current LEVEL, DMP_NAME, and ZFS_MODE values
2086 * (add property if it doesn't exist)
2087 */
2088
2089static int
2090ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args)
2091{
2092	char fullname[ZFS_MAX_DATASET_NAME_LEN];
2093	char propstr[ZFS_MAXPROPLEN];
2094	zfs_handle_t *zhp;
2095	boolean_t set;
2096	int err;
2097
2098	(void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
2099	    ndmpd_zfs_args->nz_dataset,
2100	    ndmpd_zfs_args->nz_snapname);
2101
2102	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
2103
2104	if (!zhp) {
2105		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)");
2106		return (-1);
2107	}
2108
2109	bzero(propstr, ZFS_MAXPROPLEN);
2110
2111	if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) {
2112		NDMP_LOG(LOG_DEBUG, "error getting property");
2113		zfs_close(zhp);
2114		return (-1);
2115	}
2116
2117	if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) {
2118		zfs_close(zhp);
2119		return (-1);
2120	}
2121
2122	if (set) {
2123		err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr);
2124		if (err) {
2125			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
2126			    err);
2127			NDMP_LOG(LOG_ERR, "error setting property %s",
2128			    propstr);
2129			zfs_close(zhp);
2130			return (-1);
2131		}
2132	}
2133
2134	zfs_close(zhp);
2135
2136	(void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN);
2137
2138	return (0);
2139}
2140
2141static int
2142ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
2143    char *propstr, boolean_t *set)
2144{
2145	char subprop[ZFS_MAXPROPLEN];
2146	char *p = propstr;
2147	int slash_count = 0;
2148
2149	*set = B_TRUE;
2150
2151	(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
2152	    subprop, ZFS_MAXPROPLEN, B_FALSE);
2153
2154	if (propstr[0] == '\0') {
2155		(void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s",
2156		    NDMPD_ZFS_PROP_MAJOR_VERSION,
2157		    NDMPD_ZFS_PROP_MINOR_VERSION,
2158		    (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u',
2159		    subprop);
2160		return (0);
2161	}
2162
2163	if (strstr((const char *)propstr, (const char *)subprop)) {
2164		NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists",
2165		    subprop);
2166		*set = B_FALSE;
2167		return (0);
2168	}
2169
2170	while (*p) {
2171		if (*(p++) == '/')
2172			slash_count++;
2173	}
2174
2175	if (slash_count >= NDMPD_ZFS_SUBPROP_MAX) {
2176		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2177		    "snapshot %s: user property %s limit of %d subprops "
2178		    "reached; cannot complete operation",
2179		    ndmpd_zfs_args->nz_snapname,
2180		    NDMPD_ZFS_PROP_INCR,
2181		    NDMPD_ZFS_SUBPROP_MAX);
2182		return (-1);
2183	}
2184
2185	assert((strlen(propstr) + strlen(subprop) + 2) < ZFS_MAXPROPLEN);
2186
2187	(void) strlcat(propstr, "/", ZFS_MAXPROPLEN);
2188	(void) strlcat(propstr, subprop, ZFS_MAXPROPLEN);
2189
2190	return (0);
2191}
2192
2193static int
2194ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args,
2195    char *subprop, int len, boolean_t prev_level)
2196{
2197	return (snprintf(subprop, len, "%d.%s.%c",
2198	    prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level,
2199	    ndmpd_zfs_args->nz_dmp_name,
2200	    ndmpd_zfs_args->nz_zfs_mode));
2201}
2202
2203/*
2204 * ndmpd_zfs_snapshot_prop_remove()
2205 *
2206 * Remove specified substring from the snapshot's
2207 * NDMPD_ZFS_PROP_INCR property
2208 */
2209
2210static int
2211ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args,
2212    ndmpd_zfs_snapfind_t *snapdata_p)
2213{
2214	char findprop_plus_slash[ZFS_MAXPROPLEN];
2215	char fullname[ZFS_MAX_DATASET_NAME_LEN];
2216	char newprop[ZFS_MAXPROPLEN];
2217	char tmpstr[ZFS_MAXPROPLEN];
2218	zfs_handle_t *zhp;
2219	char *ptr;
2220	int err;
2221
2222	(void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
2223	    ndmpd_zfs_args->nz_dataset,
2224	    snapdata_p->nzs_snapname);
2225
2226	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
2227
2228	if (!zhp) {
2229		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
2230		return (-1);
2231	}
2232
2233	bzero(newprop, ZFS_MAXPROPLEN);
2234
2235	/*
2236	 * If the substring to be removed is the only {L, D, Z}
2237	 * in the property, remove the entire property
2238	 */
2239
2240	tmpstr[0] = '\0';
2241
2242	(void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr);
2243
2244	if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) {
2245
2246		err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
2247
2248		zfs_close(zhp);
2249
2250		if (err) {
2251			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
2252			    err);
2253			NDMP_LOG(LOG_ERR, "error setting property %s", newprop);
2254			return (-1);
2255		}
2256
2257		return (0);
2258	}
2259
2260	(void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
2261	    snapdata_p->nzs_findprop);
2262
2263	ptr = strstr((const char *)snapdata_p->nzs_snapprop,
2264	    (const char *)findprop_plus_slash);
2265
2266	if (ptr == NULL) {
2267		/*
2268		 * This shouldn't happen.  Just return success.
2269		 */
2270		zfs_close(zhp);
2271
2272		return (0);
2273	}
2274
2275	/*
2276	 * Remove "nzs_findprop" substring from property
2277	 *
2278	 * Example property:
2279	 *	0.0.u/1.bob.p/0.jane.d
2280	 *
2281	 * Note that there will always be a prefix to the
2282	 * strstr() result.  Hence the below code works for
2283	 * all cases.
2284	 */
2285
2286	ptr--;
2287	(void) strncpy(newprop, snapdata_p->nzs_snapprop,
2288	    (char *)ptr - snapdata_p->nzs_snapprop);
2289	ptr += strlen(snapdata_p->nzs_findprop) + 1;
2290	(void) strlcat(newprop, ptr, ZFS_MAXPROPLEN);
2291
2292	err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
2293
2294	zfs_close(zhp);
2295
2296	if (err) {
2297		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err);
2298		NDMP_LOG(LOG_ERR, "error modifying property %s", newprop);
2299		return (-1);
2300	}
2301
2302	return (0);
2303}
2304
2305static boolean_t
2306ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor)
2307{
2308	(void) sscanf(propstr, "%u.%u.%*c%*s", major, minor);
2309
2310	if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) {
2311		NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)",
2312		    *major, NDMPD_ZFS_PROP_MAJOR_VERSION);
2313		return (B_FALSE);
2314	}
2315
2316	if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) {
2317		NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)",
2318		    *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
2319	}
2320
2321	NDMP_LOG(LOG_DEBUG, "passed version check: "
2322	    "supported prop major (%u <= %u); (snapprop minor: %u [%u])",
2323	    *major, NDMPD_ZFS_PROP_MAJOR_VERSION,
2324	    *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
2325
2326	return (B_TRUE);
2327}
2328
2329static int
2330ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
2331    char *snapname, int namelen)
2332{
2333	char subprop[ZFS_MAXPROPLEN];
2334	struct timeval tp;
2335	int err = 0;
2336
2337	(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
2338	    subprop, ZFS_MAXPROPLEN, B_FALSE);
2339
2340	(void) gettimeofday(&tp, NULL);
2341
2342	err = snprintf(snapname, namelen,
2343	    "ndmp.%s.%ld.%ld",
2344	    subprop,
2345	    tp.tv_sec,
2346	    tp.tv_usec);
2347
2348	if (err > namelen) {
2349		NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d",
2350		    snapname, namelen);
2351		return (-1);
2352	}
2353
2354	return (0);
2355}
2356
2357static void
2358ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args)
2359{
2360	switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) {
2361	case EZFS_EXISTS:
2362	case EZFS_BUSY:
2363	case EZFS_NOENT:
2364	case EZFS_INVALIDNAME:
2365	case EZFS_MOUNTFAILED:
2366	case EZFS_UMOUNTFAILED:
2367	case EZFS_NAMETOOLONG:
2368	case EZFS_BADRESTORE:
2369
2370		/* use existing error text */
2371
2372		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2373		    "%s: %s: %s\n",
2374		    ndmpd_zfs_args->nz_dataset,
2375		    libzfs_error_action(ndmpd_zfs_args->nz_zlibh),
2376		    libzfs_error_description(ndmpd_zfs_args->nz_zlibh));
2377
2378		break;
2379
2380	case EZFS_NOMEM:
2381		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2382		    "Unable to obtain memory for operation\n");
2383		break;
2384
2385	case EZFS_PROPSPACE:
2386		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2387		    "A bad ZFS quota or reservation was encountered.\n");
2388		break;
2389
2390	case EZFS_BADSTREAM:
2391		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2392		    "The backup stream is invalid.\n");
2393		break;
2394
2395	case EZFS_ZONED:
2396		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2397		    "An error related to the local zone occurred.\n");
2398		break;
2399
2400	case EZFS_NOSPC:
2401		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2402		    "No more space is available\n");
2403		break;
2404
2405	case EZFS_IO:
2406		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2407		    "An I/O error occurred.\n");
2408		break;
2409
2410	default:
2411		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2412		    "An internal ndmpd error occurred.  "
2413		    "Please contact support\n");
2414		break;
2415	}
2416}
2417
2418void
2419ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type,
2420    char *format, ...)
2421{
2422	static char buf[1024];
2423	va_list ap;
2424
2425	va_start(ap, format);
2426
2427	/*LINTED variable format specifier */
2428	(void) vsnprintf(buf, sizeof (buf), format, ap);
2429	va_end(ap);
2430
2431	MOD_LOGV3(ndmpd_zfs_params, log_type, buf);
2432
2433	if ((log_type) == NDMP_LOG_ERROR) {
2434		NDMP_LOG(LOG_ERR, buf);
2435	} else {
2436		NDMP_LOG(LOG_NOTICE, buf);
2437	}
2438}
2439