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