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