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