xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c (revision 82049ff5)
18c4f9701SJanice Chang /*
28c4f9701SJanice Chang  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
39adfa60dSMatthew Ahrens  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
48c4f9701SJanice Chang  */
58c4f9701SJanice Chang 
68c4f9701SJanice Chang /*
78c4f9701SJanice Chang  * BSD 3 Clause License
88c4f9701SJanice Chang  *
98c4f9701SJanice Chang  * Copyright (c) 2007, The Storage Networking Industry Association.
108c4f9701SJanice Chang  *
118c4f9701SJanice Chang  * Redistribution and use in source and binary forms, with or without
128c4f9701SJanice Chang  * modification, are permitted provided that the following conditions
138c4f9701SJanice Chang  * are met:
14*82049ff5SToomas Soome  *	- Redistributions of source code must retain the above copyright
158c4f9701SJanice Chang  *	  notice, this list of conditions and the following disclaimer.
168c4f9701SJanice Chang  *
17*82049ff5SToomas Soome  *	- Redistributions in binary form must reproduce the above copyright
188c4f9701SJanice Chang  *	  notice, this list of conditions and the following disclaimer in
198c4f9701SJanice Chang  *	  the documentation and/or other materials provided with the
208c4f9701SJanice Chang  *	  distribution.
218c4f9701SJanice Chang  *
228c4f9701SJanice Chang  *	- Neither the name of The Storage Networking Industry Association (SNIA)
238c4f9701SJanice Chang  *	  nor the names of its contributors may be used to endorse or promote
248c4f9701SJanice Chang  *	  products derived from this software without specific prior written
258c4f9701SJanice Chang  *	  permission.
268c4f9701SJanice Chang  *
278c4f9701SJanice Chang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
288c4f9701SJanice Chang  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
298c4f9701SJanice Chang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
308c4f9701SJanice Chang  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
318c4f9701SJanice Chang  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
328c4f9701SJanice Chang  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
338c4f9701SJanice Chang  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
348c4f9701SJanice Chang  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
358c4f9701SJanice Chang  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
368c4f9701SJanice Chang  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
378c4f9701SJanice Chang  * POSSIBILITY OF SUCH DAMAGE.
388c4f9701SJanice Chang  */
398c4f9701SJanice Chang /* Copyright (c) 2007, The Storage Networking Industry Association. */
408c4f9701SJanice Chang /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
418c4f9701SJanice Chang 
428c4f9701SJanice Chang #include <sys/types.h>
438c4f9701SJanice Chang #include <sys/param.h>
448c4f9701SJanice Chang #include <sys/lwp.h>
458c4f9701SJanice Chang #include <sys/fs/zfs.h>
468c4f9701SJanice Chang #include <sys/mtio.h>
478c4f9701SJanice Chang #include <sys/time.h>
488c4f9701SJanice Chang #include <unistd.h>
498c4f9701SJanice Chang #include <errno.h>
508c4f9701SJanice Chang #include <stdlib.h>
518c4f9701SJanice Chang #include <string.h>
528c4f9701SJanice Chang #include <ctype.h>
538c4f9701SJanice Chang #include <libzfs.h>
548c4f9701SJanice Chang #include <stdio.h>
558c4f9701SJanice Chang #include "ndmpd_common.h"
568c4f9701SJanice Chang #include "ndmpd.h"
578c4f9701SJanice Chang 
588c4f9701SJanice Chang typedef struct {
598c4f9701SJanice Chang 	char nzs_findprop[ZFS_MAXPROPLEN]; /* prop substring to find */
609adfa60dSMatthew Ahrens 	char nzs_snapname[ZFS_MAX_DATASET_NAME_LEN]; /* snap's name */
618c4f9701SJanice Chang 	char nzs_snapprop[ZFS_MAXPROPLEN]; /* snap's prop value */
628c4f9701SJanice Chang 	char nzs_snapskip[ZFS_MAXPROPLEN]; /* snap to skip */
638c4f9701SJanice Chang 	uint32_t nzs_prop_major;	   /* property major version */
648c4f9701SJanice Chang 	uint32_t nzs_prop_minor;	   /* property minor version */
658c4f9701SJanice Chang } ndmpd_zfs_snapfind_t;
668c4f9701SJanice Chang 
678c4f9701SJanice Chang mutex_t ndmpd_zfs_fd_lock;
688c4f9701SJanice Chang 
698c4f9701SJanice Chang static int ndmpd_zfs_open_fds(ndmpd_zfs_args_t *);
708c4f9701SJanice Chang static void ndmpd_zfs_close_fds(ndmpd_zfs_args_t *);
718c4f9701SJanice Chang 
728c4f9701SJanice Chang static void ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *, int);
738c4f9701SJanice Chang 
748c4f9701SJanice Chang static int ndmpd_zfs_header_write(ndmpd_session_t *);
758c4f9701SJanice Chang static int ndmpd_zfs_header_read(ndmpd_zfs_args_t *);
768c4f9701SJanice Chang 
77*82049ff5SToomas Soome static void *ndmpd_zfs_backup_send_read(void *);
78*82049ff5SToomas Soome static void *ndmpd_zfs_backup_tape_write(void *);
798c4f9701SJanice Chang 
808c4f9701SJanice Chang static int ndmpd_zfs_restore(ndmpd_zfs_args_t *);
81*82049ff5SToomas Soome static void *ndmpd_zfs_restore_tape_read(void *);
82*82049ff5SToomas Soome static void *ndmpd_zfs_restore_recv_write(void *);
838c4f9701SJanice Chang 
848c4f9701SJanice Chang static int ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *, int **, int **);
858c4f9701SJanice Chang 
86c1a2c731SJanice Chang static int ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *, u_longlong_t);
878c4f9701SJanice Chang 
888c4f9701SJanice Chang static boolean_t ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *);
898c4f9701SJanice Chang static int ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *, char *, int);
908c4f9701SJanice Chang static int ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *);
918c4f9701SJanice Chang 
928c4f9701SJanice Chang static boolean_t ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *);
938c4f9701SJanice Chang static int ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *);
948c4f9701SJanice Chang static int ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *);
958c4f9701SJanice Chang 
968c4f9701SJanice Chang static int ndmpd_zfs_getenv(ndmpd_zfs_args_t *);
978c4f9701SJanice Chang static int ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *);
988c4f9701SJanice Chang static int ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *);
998c4f9701SJanice Chang static int ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *);
1008c4f9701SJanice Chang static int ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *);
1018c4f9701SJanice Chang static int ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *);
102c1a2c731SJanice Chang static int ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *);
103c1a2c731SJanice Chang 
1048c4f9701SJanice Chang static boolean_t ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *, char *);
1058c4f9701SJanice Chang static boolean_t ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *);
106f9708870SReza Sabdar static int ndmpd_zfs_send_fhist(ndmpd_zfs_args_t *);
1078c4f9701SJanice Chang 
1088c4f9701SJanice Chang static int ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *);
1098c4f9701SJanice Chang static int ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *, int);
1108c4f9701SJanice Chang static int ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *);
1118c4f9701SJanice Chang static int ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *,
1128c4f9701SJanice Chang     boolean_t, ndmpd_zfs_snapfind_t *);
1138c4f9701SJanice Chang static boolean_t ndmpd_zfs_snapshot_ndmpd_generated(char *);
1148c4f9701SJanice Chang static int ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *, ndmpd_zfs_snapfind_t *);
1158c4f9701SJanice Chang 
1168c4f9701SJanice Chang static int ndmpd_zfs_snapshot_prop_find(zfs_handle_t *, void *);
1178c4f9701SJanice Chang static int ndmpd_zfs_snapshot_prop_get(zfs_handle_t *, char *);
1188c4f9701SJanice Chang static int ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *);
1198c4f9701SJanice Chang static int ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *, char *,
1208c4f9701SJanice Chang     boolean_t *);
1218c4f9701SJanice Chang static int ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *, char *, int,
1228c4f9701SJanice Chang     boolean_t);
1238c4f9701SJanice Chang static int ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *,
1248c4f9701SJanice Chang     ndmpd_zfs_snapfind_t *);
1258c4f9701SJanice Chang static boolean_t ndmpd_zfs_prop_version_check(char *, uint32_t *, uint32_t *);
1268c4f9701SJanice Chang 
1278c4f9701SJanice Chang static int ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *, char *, int);
1288c4f9701SJanice Chang 
1298c4f9701SJanice Chang static void ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *);
1308c4f9701SJanice Chang 
1318c4f9701SJanice Chang static int ndmpd_zfs_backup(ndmpd_zfs_args_t *);
1328c4f9701SJanice Chang 
1338c4f9701SJanice Chang /*
1348c4f9701SJanice Chang  * Syntax for com.sun.ndmp:incr property value:
1358c4f9701SJanice Chang  *	#.#.n|u/$LEVEL.$DMP_NAME.$ZFS_MODE(/ ...)
1368c4f9701SJanice Chang  *
1378c4f9701SJanice Chang  * where
1388c4f9701SJanice Chang  *	#.# is the version number
1398c4f9701SJanice Chang  *	'n' means ndmp-generated; 'u' means user-supplied
1408c4f9701SJanice Chang  *	$LEVEL: backup (incremental) level [0-9]
1418c4f9701SJanice Chang  *	$DMP_NAME: set name [default: "level"]
1428c4f9701SJanice Chang  *	$ZFS_MODE: d | r | p [for dataset, recursive, or package]
1438c4f9701SJanice Chang  *
1448c4f9701SJanice Chang  * Examples:
1458c4f9701SJanice Chang  *
146*82049ff5SToomas Soome  *	0.0.n/0.bob.p
147*82049ff5SToomas Soome  *	0.0.u/1.bob.p/0.jane.d
148d0194491SJanice Chang  *
149d0194491SJanice Chang  * Note: NDMPD_ZFS_SUBPROP_MAX is calculated based on ZFS_MAXPROPLEN
1508c4f9701SJanice Chang  */
1518c4f9701SJanice Chang 
1528c4f9701SJanice Chang #define	NDMPD_ZFS_PROP_INCR "com.sun.ndmp:incr"
153d0194491SJanice Chang #define	NDMPD_ZFS_SUBPROP_MAX	28
1548c4f9701SJanice Chang 
1558c4f9701SJanice Chang /*
1568c4f9701SJanice Chang  * NDMPD_ZFS_LOG_ZERR
1578c4f9701SJanice Chang  *
1588c4f9701SJanice Chang  * As coded, there should be no races in the retrieval of the ZFS errno
1598c4f9701SJanice Chang  * from the ndmpd_zfs_args->nz_zlibh.  I.e., for a given ndmpd_zfs backup
1608c4f9701SJanice Chang  * or restore, there should only ever be one ZFS library call taking place
1618c4f9701SJanice Chang  * at any one moment in time.
1628c4f9701SJanice Chang  */
1638c4f9701SJanice Chang 
1648c4f9701SJanice Chang #define	NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, ...) {			\
1658c4f9701SJanice Chang 	NDMP_LOG(LOG_ERR, __VA_ARGS__);					\
1668c4f9701SJanice Chang 	NDMP_LOG(LOG_ERR, "%s--%s",					\
167*82049ff5SToomas Soome 	    libzfs_error_action((ndmpd_zfs_args)->nz_zlibh),		\
168*82049ff5SToomas Soome 	    libzfs_error_description((ndmpd_zfs_args)->nz_zlibh));	\
1698c4f9701SJanice Chang 	ndmpd_zfs_zerr_dma_log((ndmpd_zfs_args));			\
1708c4f9701SJanice Chang }
1718c4f9701SJanice Chang 
1728c4f9701SJanice Chang int
ndmpd_zfs_init(ndmpd_session_t * session)1738c4f9701SJanice Chang ndmpd_zfs_init(ndmpd_session_t *session)
1748c4f9701SJanice Chang {
1758c4f9701SJanice Chang 	ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
1768c4f9701SJanice Chang 	int version = session->ns_protocol_version;
1778c4f9701SJanice Chang 
1788c4f9701SJanice Chang 	bzero(ndmpd_zfs_args, sizeof (*ndmpd_zfs_args));
1798c4f9701SJanice Chang 
1808c4f9701SJanice Chang 	if ((version < NDMPV3) || (version > NDMPV4)) {
1818c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "Unknown or unsupported version %d", version);
1828c4f9701SJanice Chang 		return (-1);
1838c4f9701SJanice Chang 	}
1848c4f9701SJanice Chang 
1858c4f9701SJanice Chang 	if ((ndmpd_zfs_args->nz_zlibh = libzfs_init()) == NULL) {
1868c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "libzfs init error [%d]", errno);
1878c4f9701SJanice Chang 		return (-1);
1888c4f9701SJanice Chang 	}
1898c4f9701SJanice Chang 
1908c4f9701SJanice Chang 	if (ndmpd_zfs_open_fds(ndmpd_zfs_args) < 0) {
1918c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "open_fds() failure(): %d\n", errno);
1928c4f9701SJanice Chang 		return (-1);
1938c4f9701SJanice Chang 	}
1948c4f9701SJanice Chang 
1958c4f9701SJanice Chang 	ndmpd_zfs_args->nz_bufsize = ndmp_buffer_get_size(session);
1968c4f9701SJanice Chang 	ndmpd_zfs_args->nz_window_len = session->ns_mover.md_window_length;
1978c4f9701SJanice Chang 
1988c4f9701SJanice Chang 	ndmpd_zfs_args->nz_nlp = ndmp_get_nlp(session);
1998c4f9701SJanice Chang 
2008c4f9701SJanice Chang 	assert(ndmpd_zfs_args->nz_nlp != NULL);
2018c4f9701SJanice Chang 
2028c4f9701SJanice Chang 	ndmpd_zfs_args->nz_nlp->nlp_bytes_total = 0;
2038c4f9701SJanice Chang 
2048c4f9701SJanice Chang 	session->ns_data.dd_module.dm_module_cookie = ndmpd_zfs_args;
2058c4f9701SJanice Chang 	session->ns_data.dd_data_size = 0;
2068c4f9701SJanice Chang 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2078c4f9701SJanice Chang 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining  = 0;
2088c4f9701SJanice Chang 
2098c4f9701SJanice Chang 	session->ns_data.dd_bytes_left_to_read = 0;
2108c4f9701SJanice Chang 	session->ns_data.dd_position = 0;
2118c4f9701SJanice Chang 	session->ns_data.dd_discard_length = 0;
2128c4f9701SJanice Chang 	session->ns_data.dd_read_offset = 0;
2138c4f9701SJanice Chang 	session->ns_data.dd_read_length = 0;
2148c4f9701SJanice Chang 
2158c4f9701SJanice Chang 	ndmpd_zfs_params->mp_get_env_func = ndmpd_api_get_env;
2168c4f9701SJanice Chang 	ndmpd_zfs_params->mp_add_env_func = ndmpd_api_add_env;
2178c4f9701SJanice Chang 	ndmpd_zfs_params->mp_set_env_func = ndmpd_api_set_env;
2188c4f9701SJanice Chang 	ndmpd_zfs_params->mp_dispatch_func = ndmpd_api_dispatch;
2198c4f9701SJanice Chang 	ndmpd_zfs_params->mp_daemon_cookie = (void *)session;
2208c4f9701SJanice Chang 	ndmpd_zfs_params->mp_protocol_version = session->ns_protocol_version;
2218c4f9701SJanice Chang 	ndmpd_zfs_params->mp_stats = &session->ns_data.dd_module.dm_stats;
2228c4f9701SJanice Chang 	ndmpd_zfs_params->mp_add_file_handler_func =
2238c4f9701SJanice Chang 	    ndmpd_api_add_file_handler;
2248c4f9701SJanice Chang 	ndmpd_zfs_params->mp_remove_file_handler_func =
2258c4f9701SJanice Chang 	    ndmpd_api_remove_file_handler;
2268c4f9701SJanice Chang 	ndmpd_zfs_params->mp_seek_func = 0;
2278c4f9701SJanice Chang 
2288c4f9701SJanice Chang 	switch (version) {
2298c4f9701SJanice Chang 	case NDMPV3:
2308c4f9701SJanice Chang 		ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
2318c4f9701SJanice Chang 		ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
2328c4f9701SJanice Chang 		ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
2338c4f9701SJanice Chang 		ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
2348c4f9701SJanice Chang 		ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v3;
2358c4f9701SJanice Chang 		ndmpd_zfs_params->mp_file_recovered_func =
2368c4f9701SJanice Chang 		    ndmpd_api_file_recovered_v3;
2378c4f9701SJanice Chang 		break;
2388c4f9701SJanice Chang 	case NDMPV4:
2398c4f9701SJanice Chang 		ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
2408c4f9701SJanice Chang 		ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
2418c4f9701SJanice Chang 		ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
2428c4f9701SJanice Chang 		ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
2438c4f9701SJanice Chang 		ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v4;
2448c4f9701SJanice Chang 		ndmpd_zfs_params->mp_file_recovered_func =
2458c4f9701SJanice Chang 		    ndmpd_api_file_recovered_v4;
2468c4f9701SJanice Chang 		break;
2478c4f9701SJanice Chang 	default:
2488c4f9701SJanice Chang 		/* error already returned above for this case */
2498c4f9701SJanice Chang 		break;
2508c4f9701SJanice Chang 	}
2518c4f9701SJanice Chang 
2528c4f9701SJanice Chang 	return (0);
2538c4f9701SJanice Chang }
2548c4f9701SJanice Chang 
2558c4f9701SJanice Chang void
ndmpd_zfs_fini(ndmpd_zfs_args_t * ndmpd_zfs_args)2568c4f9701SJanice Chang ndmpd_zfs_fini(ndmpd_zfs_args_t *ndmpd_zfs_args)
2578c4f9701SJanice Chang {
2588c4f9701SJanice Chang 	libzfs_fini(ndmpd_zfs_args->nz_zlibh);
2598c4f9701SJanice Chang 
2608c4f9701SJanice Chang 	ndmpd_zfs_close_fds(ndmpd_zfs_args);
2618c4f9701SJanice Chang }
2628c4f9701SJanice Chang 
2638c4f9701SJanice Chang static int
ndmpd_zfs_open_fds(ndmpd_zfs_args_t * ndmpd_zfs_args)2648c4f9701SJanice Chang ndmpd_zfs_open_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
2658c4f9701SJanice Chang {
2668c4f9701SJanice Chang 	int err;
2678c4f9701SJanice Chang 
2688c4f9701SJanice Chang 	err = pipe(ndmpd_zfs_args->nz_pipe_fd);
2698c4f9701SJanice Chang 	if (err)
2708c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n", strerror(errno));
2718c4f9701SJanice Chang 
2728c4f9701SJanice Chang 	return (err);
2738c4f9701SJanice Chang }
2748c4f9701SJanice Chang 
2758c4f9701SJanice Chang /*
2768c4f9701SJanice Chang  * ndmpd_zfs_close_fds()
2778c4f9701SJanice Chang  *
2788c4f9701SJanice Chang  * In the abort case, use dup2() to redirect the end of the pipe that is
2798c4f9701SJanice Chang  * being written to (to a new pipe).  Close the ends of the new pipe to cause
2808c4f9701SJanice Chang  * EPIPE to be returned to the writing thread.  This will cause the writer
2818c4f9701SJanice Chang  * and reader to terminate without having any of the writer's data erroneously
2828c4f9701SJanice Chang  * go to any reopened descriptor.
2838c4f9701SJanice Chang  */
2848c4f9701SJanice Chang 
2858c4f9701SJanice Chang static void
ndmpd_zfs_close_fds(ndmpd_zfs_args_t * ndmpd_zfs_args)2868c4f9701SJanice Chang ndmpd_zfs_close_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
2878c4f9701SJanice Chang {
2888c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
2898c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
2908c4f9701SJanice Chang 	int pipe_end;
2918c4f9701SJanice Chang 	int fds[2];
2928c4f9701SJanice Chang 
2938c4f9701SJanice Chang 	if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE) {
2948c4f9701SJanice Chang 		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
2958c4f9701SJanice Chang 		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
2968c4f9701SJanice Chang 		return;
2978c4f9701SJanice Chang 	}
2988c4f9701SJanice Chang 
2998c4f9701SJanice Chang 	(void) mutex_lock(&ndmpd_zfs_fd_lock);
3008c4f9701SJanice Chang 
3018c4f9701SJanice Chang 	if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) {
3028c4f9701SJanice Chang 		pipe_end = PIPE_ZFS;
3038c4f9701SJanice Chang 	} else {
3048c4f9701SJanice Chang 		pipe_end = PIPE_TAPE;
3058c4f9701SJanice Chang 	}
3068c4f9701SJanice Chang 
3078c4f9701SJanice Chang 	if (ndmpd_zfs_args->nz_pipe_fd[pipe_end] != -1) {
3088c4f9701SJanice Chang 		if (pipe(fds) != 0) {
3098c4f9701SJanice Chang 			(void) mutex_unlock(&ndmpd_zfs_fd_lock);
3108c4f9701SJanice Chang 			NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n",
3118c4f9701SJanice Chang 			    strerror(errno));
3128c4f9701SJanice Chang 			return;
3138c4f9701SJanice Chang 		}
3148c4f9701SJanice Chang 
3158c4f9701SJanice Chang 		(void) dup2(fds[0], ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
3168c4f9701SJanice Chang 		(void) close(fds[0]);
3178c4f9701SJanice Chang 		(void) close(fds[1]);
3188c4f9701SJanice Chang 
3198c4f9701SJanice Chang 		ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
3208c4f9701SJanice Chang 	}
3218c4f9701SJanice Chang 
3228c4f9701SJanice Chang 	(void) mutex_unlock(&ndmpd_zfs_fd_lock);
3238c4f9701SJanice Chang }
3248c4f9701SJanice Chang 
3258c4f9701SJanice Chang static void
ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t * ndmpd_zfs_args,int pipe_end)3268c4f9701SJanice Chang ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *ndmpd_zfs_args, int pipe_end)
3278c4f9701SJanice Chang {
3288c4f9701SJanice Chang 	(void) mutex_lock(&ndmpd_zfs_fd_lock);
3298c4f9701SJanice Chang 	(void) close(ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
3308c4f9701SJanice Chang 	ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
3318c4f9701SJanice Chang 	(void) mutex_unlock(&ndmpd_zfs_fd_lock);
3328c4f9701SJanice Chang }
3338c4f9701SJanice Chang 
3348c4f9701SJanice Chang static int
ndmpd_zfs_header_write(ndmpd_session_t * session)3358c4f9701SJanice Chang ndmpd_zfs_header_write(ndmpd_session_t *session)
3368c4f9701SJanice Chang {
3378c4f9701SJanice Chang 	ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
3388c4f9701SJanice Chang 	int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
3398c4f9701SJanice Chang 	ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
3408c4f9701SJanice Chang 	char *buf;
3418c4f9701SJanice Chang 
3428c4f9701SJanice Chang 	buf = ndmp_malloc(bufsize);
3438c4f9701SJanice Chang 	if (buf == NULL) {
3448c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "buf NULL");
3458c4f9701SJanice Chang 		return (-1);
3468c4f9701SJanice Chang 	}
3478c4f9701SJanice Chang 
3488c4f9701SJanice Chang 	(void) strlcpy(tape_header->nzh_magic, NDMPUTF8MAGIC,
3498c4f9701SJanice Chang 	    sizeof (NDMPUTF8MAGIC));
3508c4f9701SJanice Chang 	tape_header->nzh_major = LE_32(NDMPD_ZFS_MAJOR_VERSION);
3518c4f9701SJanice Chang 	tape_header->nzh_minor = LE_32(NDMPD_ZFS_MINOR_VERSION);
3528c4f9701SJanice Chang 	tape_header->nzh_hdrlen = LE_32(bufsize);
3538c4f9701SJanice Chang 
3548c4f9701SJanice Chang 	bzero(buf, bufsize);
3558c4f9701SJanice Chang 	(void) memcpy(buf, tape_header, sizeof (ndmpd_zfs_header_t));
3568c4f9701SJanice Chang 
3578c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "header (major, minor, length): %u %u %u",
3588c4f9701SJanice Chang 	    NDMPD_ZFS_MAJOR_VERSION,
3598c4f9701SJanice Chang 	    NDMPD_ZFS_MINOR_VERSION,
3608c4f9701SJanice Chang 	    bufsize);
3618c4f9701SJanice Chang 
3628c4f9701SJanice Chang 	if (MOD_WRITE(ndmpd_zfs_params, buf, bufsize) != 0) {
3638c4f9701SJanice Chang 		free(buf);
3648c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "MOD_WRITE error");
3658c4f9701SJanice Chang 		return (-1);
3668c4f9701SJanice Chang 	}
3678c4f9701SJanice Chang 
3688c4f9701SJanice Chang 	free(buf);
3698c4f9701SJanice Chang 
3708c4f9701SJanice Chang 	session->ns_data.dd_module.dm_stats.ms_bytes_processed = bufsize;
3718c4f9701SJanice Chang 
3728c4f9701SJanice Chang 	return (0);
3738c4f9701SJanice Chang }
3748c4f9701SJanice Chang 
3758c4f9701SJanice Chang static int
ndmpd_zfs_header_read(ndmpd_zfs_args_t * ndmpd_zfs_args)3768c4f9701SJanice Chang ndmpd_zfs_header_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
3778c4f9701SJanice Chang {
3788c4f9701SJanice Chang 	int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
3798c4f9701SJanice Chang 	ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
3808c4f9701SJanice Chang 	uint32_t hdrlen;
3818c4f9701SJanice Chang 	int32_t header_left;
3828c4f9701SJanice Chang 	int err;
3838c4f9701SJanice Chang 	char *buf;
3848c4f9701SJanice Chang 
3858c4f9701SJanice Chang 	buf = ndmp_malloc(bufsize);
3868c4f9701SJanice Chang 	if (buf == NULL) {
3878c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "buf NULL");
3888c4f9701SJanice Chang 		return (-1);
3898c4f9701SJanice Chang 	}
3908c4f9701SJanice Chang 
3918c4f9701SJanice Chang 	bzero(buf, bufsize);
3928c4f9701SJanice Chang 
3938c4f9701SJanice Chang 	/*
3948c4f9701SJanice Chang 	 * Read nz_bufsize worth of bytes first (the size of a mover record).
3958c4f9701SJanice Chang 	 */
3968c4f9701SJanice Chang 
3978c4f9701SJanice Chang 	err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
3988c4f9701SJanice Chang 
3998c4f9701SJanice Chang 	if (err != 0) {
4008c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "MOD_READ error: %d", err);
4018c4f9701SJanice Chang 		free(buf);
4028c4f9701SJanice Chang 		return (-1);
4038c4f9701SJanice Chang 	}
4048c4f9701SJanice Chang 
4058c4f9701SJanice Chang 	(void) memcpy(tape_header, buf, sizeof (ndmpd_zfs_header_t));
4068c4f9701SJanice Chang 
4078c4f9701SJanice Chang 	if (strcmp(tape_header->nzh_magic, NDMPUTF8MAGIC) != 0) {
4088c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
4098c4f9701SJanice Chang 		    "bad magic string\n");
4108c4f9701SJanice Chang 		goto _err;
4118c4f9701SJanice Chang 	}
4128c4f9701SJanice Chang 
4138c4f9701SJanice Chang 	if (tape_header->nzh_major > LE_32(NDMPD_ZFS_MAJOR_VERSION)) {
4148c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
4158c4f9701SJanice Chang 		    "major number larger than supported: (%d %d)\n",
4168c4f9701SJanice Chang 		    LE_32(tape_header->nzh_major), NDMPD_ZFS_MAJOR_VERSION);
4178c4f9701SJanice Chang 		goto _err;
4188c4f9701SJanice Chang 	}
4198c4f9701SJanice Chang 
4208c4f9701SJanice Chang 	/*
4218c4f9701SJanice Chang 	 * Major version 0 (regardless of minor version):
4228c4f9701SJanice Chang 	 * Header must be a multiple of the mover record size.
4238c4f9701SJanice Chang 	 */
4248c4f9701SJanice Chang 
4258c4f9701SJanice Chang 	hdrlen = LE_32(tape_header->nzh_hdrlen);
4268c4f9701SJanice Chang 	if (hdrlen > bufsize) {
4278c4f9701SJanice Chang 		header_left = hdrlen - bufsize;
4288c4f9701SJanice Chang 		while (header_left > 0) {
4298c4f9701SJanice Chang 			err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
4308c4f9701SJanice Chang 			if (err == -1) {
4318c4f9701SJanice Chang 				ndmpd_zfs_dma_log(ndmpd_zfs_args,
4328c4f9701SJanice Chang 				    NDMP_LOG_ERROR, "bad header\n");
4338c4f9701SJanice Chang 				goto _err;
4348c4f9701SJanice Chang 			}
4358c4f9701SJanice Chang 			header_left -= bufsize;
4368c4f9701SJanice Chang 		}
4378c4f9701SJanice Chang 	}
4388c4f9701SJanice Chang 
4398c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "tape header: %s; %u %u; %u ",
4408c4f9701SJanice Chang 	    tape_header->nzh_magic,
4418c4f9701SJanice Chang 	    LE_32(tape_header->nzh_major),
4428c4f9701SJanice Chang 	    LE_32(tape_header->nzh_minor),
4438c4f9701SJanice Chang 	    LE_32(tape_header->nzh_hdrlen));
4448c4f9701SJanice Chang 
4458c4f9701SJanice Chang 	ndmpd_zfs_args->nz_nlp->nlp_bytes_total = hdrlen;
4468c4f9701SJanice Chang 
4478c4f9701SJanice Chang 	free(buf);
4488c4f9701SJanice Chang 	return (0);
4498c4f9701SJanice Chang 
4508c4f9701SJanice Chang _err:
4518c4f9701SJanice Chang 
4528c4f9701SJanice Chang 	NDMP_LOG(LOG_ERR, "tape header: %s; %u %u; %u ",
4538c4f9701SJanice Chang 	    tape_header->nzh_magic,
4548c4f9701SJanice Chang 	    LE_32(tape_header->nzh_major),
4558c4f9701SJanice Chang 	    LE_32(tape_header->nzh_minor),
4568c4f9701SJanice Chang 	    LE_32(tape_header->nzh_hdrlen));
4578c4f9701SJanice Chang 
4588c4f9701SJanice Chang 	free(buf);
4598c4f9701SJanice Chang 	return (-1);
4608c4f9701SJanice Chang }
4618c4f9701SJanice Chang 
462*82049ff5SToomas Soome void *
ndmpd_zfs_backup_starter(void * arg)4638c4f9701SJanice Chang ndmpd_zfs_backup_starter(void *arg)
4648c4f9701SJanice Chang {
4658c4f9701SJanice Chang 	ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
4668c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
4678c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
4688c4f9701SJanice Chang 	int cleanup_err = 0;
4698c4f9701SJanice Chang 	int err = 0;
4708c4f9701SJanice Chang 
4718c4f9701SJanice Chang 	ndmp_session_ref(session);
4728c4f9701SJanice Chang 
4738c4f9701SJanice Chang 	if (ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args) != 0) {
4748c4f9701SJanice Chang 		err = -1;
4758c4f9701SJanice Chang 		goto _done;
4768c4f9701SJanice Chang 	}
4778c4f9701SJanice Chang 
4788c4f9701SJanice Chang 	err = ndmpd_zfs_backup(ndmpd_zfs_args);
4798c4f9701SJanice Chang 
4808c4f9701SJanice Chang 	cleanup_err = ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args, err);
4818c4f9701SJanice Chang 
4828c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG,
4838c4f9701SJanice Chang 	    "data bytes_total(including header):%llu",
4848c4f9701SJanice Chang 	    session->ns_data.dd_module.dm_stats.ms_bytes_processed);
4858c4f9701SJanice Chang 
486f9708870SReza Sabdar 	if (err == 0)
487f9708870SReza Sabdar 		err = ndmpd_zfs_send_fhist(ndmpd_zfs_args);
4888c4f9701SJanice Chang 
4898c4f9701SJanice Chang _done:
4908c4f9701SJanice Chang 	NS_DEC(nbk);
4918c4f9701SJanice Chang 	MOD_DONE(ndmpd_zfs_params, err ? err : cleanup_err);
4928c4f9701SJanice Chang 	ndmp_session_unref(session);
4938c4f9701SJanice Chang 	ndmpd_zfs_fini(ndmpd_zfs_args);
4948c4f9701SJanice Chang 
495*82049ff5SToomas Soome 	return ((void *)(uintptr_t)err);
4968c4f9701SJanice Chang }
4978c4f9701SJanice Chang 
498f9708870SReza Sabdar static int
ndmpd_zfs_send_fhist(ndmpd_zfs_args_t * ndmpd_zfs_args)499f9708870SReza Sabdar ndmpd_zfs_send_fhist(ndmpd_zfs_args_t *ndmpd_zfs_args)
500f9708870SReza Sabdar {
501f9708870SReza Sabdar 	ndmpd_session_t *session = (ndmpd_session_t *)
502f9708870SReza Sabdar 	    (ndmpd_zfs_params->mp_daemon_cookie);
503f9708870SReza Sabdar 	struct stat64 st;
504f9708870SReza Sabdar 	char *envp;
505f9708870SReza Sabdar 
506f9708870SReza Sabdar 	envp = MOD_GETENV(ndmpd_zfs_params, "HIST");
507f9708870SReza Sabdar 	if (!envp)
508f9708870SReza Sabdar 		return (0);
509f9708870SReza Sabdar 
510f9708870SReza Sabdar 	if (!(strchr("YT", toupper(*envp)))) {
511f9708870SReza Sabdar 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
512f9708870SReza Sabdar 		    "HIST is not set.  No file history will be "
513f9708870SReza Sabdar 		    "generated.\n");
514f9708870SReza Sabdar 		return (0);
515f9708870SReza Sabdar 	}
516f9708870SReza Sabdar 
517f3012b59SReza Sabdar 	/* Build up a sample root dir stat */
518f3012b59SReza Sabdar 	(void) memset(&st, 0, sizeof (struct stat64));
519f3012b59SReza Sabdar 	st.st_mode = S_IFDIR | 0777;
520f3012b59SReza Sabdar 	st.st_mtime = st.st_atime = st.st_ctime = time(NULL);
521f3012b59SReza Sabdar 	st.st_uid = st.st_gid = 0;
522f3012b59SReza Sabdar 	st.st_size = 1;
523f3012b59SReza Sabdar 	st.st_nlink = 1;
524f9708870SReza Sabdar 
525f9708870SReza Sabdar 	if (ndmpd_api_file_history_dir_v3(session, ".", ROOT_INODE,
526f9708870SReza Sabdar 	    ROOT_INODE) != 0)
527f9708870SReza Sabdar 		return (-1);
528f9708870SReza Sabdar 	if (ndmpd_api_file_history_dir_v3(session, "..", ROOT_INODE,
529f9708870SReza Sabdar 	    ROOT_INODE) != 0)
530f9708870SReza Sabdar 		return (-1);
531f9708870SReza Sabdar 	if (ndmpd_api_file_history_node_v3(session, ROOT_INODE, &st, 0) != 0)
532f9708870SReza Sabdar 		return (-1);
533f9708870SReza Sabdar 
534f9708870SReza Sabdar 	ndmpd_file_history_cleanup(session, TRUE);
535f9708870SReza Sabdar 	return (0);
536f9708870SReza Sabdar }
537f9708870SReza Sabdar 
5388c4f9701SJanice Chang static int
ndmpd_zfs_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)5398c4f9701SJanice Chang ndmpd_zfs_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
5408c4f9701SJanice Chang {
5418c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
5428c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
5438c4f9701SJanice Chang 	int *read_err = NULL;
5448c4f9701SJanice Chang 	int *write_err = NULL;
5458c4f9701SJanice Chang 	int result = 0;
5468c4f9701SJanice Chang 	int err;
5478c4f9701SJanice Chang 
5488c4f9701SJanice Chang 	if (session->ns_eof)
5498c4f9701SJanice Chang 		return (-1);
5508c4f9701SJanice Chang 
5518c4f9701SJanice Chang 	if (!session->ns_data.dd_abort) {
5528c4f9701SJanice Chang 		if (ndmpd_zfs_header_write(session)) {
5538c4f9701SJanice Chang 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
5548c4f9701SJanice Chang 			    "ndmpd_zfs header write error\n");
5558c4f9701SJanice Chang 			return (-1);
5568c4f9701SJanice Chang 		}
5578c4f9701SJanice Chang 
5588c4f9701SJanice Chang 		err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
5598c4f9701SJanice Chang 		    &read_err, &write_err);
5608c4f9701SJanice Chang 
5618c4f9701SJanice Chang 		if (err || read_err || write_err || session->ns_eof)
5628c4f9701SJanice Chang 			result = EPIPE;
5638c4f9701SJanice Chang 	}
5648c4f9701SJanice Chang 
5658c4f9701SJanice Chang 	if (session->ns_data.dd_abort) {
5668c4f9701SJanice Chang 		ndmpd_audit_backup(session->ns_connection,
5678c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset,
5688c4f9701SJanice Chang 		    session->ns_data.dd_data_addr.addr_type,
5698c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset, EINTR);
5708c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
5718c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset);
5728c4f9701SJanice Chang 
5738c4f9701SJanice Chang 		(void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
5748c4f9701SJanice Chang 		err = -1;
5758c4f9701SJanice Chang 	} else {
5768c4f9701SJanice Chang 		ndmpd_audit_backup(session->ns_connection,
5778c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset,
5788c4f9701SJanice Chang 		    session->ns_data.dd_data_addr.addr_type,
5798c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset, result);
5808c4f9701SJanice Chang 
5818c4f9701SJanice Chang 		err = ndmpd_zfs_post_backup(ndmpd_zfs_args);
5828c4f9701SJanice Chang 		if (err || result)
5838c4f9701SJanice Chang 			err = -1;
5848c4f9701SJanice Chang 
5858c4f9701SJanice Chang 		if (err == 0)  {
5868c4f9701SJanice Chang 			NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished.",
5878c4f9701SJanice Chang 			    ndmpd_zfs_args->nz_dataset);
5888c4f9701SJanice Chang 		} else {
5898c4f9701SJanice Chang 			NDMP_LOG(LOG_DEBUG, "An error occurred while backing up"
5908c4f9701SJanice Chang 			    " \"%s\"", ndmpd_zfs_args->nz_dataset);
5918c4f9701SJanice Chang 		}
5928c4f9701SJanice Chang 	}
5938c4f9701SJanice Chang 
5948c4f9701SJanice Chang 	return (err);
5958c4f9701SJanice Chang }
5968c4f9701SJanice Chang 
5978c4f9701SJanice Chang /*
5988c4f9701SJanice Chang  * ndmpd_zfs_backup_send_read()
5998c4f9701SJanice Chang  *
6008c4f9701SJanice Chang  * This routine executes zfs_send() to create the backup data stream.
6018c4f9701SJanice Chang  * The value of ZFS_MODE determines the type of zfs_send():
602*82049ff5SToomas Soome  *	dataset ('d'): Only the dataset specified (i.e., top level) is backed up
603*82049ff5SToomas Soome  *	recursive ('r'): The dataset and its child file systems are backed up
604*82049ff5SToomas Soome  *	package ('p'): Same as 'r', except all intermediate snapshots are also
6058c4f9701SJanice Chang  *			backed up
6068c4f9701SJanice Chang  *
6078c4f9701SJanice Chang  * Volumes do not have descednants, so 'd' and 'r' produce equivalent results.
6088c4f9701SJanice Chang  */
6098c4f9701SJanice Chang 
610*82049ff5SToomas Soome static void *
ndmpd_zfs_backup_send_read(void * ptr)611*82049ff5SToomas Soome ndmpd_zfs_backup_send_read(void *ptr)
6128c4f9701SJanice Chang {
613*82049ff5SToomas Soome 	ndmpd_zfs_args_t *ndmpd_zfs_args = ptr;
6148c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
6158c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
6168c4f9701SJanice Chang 	sendflags_t flags = { 0 };
6178c4f9701SJanice Chang 	char *fromsnap = NULL;
6188c4f9701SJanice Chang 	zfs_handle_t *zhp;
6198c4f9701SJanice Chang 	int err;
6208c4f9701SJanice Chang 
6218c4f9701SJanice Chang 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
6228c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
6238c4f9701SJanice Chang 
6248c4f9701SJanice Chang 	if (!zhp) {
6258c4f9701SJanice Chang 		if (!session->ns_data.dd_abort)
6268c4f9701SJanice Chang 			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
627*82049ff5SToomas Soome 		return ((void *)(uintptr_t)-1);
6288c4f9701SJanice Chang 	}
6298c4f9701SJanice Chang 
6308c4f9701SJanice Chang 	switch (ndmpd_zfs_args->nz_zfs_mode) {
6318c4f9701SJanice Chang 	case ('d'):
6328c4f9701SJanice Chang 		flags.props = B_TRUE;
6338c4f9701SJanice Chang 		break;
6348c4f9701SJanice Chang 	case ('r'):
6358c4f9701SJanice Chang 		flags.replicate = B_TRUE;
6368c4f9701SJanice Chang 		break;
6378c4f9701SJanice Chang 	case ('p'):
6388c4f9701SJanice Chang 		flags.doall = B_TRUE;
6398c4f9701SJanice Chang 		flags.replicate = B_TRUE;
6408c4f9701SJanice Chang 		break;
6418c4f9701SJanice Chang 	default:
6428c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c",
6438c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_zfs_mode);
6448c4f9701SJanice Chang 		zfs_close(zhp);
645*82049ff5SToomas Soome 		return ((void *)(uintptr_t)-1);
6468c4f9701SJanice Chang 	}
6478c4f9701SJanice Chang 
6488c4f9701SJanice Chang 	if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
6498c4f9701SJanice Chang 		if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') {
6508c4f9701SJanice Chang 			NDMP_LOG(LOG_ERR, "no fromsnap");
6518c4f9701SJanice Chang 			zfs_close(zhp);
652*82049ff5SToomas Soome 			return ((void *)(uintptr_t)-1);
6538c4f9701SJanice Chang 		}
6548c4f9701SJanice Chang 		fromsnap = ndmpd_zfs_args->nz_fromsnap;
6558c4f9701SJanice Chang 	}
6568c4f9701SJanice Chang 
65719b94df9SMatthew Ahrens 	err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, &flags,
6583f9d6ad7SLin Ling 	    ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL);
6598c4f9701SJanice Chang 
6608c4f9701SJanice Chang 	if (err && !session->ns_data.dd_abort)
6618c4f9701SJanice Chang 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err);
6628c4f9701SJanice Chang 
6638c4f9701SJanice Chang 	zfs_close(zhp);
6648c4f9701SJanice Chang 
665*82049ff5SToomas Soome 	return ((void *)(uintptr_t)err);
6668c4f9701SJanice Chang }
6678c4f9701SJanice Chang 
6688c4f9701SJanice Chang /*
6698c4f9701SJanice Chang  * ndmpd_zfs_backup_tape_write()
6708c4f9701SJanice Chang  *
6718c4f9701SJanice Chang  * The data begins on a mover record boundary (because
6728c4f9701SJanice Chang  * the header is the size of a mover record--i.e.
6738c4f9701SJanice Chang  * ndmpd_zfs_args->nz_bufsize).
6748c4f9701SJanice Chang  */
6758c4f9701SJanice Chang 
676*82049ff5SToomas Soome static void *
ndmpd_zfs_backup_tape_write(void * ptr)677*82049ff5SToomas Soome ndmpd_zfs_backup_tape_write(void *ptr)
6788c4f9701SJanice Chang {
679*82049ff5SToomas Soome 	ndmpd_zfs_args_t *ndmpd_zfs_args = ptr;
6808c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
6818c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
6828c4f9701SJanice Chang 	int bufsize = ndmpd_zfs_args->nz_bufsize;
6838c4f9701SJanice Chang 	u_longlong_t *bytes_totalp;
6848c4f9701SJanice Chang 	int count;
6858c4f9701SJanice Chang 	char *buf;
6868c4f9701SJanice Chang 
6878c4f9701SJanice Chang 	buf = ndmp_malloc(bufsize);
6888c4f9701SJanice Chang 	if (buf == NULL) {
6898c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "buf NULL");
690*82049ff5SToomas Soome 		return ((void *)(uintptr_t)-1);
6918c4f9701SJanice Chang 	}
6928c4f9701SJanice Chang 
6938c4f9701SJanice Chang 	bytes_totalp =
6948c4f9701SJanice Chang 	    &(session->ns_data.dd_module.dm_stats.ms_bytes_processed);
6958c4f9701SJanice Chang 
6968c4f9701SJanice Chang 	for (;;) {
6978c4f9701SJanice Chang 		bzero(buf, bufsize);
6988c4f9701SJanice Chang 
6998c4f9701SJanice Chang 		count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
7008c4f9701SJanice Chang 		    bufsize);
7018c4f9701SJanice Chang 
7028c4f9701SJanice Chang 		if (count == 0) /* EOF */ {
7038c4f9701SJanice Chang 			NDMP_LOG(LOG_DEBUG,
704c1a2c731SJanice Chang 			    "zfs_send stream size: %llu bytes; "
705c1a2c731SJanice Chang 			    "full backup size (including header): %llu",
706c1a2c731SJanice Chang 			    *bytes_totalp - bufsize, *bytes_totalp);
7078c4f9701SJanice Chang 			free(buf);
708c1a2c731SJanice Chang 
709*82049ff5SToomas Soome 			return ((void *)(uintptr_t)
710*82049ff5SToomas Soome 			    ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args,
711c1a2c731SJanice Chang 			    *bytes_totalp));
7128c4f9701SJanice Chang 		}
7138c4f9701SJanice Chang 
7148c4f9701SJanice Chang 		if (count == -1) {
7158c4f9701SJanice Chang 			NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)",
7168c4f9701SJanice Chang 			    errno);
7178c4f9701SJanice Chang 			free(buf);
718*82049ff5SToomas Soome 			return ((void *)(uintptr_t)-1);
7198c4f9701SJanice Chang 		}
720f9708870SReza Sabdar 		NS_ADD(rdisk, count);
7218c4f9701SJanice Chang 
7228c4f9701SJanice Chang 		if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) {
7238c4f9701SJanice Chang 			(void) ndmpd_zfs_abort((void *) ndmpd_zfs_args);
7248c4f9701SJanice Chang 			NDMP_LOG(LOG_ERR, "MOD_WRITE error");
7258c4f9701SJanice Chang 			free(buf);
726*82049ff5SToomas Soome 			return ((void *)(uintptr_t)-1);
7278c4f9701SJanice Chang 		}
7288c4f9701SJanice Chang 
7298c4f9701SJanice Chang 		*bytes_totalp += count;
7308c4f9701SJanice Chang 	}
7318c4f9701SJanice Chang 	/* NOTREACHED */
7328c4f9701SJanice Chang }
7338c4f9701SJanice Chang 
734c1a2c731SJanice Chang static int
ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t * ndmpd_zfs_args,u_longlong_t bytes_total)735c1a2c731SJanice Chang ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args,
736c1a2c731SJanice Chang     u_longlong_t bytes_total)
737c1a2c731SJanice Chang {
738c1a2c731SJanice Chang 	char zfs_backup_size[32];
739c1a2c731SJanice Chang 	int err;
740c1a2c731SJanice Chang 
741c1a2c731SJanice Chang 	(void) snprintf(zfs_backup_size, sizeof (zfs_backup_size), "%llu",
742c1a2c731SJanice Chang 	    bytes_total);
743c1a2c731SJanice Chang 
744c1a2c731SJanice Chang 	err = MOD_ADDENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE", zfs_backup_size);
745c1a2c731SJanice Chang 
746c1a2c731SJanice Chang 	if (err) {
747c1a2c731SJanice Chang 		NDMP_LOG(LOG_ERR, "Failed to add ZFS_BACKUP_SIZE env");
748c1a2c731SJanice Chang 		return (-1);
749c1a2c731SJanice Chang 	}
750c1a2c731SJanice Chang 
751c1a2c731SJanice Chang 	NDMP_LOG(LOG_DEBUG, "Added ZFS_BACKUP_SIZE env: %s", zfs_backup_size);
752c1a2c731SJanice Chang 
753c1a2c731SJanice Chang 	return (0);
754c1a2c731SJanice Chang }
755c1a2c731SJanice Chang 
756*82049ff5SToomas Soome void *
ndmpd_zfs_restore_starter(void * arg)7578c4f9701SJanice Chang ndmpd_zfs_restore_starter(void *arg)
7588c4f9701SJanice Chang {
7598c4f9701SJanice Chang 	ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
7608c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
7618c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
7628c4f9701SJanice Chang 	int err;
7638c4f9701SJanice Chang 
7648c4f9701SJanice Chang 	ndmp_session_ref(session);
7658c4f9701SJanice Chang 
7668c4f9701SJanice Chang 	err = ndmpd_zfs_restore(ndmpd_zfs_args);
7678c4f9701SJanice Chang 
7688c4f9701SJanice Chang 	MOD_DONE(ndmpd_zfs_params, err);
7698c4f9701SJanice Chang 
7708c4f9701SJanice Chang 	NS_DEC(nrs);
7718c4f9701SJanice Chang 
7728c4f9701SJanice Chang 	ndmp_session_unref(session);
7738c4f9701SJanice Chang 
7748c4f9701SJanice Chang 	ndmpd_zfs_fini(ndmpd_zfs_args);
7758c4f9701SJanice Chang 
776*82049ff5SToomas Soome 	return ((void *)(uintptr_t)err);
7778c4f9701SJanice Chang }
7788c4f9701SJanice Chang 
7798c4f9701SJanice Chang static int
ndmpd_zfs_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)7808c4f9701SJanice Chang ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
7818c4f9701SJanice Chang {
7828c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
7838c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
7848c4f9701SJanice Chang 	int *read_err = NULL;
7858c4f9701SJanice Chang 	int *write_err = NULL;
7868c4f9701SJanice Chang 	int result = 0;
7878c4f9701SJanice Chang 	int err;
7888c4f9701SJanice Chang 
7898c4f9701SJanice Chang 	if (!session->ns_data.dd_abort) {
7908c4f9701SJanice Chang 		if (ndmpd_zfs_header_read(ndmpd_zfs_args)) {
7918c4f9701SJanice Chang 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
7928c4f9701SJanice Chang 			    "ndmpd_zfs header read error\n");
7938c4f9701SJanice Chang 			return (-1);
7948c4f9701SJanice Chang 		}
7958c4f9701SJanice Chang 
7968c4f9701SJanice Chang 		err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
7978c4f9701SJanice Chang 		    &write_err, &read_err);
7988c4f9701SJanice Chang 
7998c4f9701SJanice Chang 		if (err || read_err || write_err || session->ns_eof)
8008c4f9701SJanice Chang 			result = EIO;
8018c4f9701SJanice Chang 	}
8028c4f9701SJanice Chang 
8038c4f9701SJanice Chang 	if (session->ns_data.dd_abort) {
8048c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
8058c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset);
8068c4f9701SJanice Chang 		ndmpd_audit_restore(session->ns_connection,
8078c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset,
8088c4f9701SJanice Chang 		    session->ns_data.dd_data_addr.addr_type,
8098c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset, EINTR);
8108c4f9701SJanice Chang 		(void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
8118c4f9701SJanice Chang 		err = -1;
8128c4f9701SJanice Chang 	} else {
8138c4f9701SJanice Chang 		ndmpd_audit_restore(session->ns_connection,
8148c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset,
8158c4f9701SJanice Chang 		    session->ns_data.dd_data_addr.addr_type,
8168c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset, result);
8178c4f9701SJanice Chang 		err = ndmpd_zfs_post_restore(ndmpd_zfs_args);
8188c4f9701SJanice Chang 		if (err || result)
8198c4f9701SJanice Chang 			err = -1;
8208c4f9701SJanice Chang 
8218c4f9701SJanice Chang 		if (err == 0) {
8228c4f9701SJanice Chang 			NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished",
8238c4f9701SJanice Chang 			    ndmpd_zfs_args->nz_dataset);
8248c4f9701SJanice Chang 		} else {
8258c4f9701SJanice Chang 			NDMP_LOG(LOG_DEBUG, "An error occurred while restoring"
8268c4f9701SJanice Chang 			    " to \"%s\"", ndmpd_zfs_args->nz_dataset);
8278c4f9701SJanice Chang 		}
8288c4f9701SJanice Chang 	}
8298c4f9701SJanice Chang 
8308c4f9701SJanice Chang 	return (err);
8318c4f9701SJanice Chang }
8328c4f9701SJanice Chang 
833*82049ff5SToomas Soome static void *
ndmpd_zfs_restore_tape_read(void * ptr)834*82049ff5SToomas Soome ndmpd_zfs_restore_tape_read(void *ptr)
8358c4f9701SJanice Chang {
836*82049ff5SToomas Soome 	ndmpd_zfs_args_t *ndmpd_zfs_args = ptr;
8378c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
8388c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
8398c4f9701SJanice Chang 	int bufsize = ndmpd_zfs_args->nz_bufsize;
840c1a2c731SJanice Chang 	u_longlong_t backup_size = ndmpd_zfs_args->nz_zfs_backup_size;
8418c4f9701SJanice Chang 	u_longlong_t *bytes_totalp;
842c1a2c731SJanice Chang 	u_longlong_t bytes;
8438c4f9701SJanice Chang 	char *buf;
8448c4f9701SJanice Chang 	int count;
8458c4f9701SJanice Chang 	int err;
8468c4f9701SJanice Chang 
8478c4f9701SJanice Chang 	buf = ndmp_malloc(bufsize);
8488c4f9701SJanice Chang 	if (buf == NULL) {
8498c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "buf NULL");
850*82049ff5SToomas Soome 		return ((void *)(uintptr_t)-1);
8518c4f9701SJanice Chang 	}
8528c4f9701SJanice Chang 
8538c4f9701SJanice Chang 	bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total;
8548c4f9701SJanice Chang 
855c1a2c731SJanice Chang 	while (*bytes_totalp < backup_size) {
8568c4f9701SJanice Chang 
857c1a2c731SJanice Chang 		bytes = backup_size - *bytes_totalp;
8588c4f9701SJanice Chang 
859c1a2c731SJanice Chang 		if (bytes >= bufsize)
860c1a2c731SJanice Chang 			bytes = bufsize;
8618c4f9701SJanice Chang 
862c1a2c731SJanice Chang 		err = MOD_READ(ndmpd_zfs_params, buf, bytes);
8638c4f9701SJanice Chang 
864c1a2c731SJanice Chang 		if (err != 0) {
865c1a2c731SJanice Chang 			NDMP_LOG(LOG_ERR, "MOD_READ error: %d; returning -1",
866c1a2c731SJanice Chang 			    err);
867c1a2c731SJanice Chang 			free(buf);
868*82049ff5SToomas Soome 			return ((void *)(uintptr_t)-1);
8698c4f9701SJanice Chang 		}
8708c4f9701SJanice Chang 
871c1a2c731SJanice Chang 		count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
872c1a2c731SJanice Chang 		    bytes);
8738c4f9701SJanice Chang 
874c1a2c731SJanice Chang 		if (count != bytes) {
875c1a2c731SJanice Chang 			NDMP_LOG(LOG_ERR, "count (%d) != bytes (%d)",
876c1a2c731SJanice Chang 			    count, bytes);
8778c4f9701SJanice Chang 
878c1a2c731SJanice Chang 			if (count == -1) {
879c1a2c731SJanice Chang 				NDMP_LOG(LOG_ERR, "pipe write error: errno: %d",
880c1a2c731SJanice Chang 				    errno);
8818c4f9701SJanice Chang 
882c1a2c731SJanice Chang 				if (session->ns_data.dd_abort)
883c1a2c731SJanice Chang 					NDMP_LOG(LOG_DEBUG, "abort set");
8848c4f9701SJanice Chang 			}
885c1a2c731SJanice Chang 
886c1a2c731SJanice Chang 			free(buf);
887*82049ff5SToomas Soome 			return ((void *)(uintptr_t)-1);
8888c4f9701SJanice Chang 		}
889c1a2c731SJanice Chang 
890c1a2c731SJanice Chang 		NS_ADD(wdisk, count);
891c1a2c731SJanice Chang 
892c1a2c731SJanice Chang 		*bytes_totalp += count;
8938c4f9701SJanice Chang 	}
8948c4f9701SJanice Chang 
8958c4f9701SJanice Chang 	free(buf);
896*82049ff5SToomas Soome 	return (NULL);
8978c4f9701SJanice Chang }
8988c4f9701SJanice Chang 
8998c4f9701SJanice Chang /*
9008c4f9701SJanice Chang  * ndmpd_zfs_restore_recv_write()
9018c4f9701SJanice Chang  *
9028c4f9701SJanice Chang  * This routine executes zfs_receive() to restore the backup.
9038c4f9701SJanice Chang  */
9048c4f9701SJanice Chang 
905*82049ff5SToomas Soome static void *
ndmpd_zfs_restore_recv_write(void * ptr)906*82049ff5SToomas Soome ndmpd_zfs_restore_recv_write(void *ptr)
9078c4f9701SJanice Chang {
908*82049ff5SToomas Soome 	ndmpd_zfs_args_t *ndmpd_zfs_args = ptr;
9098c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
9108c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
9118c4f9701SJanice Chang 	recvflags_t flags;
9128c4f9701SJanice Chang 	int err;
9138c4f9701SJanice Chang 
9148c4f9701SJanice Chang 	bzero(&flags, sizeof (recvflags_t));
9158c4f9701SJanice Chang 
9168c4f9701SJanice Chang 	flags.nomount = B_TRUE;
9178c4f9701SJanice Chang 
918d0194491SJanice Chang 	NDMP_LOG(LOG_DEBUG, "nz_zfs_force: %d\n", ndmpd_zfs_args->nz_zfs_force);
919d0194491SJanice Chang 
9208c4f9701SJanice Chang 	if (ndmpd_zfs_args->nz_zfs_force)
9218c4f9701SJanice Chang 		flags.force = B_TRUE;
9228c4f9701SJanice Chang 
9238c4f9701SJanice Chang 	err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
924a2cdcdd2SPaul Dagnelie 	    NULL, &flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL);
9258c4f9701SJanice Chang 
9268c4f9701SJanice Chang 	if (err && !session->ns_data.dd_abort)
9278c4f9701SJanice Chang 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err);
9288c4f9701SJanice Chang 
929*82049ff5SToomas Soome 	return ((void *)(uintptr_t)err);
9308c4f9701SJanice Chang }
9318c4f9701SJanice Chang 
9328c4f9701SJanice Chang /*
9338c4f9701SJanice Chang  * ndmpd_zfs_reader_writer()
9348c4f9701SJanice Chang  *
9358c4f9701SJanice Chang  * Two separate threads are used for actual backup or restore.
9368c4f9701SJanice Chang  */
9378c4f9701SJanice Chang 
9388c4f9701SJanice Chang static int
ndmpd_zfs_reader_writer(ndmpd_zfs_args_t * ndmpd_zfs_args,int ** sendrecv_errp,int ** tape_errp)9398c4f9701SJanice Chang ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args,
9408c4f9701SJanice Chang     int **sendrecv_errp, int **tape_errp)
9418c4f9701SJanice Chang {
9428c4f9701SJanice Chang 	funct_t sendrecv_func;
9438c4f9701SJanice Chang 	funct_t tape_func;
9448c4f9701SJanice Chang 	int sendrecv_err;
9458c4f9701SJanice Chang 	int tape_err;
9468c4f9701SJanice Chang 
9478c4f9701SJanice Chang 	switch (ndmpd_zfs_params->mp_operation) {
9488c4f9701SJanice Chang 	case NDMP_DATA_OP_BACKUP:
949*82049ff5SToomas Soome 		sendrecv_func = ndmpd_zfs_backup_send_read;
950*82049ff5SToomas Soome 		tape_func = ndmpd_zfs_backup_tape_write;
9518c4f9701SJanice Chang 		break;
9528c4f9701SJanice Chang 	case NDMP_DATA_OP_RECOVER:
953*82049ff5SToomas Soome 		sendrecv_func = ndmpd_zfs_restore_recv_write;
954*82049ff5SToomas Soome 		tape_func = ndmpd_zfs_restore_tape_read;
9558c4f9701SJanice Chang 		break;
9568c4f9701SJanice Chang 	}
9578c4f9701SJanice Chang 
9588c4f9701SJanice Chang 	sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread,
9598c4f9701SJanice Chang 	    NULL, sendrecv_func, ndmpd_zfs_args);
9608c4f9701SJanice Chang 
9618c4f9701SJanice Chang 	if (sendrecv_err == 0) {
9628c4f9701SJanice Chang 		tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread,
9638c4f9701SJanice Chang 		    NULL, tape_func, ndmpd_zfs_args);
9648c4f9701SJanice Chang 
9658c4f9701SJanice Chang 		if (tape_err) {
9668c4f9701SJanice Chang 			/*
9678c4f9701SJanice Chang 			 * The close of the tape side of the pipe will cause
9688c4f9701SJanice Chang 			 * nz_sendrecv_thread to error in the zfs_send/recv()
9698c4f9701SJanice Chang 			 * call and to return.  Hence we do not need
9708c4f9701SJanice Chang 			 * to explicitly cancel the sendrecv_thread here
9718c4f9701SJanice Chang 			 * (the pthread_join() below is sufficient).
9728c4f9701SJanice Chang 			 */
9738c4f9701SJanice Chang 
9748c4f9701SJanice Chang 			(void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]);
9758c4f9701SJanice Chang 			NDMP_LOG(LOG_ERR, "Could not start tape thread; "
9768c4f9701SJanice Chang 			    "aborting z-op");
9778c4f9701SJanice Chang 		}
9788c4f9701SJanice Chang 
9798c4f9701SJanice Chang 		(void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread,
9808c4f9701SJanice Chang 		    (void **) sendrecv_errp);
9818c4f9701SJanice Chang 	}
9828c4f9701SJanice Chang 
9838c4f9701SJanice Chang 	if ((tape_err == 0) &&
9848c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER))
9858c4f9701SJanice Chang 		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
9868c4f9701SJanice Chang 
9878c4f9701SJanice Chang 	ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
9888c4f9701SJanice Chang 
9898c4f9701SJanice Chang 	if ((sendrecv_err == 0) && (tape_err == 0)) {
9908c4f9701SJanice Chang 		(void) pthread_join(ndmpd_zfs_args->nz_tape_thread,
9918c4f9701SJanice Chang 		    (void **) tape_errp);
9928c4f9701SJanice Chang 	}
9938c4f9701SJanice Chang 
9948c4f9701SJanice Chang 	if ((tape_err == 0) &&
9958c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP))
9968c4f9701SJanice Chang 		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
9978c4f9701SJanice Chang 
9988c4f9701SJanice Chang 	return (sendrecv_err ? sendrecv_err : tape_err);
9998c4f9701SJanice Chang }
10008c4f9701SJanice Chang 
10018c4f9701SJanice Chang int
ndmpd_zfs_abort(void * arg)10028c4f9701SJanice Chang ndmpd_zfs_abort(void *arg)
10038c4f9701SJanice Chang {
10048c4f9701SJanice Chang 	ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
10058c4f9701SJanice Chang 	char str[8];
10068c4f9701SJanice Chang 
10078c4f9701SJanice Chang 	if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)
10088c4f9701SJanice Chang 		(void) strlcpy(str, "backup", 8);
10098c4f9701SJanice Chang 	else
10108c4f9701SJanice Chang 		(void) strlcpy(str, "recover", 8);
10118c4f9701SJanice Chang 
10128c4f9701SJanice Chang 	NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation",
10138c4f9701SJanice Chang 	    str);
10148c4f9701SJanice Chang 
10158c4f9701SJanice Chang 	ndmpd_zfs_close_fds(ndmpd_zfs_args);
10168c4f9701SJanice Chang 
10178c4f9701SJanice Chang 	return (0);
10188c4f9701SJanice Chang }
10198c4f9701SJanice Chang 
10208c4f9701SJanice Chang /*
10218c4f9701SJanice Chang  * ndmpd_zfs_pre_backup()
10228c4f9701SJanice Chang  *
10238c4f9701SJanice Chang  * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL.
10248c4f9701SJanice Chang  * This ensures that ndmp_include_zfs() will fail, which is
10258c4f9701SJanice Chang  * a requirement for "zfs"-type backup.
10268c4f9701SJanice Chang  */
10278c4f9701SJanice Chang 
10288c4f9701SJanice Chang int
ndmpd_zfs_pre_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)10298c4f9701SJanice Chang ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
10308c4f9701SJanice Chang {
10318c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
10328c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
10338c4f9701SJanice Chang 	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
10348c4f9701SJanice Chang 	int err;
10358c4f9701SJanice Chang 
10368c4f9701SJanice Chang 	if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL)
10378c4f9701SJanice Chang 		return (0);
10388c4f9701SJanice Chang 
10398c4f9701SJanice Chang 	(void) memset(nctxp, 0, sizeof (ndmp_context_t));
10408c4f9701SJanice Chang 	nctxp->nc_plversion = ndmp_pl->np_plversion;
10418c4f9701SJanice Chang 	nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
10428c4f9701SJanice Chang 	nctxp->nc_ddata = (void *) session;
10431e05b03fSJanice Chang 	nctxp->nc_params = ndmpd_zfs_params;
10448c4f9701SJanice Chang 
10458c4f9701SJanice Chang 	err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp,
10468c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_dataset);
10478c4f9701SJanice Chang 
10488c4f9701SJanice Chang 	if (err != 0) {
10498c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m");
10508c4f9701SJanice Chang 		(void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
10518c4f9701SJanice Chang 	}
10528c4f9701SJanice Chang 
10538c4f9701SJanice Chang 	return (err);
10548c4f9701SJanice Chang }
10558c4f9701SJanice Chang 
10568c4f9701SJanice Chang int
ndmpd_zfs_post_backup(ndmpd_zfs_args_t * ndmpd_zfs_args)10578c4f9701SJanice Chang ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
10588c4f9701SJanice Chang {
10598c4f9701SJanice Chang 	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
10608c4f9701SJanice Chang 	int err = 0;
10618c4f9701SJanice Chang 
10628c4f9701SJanice Chang 	if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL)
10638c4f9701SJanice Chang 		return (0);
10648c4f9701SJanice Chang 
10658c4f9701SJanice Chang 	err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err);
10668c4f9701SJanice Chang 
10678c4f9701SJanice Chang 	if (err == -1)
10688c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
10698c4f9701SJanice Chang 
10708c4f9701SJanice Chang 	return (err);
10718c4f9701SJanice Chang }
10728c4f9701SJanice Chang 
10738c4f9701SJanice Chang int
ndmpd_zfs_pre_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)10748c4f9701SJanice Chang ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
10758c4f9701SJanice Chang {
10768c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
10778c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
10788c4f9701SJanice Chang 	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
10799adfa60dSMatthew Ahrens 	char bkpath[ZFS_MAX_DATASET_NAME_LEN];
10808c4f9701SJanice Chang 	int err;
10818c4f9701SJanice Chang 
10828c4f9701SJanice Chang 	if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL)
10838c4f9701SJanice Chang 		return (0);
10848c4f9701SJanice Chang 
10859adfa60dSMatthew Ahrens 	err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath,
10869adfa60dSMatthew Ahrens 	    ZFS_MAX_DATASET_NAME_LEN);
10878c4f9701SJanice Chang 
10888c4f9701SJanice Chang 	if (err != 0) {
10898c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err);
10908c4f9701SJanice Chang 		return (-1);
10918c4f9701SJanice Chang 	}
10928c4f9701SJanice Chang 
10938c4f9701SJanice Chang 	err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args);
10948c4f9701SJanice Chang 
10958c4f9701SJanice Chang 	if (err != 0) {
10968c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err);
10978c4f9701SJanice Chang 		return (-1);
10988c4f9701SJanice Chang 	}
10998c4f9701SJanice Chang 
11008c4f9701SJanice Chang 	(void) memset(nctxp, 0, sizeof (ndmp_context_t));
11018c4f9701SJanice Chang 	nctxp->nc_ddata = (void *) session;
11021e05b03fSJanice Chang 	nctxp->nc_params = ndmpd_zfs_params;
11038c4f9701SJanice Chang 
11048c4f9701SJanice Chang 	err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath,
11058c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_dataset);
11068c4f9701SJanice Chang 
11078c4f9701SJanice Chang 	if (err != 0) {
11088c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
11098c4f9701SJanice Chang 		return (-1);
11108c4f9701SJanice Chang 	}
11118c4f9701SJanice Chang 
11128c4f9701SJanice Chang 	return (0);
11138c4f9701SJanice Chang }
11148c4f9701SJanice Chang 
11158c4f9701SJanice Chang int
ndmpd_zfs_post_restore(ndmpd_zfs_args_t * ndmpd_zfs_args)11168c4f9701SJanice Chang ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
11178c4f9701SJanice Chang {
11188c4f9701SJanice Chang 	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
11198c4f9701SJanice Chang 	int err = 0;
11208c4f9701SJanice Chang 
11218c4f9701SJanice Chang 	if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL)
11228c4f9701SJanice Chang 		return (0);
11238c4f9701SJanice Chang 
11248c4f9701SJanice Chang 	err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err);
11258c4f9701SJanice Chang 
11268c4f9701SJanice Chang 	if (err == -1)
11278c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
11288c4f9701SJanice Chang 
11298c4f9701SJanice Chang 	return (err);
11308c4f9701SJanice Chang }
11318c4f9701SJanice Chang 
11328c4f9701SJanice Chang boolean_t
ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t * ndmpd_zfs_args)11338c4f9701SJanice Chang ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
11348c4f9701SJanice Chang {
11358c4f9701SJanice Chang 	ndmpd_zfs_snapfind_t snapdata;
11368c4f9701SJanice Chang 
11378c4f9701SJanice Chang 	if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0)
11388c4f9701SJanice Chang 		return (B_FALSE);
11398c4f9701SJanice Chang 
11408c4f9701SJanice Chang 	if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args))
11418c4f9701SJanice Chang 		return (B_FALSE);
11428c4f9701SJanice Chang 
11438c4f9701SJanice Chang 	if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
11448c4f9701SJanice Chang 		(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
11458c4f9701SJanice Chang 		    snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE);
11468c4f9701SJanice Chang 
11478c4f9701SJanice Chang 		snapdata.nzs_snapname[0] = '\0';
11488c4f9701SJanice Chang 		snapdata.nzs_snapprop[0] = '\0';
11498c4f9701SJanice Chang 
11508c4f9701SJanice Chang 		if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata))
11518c4f9701SJanice Chang 			return (B_FALSE);
11528c4f9701SJanice Chang 
11538c4f9701SJanice Chang 		if (snapdata.nzs_snapname[0] == '\0') { /* not found */
11548c4f9701SJanice Chang 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
11558c4f9701SJanice Chang 			    "Snapshot for level %d does not exist\n",
11568c4f9701SJanice Chang 			    ndmpd_zfs_args->nz_level-1);
11578c4f9701SJanice Chang 			return (B_FALSE);
11588c4f9701SJanice Chang 		}
11598c4f9701SJanice Chang 
11608c4f9701SJanice Chang 		(void) strlcpy(ndmpd_zfs_args->nz_fromsnap,
11619adfa60dSMatthew Ahrens 		    snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN);
11628c4f9701SJanice Chang 	}
11638c4f9701SJanice Chang 
11648c4f9701SJanice Chang 	return (B_TRUE);
11658c4f9701SJanice Chang }
11668c4f9701SJanice Chang 
11678c4f9701SJanice Chang /*
11688c4f9701SJanice Chang  * ndmpd_zfs_backup_pathvalid()
11698c4f9701SJanice Chang  *
11708c4f9701SJanice Chang  * Make sure the path is of an existing dataset
11718c4f9701SJanice Chang  */
11728c4f9701SJanice Chang 
11738c4f9701SJanice Chang static boolean_t
ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t * ndmpd_zfs_args)11748c4f9701SJanice Chang ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
11758c4f9701SJanice Chang {
11769adfa60dSMatthew Ahrens 	char zpath[ZFS_MAX_DATASET_NAME_LEN];
11778c4f9701SJanice Chang 	char propstr[ZFS_MAXPROPLEN];
11788c4f9701SJanice Chang 	zfs_handle_t *zhp;
11798c4f9701SJanice Chang 	zfs_type_t ztype = 0;
11808c4f9701SJanice Chang 	int err;
11818c4f9701SJanice Chang 
11829adfa60dSMatthew Ahrens 	if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
11839adfa60dSMatthew Ahrens 	    ZFS_MAX_DATASET_NAME_LEN) != 0)
11848c4f9701SJanice Chang 		return (B_FALSE);
11858c4f9701SJanice Chang 
11868c4f9701SJanice Chang 	if (ndmpd_zfs_args->nz_snapname[0] != '\0') {
11878c4f9701SJanice Chang 		zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath,
11888c4f9701SJanice Chang 		    ZFS_TYPE_SNAPSHOT);
11898c4f9701SJanice Chang 
11908c4f9701SJanice Chang 		if (!zhp) {
11918c4f9701SJanice Chang 			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args,
11928c4f9701SJanice Chang 			    "zfs_open (snap)");
11938c4f9701SJanice Chang 			ndmpd_zfs_args->nz_snapname[0] = '\0';
11948c4f9701SJanice Chang 			ndmpd_zfs_args->nz_dataset[0] = '\0';
11958c4f9701SJanice Chang 			return (B_FALSE);
11968c4f9701SJanice Chang 		}
11978c4f9701SJanice Chang 
11988c4f9701SJanice Chang 		err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
11998c4f9701SJanice Chang 
12008c4f9701SJanice Chang 		zfs_close(zhp);
12018c4f9701SJanice Chang 
12028c4f9701SJanice Chang 		if (err) {
12038c4f9701SJanice Chang 			NDMP_LOG(LOG_DEBUG,
12048c4f9701SJanice Chang 			    "ndmpd_zfs_snapshot_prop_get failed");
12058c4f9701SJanice Chang 			return (-1);
12068c4f9701SJanice Chang 		}
12078c4f9701SJanice Chang 
12088c4f9701SJanice Chang 		if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) {
12098c4f9701SJanice Chang 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
12108c4f9701SJanice Chang 			    "cannot use an ndmpd-generated snapshot\n");
12118c4f9701SJanice Chang 			return (B_FALSE);
12128c4f9701SJanice Chang 		}
12138c4f9701SJanice Chang 	}
12148c4f9701SJanice Chang 
12158c4f9701SJanice Chang 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
12168c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET);
12178c4f9701SJanice Chang 
12188c4f9701SJanice Chang 	if (zhp) {
12198c4f9701SJanice Chang 		ztype = zfs_get_type(zhp);
12208c4f9701SJanice Chang 		zfs_close(zhp);
12218c4f9701SJanice Chang 	}
12228c4f9701SJanice Chang 
12238c4f9701SJanice Chang 	if ((ztype == ZFS_TYPE_VOLUME) ||
12248c4f9701SJanice Chang 	    (ztype == ZFS_TYPE_FILESYSTEM)) {
12258c4f9701SJanice Chang 		ndmpd_zfs_args->nz_type = ztype;
12268c4f9701SJanice Chang 		return (B_TRUE);
12278c4f9701SJanice Chang 	}
12288c4f9701SJanice Chang 
12298c4f9701SJanice Chang 	ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
12308c4f9701SJanice Chang 	    "Invalid file system or volume.\n");
12318c4f9701SJanice Chang 
12328c4f9701SJanice Chang 	return (B_FALSE);
12338c4f9701SJanice Chang }
12348c4f9701SJanice Chang 
12358c4f9701SJanice Chang /*
12368c4f9701SJanice Chang  * ndmpd_zfs_backup_getpath()
12378c4f9701SJanice Chang  *
12388c4f9701SJanice Chang  * Retrieve the backup path from the environment, which should
12398c4f9701SJanice Chang  * be of the form "/dataset[@snap]".  The leading slash is required
12408c4f9701SJanice Chang  * by certain DMA's but can otherwise be ignored.
12418c4f9701SJanice Chang  *
12428c4f9701SJanice Chang  * (Note: "dataset" can consist of more than one component,
12438c4f9701SJanice Chang  * e.g. "pool", "pool/volume", "pool/fs/fs2".)
12448c4f9701SJanice Chang  *
12458c4f9701SJanice Chang  * The dataset name and the snapshot name (if any) will be
12468c4f9701SJanice Chang  * stored in ndmpd_zfs_args.
12478c4f9701SJanice Chang  */
12488c4f9701SJanice Chang 
12498c4f9701SJanice Chang static int
ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t * ndmpd_zfs_args,char * zpath,int zlen)12508c4f9701SJanice Chang ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath,
12518c4f9701SJanice Chang     int zlen)
12528c4f9701SJanice Chang {
12538c4f9701SJanice Chang 	char *env_path;
12548c4f9701SJanice Chang 	char *at;
12558c4f9701SJanice Chang 
12568c4f9701SJanice Chang 	env_path = get_backup_path_v3(ndmpd_zfs_params);
12578c4f9701SJanice Chang 	if (env_path == NULL)
12588c4f9701SJanice Chang 		return (-1);
12598c4f9701SJanice Chang 
12608c4f9701SJanice Chang 	if (env_path[0] != '/') {
12618c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
12628c4f9701SJanice Chang 		    "Invalid path: %s (leading slash required)\n", env_path);
12638c4f9701SJanice Chang 		return (-1);
12648c4f9701SJanice Chang 	}
12658c4f9701SJanice Chang 
12668c4f9701SJanice Chang 	(void) strlcpy(zpath, &env_path[1], zlen);
12678c4f9701SJanice Chang 	(void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1],
12689adfa60dSMatthew Ahrens 	    ZFS_MAX_DATASET_NAME_LEN);
12698c4f9701SJanice Chang 
12708c4f9701SJanice Chang 	at = strchr(ndmpd_zfs_args->nz_dataset, '@');
12718c4f9701SJanice Chang 	if (at) {
12728c4f9701SJanice Chang 		*at = '\0';
12738c4f9701SJanice Chang 		(void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at,
12749adfa60dSMatthew Ahrens 		    ZFS_MAX_DATASET_NAME_LEN);
12758c4f9701SJanice Chang 	} else {
12768c4f9701SJanice Chang 		ndmpd_zfs_args->nz_snapname[0] = '\0';
12778c4f9701SJanice Chang 	}
12788c4f9701SJanice Chang 
1279d0194491SJanice Chang 	(void) trim_whitespace(ndmpd_zfs_args->nz_dataset);
1280d0194491SJanice Chang 
12818c4f9701SJanice Chang 	return (0);
12828c4f9701SJanice Chang }
12838c4f9701SJanice Chang 
12848c4f9701SJanice Chang static int
ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)12858c4f9701SJanice Chang ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
12868c4f9701SJanice Chang {
12878c4f9701SJanice Chang 	return (ndmpd_zfs_getenv(ndmpd_zfs_args));
12888c4f9701SJanice Chang }
12898c4f9701SJanice Chang 
12908c4f9701SJanice Chang boolean_t
ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t * ndmpd_zfs_args)12918c4f9701SJanice Chang ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
12928c4f9701SJanice Chang {
12938c4f9701SJanice Chang 	if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0)
12948c4f9701SJanice Chang 		return (B_FALSE);
12958c4f9701SJanice Chang 
12968c4f9701SJanice Chang 	if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args))
12978c4f9701SJanice Chang 		return (B_FALSE);
12988c4f9701SJanice Chang 
12998c4f9701SJanice Chang 	return (B_TRUE);
13008c4f9701SJanice Chang }
13018c4f9701SJanice Chang 
13028c4f9701SJanice Chang static boolean_t
ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t * ndmpd_zfs_args)13038c4f9701SJanice Chang ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
13048c4f9701SJanice Chang {
13058c4f9701SJanice Chang 	zfs_handle_t *zhp;
13068c4f9701SJanice Chang 	char *at;
13078c4f9701SJanice Chang 
13088c4f9701SJanice Chang 	if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0)
13098c4f9701SJanice Chang 		return (B_FALSE);
13108c4f9701SJanice Chang 
13118c4f9701SJanice Chang 	at = strchr(ndmpd_zfs_args->nz_dataset, '@');
13128c4f9701SJanice Chang 
13138c4f9701SJanice Chang 	if (at) {
13148c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
13158c4f9701SJanice Chang 		    "%s ignored in restore path\n", at);
13168c4f9701SJanice Chang 		*at = '\0';
13178c4f9701SJanice Chang 	}
13188c4f9701SJanice Chang 
13198c4f9701SJanice Chang 	ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
13208c4f9701SJanice Chang 
13218c4f9701SJanice Chang 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
13228c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
13238c4f9701SJanice Chang 
13248c4f9701SJanice Chang 	if (zhp) {
13258c4f9701SJanice Chang 		zfs_close(zhp);
13268c4f9701SJanice Chang 
13278c4f9701SJanice Chang 		if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
13288c4f9701SJanice Chang 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
13298c4f9701SJanice Chang 			    "Restore dataset exists.\n"
13308c4f9701SJanice Chang 			    "A nonexistent dataset must be specified "
13318c4f9701SJanice Chang 			    "for 'zfs' non-incremental restore.\n");
13328c4f9701SJanice Chang 			return (B_FALSE);
13338c4f9701SJanice Chang 		}
13348c4f9701SJanice Chang 	}
13358c4f9701SJanice Chang 
13368c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset);
13378c4f9701SJanice Chang 
13388c4f9701SJanice Chang 	return (B_TRUE);
13398c4f9701SJanice Chang }
13408c4f9701SJanice Chang 
13418c4f9701SJanice Chang /*
13428c4f9701SJanice Chang  * ndmpd_zfs_restore_getpath()
13438c4f9701SJanice Chang  *
13448c4f9701SJanice Chang  * Be sure to not include the leading slash, which is required for
13458c4f9701SJanice Chang  * compatibility with backup applications (NBU) but which is not part
13468c4f9701SJanice Chang  * of the ZFS syntax.  (Note that this done explicitly in all paths
13478c4f9701SJanice Chang  * below except those calling ndmpd_zfs_backup_getpath(), because it is
13488c4f9701SJanice Chang  * already stripped in that function.)
13498c4f9701SJanice Chang  *
13508c4f9701SJanice Chang  * In addition, the DMA might add a trailing slash to the path.
13518c4f9701SJanice Chang  * Strip all such slashes.
13528c4f9701SJanice Chang  */
13538c4f9701SJanice Chang 
13548c4f9701SJanice Chang static int
ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t * ndmpd_zfs_args)13558c4f9701SJanice Chang ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args)
13568c4f9701SJanice Chang {
13578c4f9701SJanice Chang 	int version = ndmpd_zfs_params->mp_protocol_version;
13589adfa60dSMatthew Ahrens 	char zpath[ZFS_MAX_DATASET_NAME_LEN];
13598c4f9701SJanice Chang 	mem_ndmp_name_v3_t *namep_v3;
13608c4f9701SJanice Chang 	char *dataset = ndmpd_zfs_args->nz_dataset;
13618c4f9701SJanice Chang 	char *nm;
13628c4f9701SJanice Chang 	char *p;
13638c4f9701SJanice Chang 	int len;
13648c4f9701SJanice Chang 	int err;
13658c4f9701SJanice Chang 
13668c4f9701SJanice Chang 	namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0);
13678c4f9701SJanice Chang 
13688c4f9701SJanice Chang 	if (namep_v3 == NULL) {
13698c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]");
13708c4f9701SJanice Chang 		return (-1);
13718c4f9701SJanice Chang 	}
13728c4f9701SJanice Chang 
13738c4f9701SJanice Chang 	if (namep_v3->nm3_dpath) {
13748c4f9701SJanice Chang 		if (namep_v3->nm3_dpath[0] != '/') {
13758c4f9701SJanice Chang 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
13768c4f9701SJanice Chang 			    "Invalid path: %s (leading slash required)\n",
13778c4f9701SJanice Chang 			    namep_v3->nm3_dpath);
13788c4f9701SJanice Chang 			return (-1);
13798c4f9701SJanice Chang 		}
13808c4f9701SJanice Chang 
13818c4f9701SJanice Chang 		(void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]),
13829adfa60dSMatthew Ahrens 		    ZFS_MAX_DATASET_NAME_LEN);
13838c4f9701SJanice Chang 
13848c4f9701SJanice Chang 		if (namep_v3->nm3_newnm) {
13859adfa60dSMatthew Ahrens 			(void) strlcat(dataset, "/", ZFS_MAX_DATASET_NAME_LEN);
13868c4f9701SJanice Chang 			(void) strlcat(dataset, namep_v3->nm3_newnm,
13879adfa60dSMatthew Ahrens 			    ZFS_MAX_DATASET_NAME_LEN);
13888c4f9701SJanice Chang 
13898c4f9701SJanice Chang 		} else {
13908c4f9701SJanice Chang 			if (version == NDMPV3) {
13918c4f9701SJanice Chang 				/*
13928c4f9701SJanice Chang 				 * The following does not apply for V4.
13938c4f9701SJanice Chang 				 *
13948c4f9701SJanice Chang 				 * Find the last component of nm3_opath.
13958c4f9701SJanice Chang 				 * nm3_opath has no trailing '/'.
13968c4f9701SJanice Chang 				 */
13978c4f9701SJanice Chang 				p = strrchr(namep_v3->nm3_opath, '/');
13988c4f9701SJanice Chang 				nm = p? p : namep_v3->nm3_opath;
13999adfa60dSMatthew Ahrens 				(void) strlcat(dataset, "/",
14009adfa60dSMatthew Ahrens 				    ZFS_MAX_DATASET_NAME_LEN);
14019adfa60dSMatthew Ahrens 				(void) strlcat(dataset, nm,
14029adfa60dSMatthew Ahrens 				    ZFS_MAX_DATASET_NAME_LEN);
14038c4f9701SJanice Chang 			}
14048c4f9701SJanice Chang 		}
14058c4f9701SJanice Chang 	} else {
14068c4f9701SJanice Chang 		err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
14079adfa60dSMatthew Ahrens 		    ZFS_MAX_DATASET_NAME_LEN);
14088c4f9701SJanice Chang 		if (err)
14098c4f9701SJanice Chang 			return (err);
14108c4f9701SJanice Chang 	}
14118c4f9701SJanice Chang 
14128c4f9701SJanice Chang 	len = strlen(dataset);
14138c4f9701SJanice Chang 	while (dataset[len-1] == '/') {
14148c4f9701SJanice Chang 		dataset[len-1] = '\0';
14158c4f9701SJanice Chang 		len--;
14168c4f9701SJanice Chang 	}
14178c4f9701SJanice Chang 
14188c4f9701SJanice Chang 	return (0);
14198c4f9701SJanice Chang }
14208c4f9701SJanice Chang 
14218c4f9701SJanice Chang static int
ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)14228c4f9701SJanice Chang ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
14238c4f9701SJanice Chang {
1424c1a2c731SJanice Chang 	if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args) != 0)
1425c1a2c731SJanice Chang 		return (-1);
1426c1a2c731SJanice Chang 
14278c4f9701SJanice Chang 	return (ndmpd_zfs_getenv(ndmpd_zfs_args));
14288c4f9701SJanice Chang }
14298c4f9701SJanice Chang 
14308c4f9701SJanice Chang static int
ndmpd_zfs_getenv(ndmpd_zfs_args_t * ndmpd_zfs_args)14318c4f9701SJanice Chang ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
14328c4f9701SJanice Chang {
14338c4f9701SJanice Chang 
14348c4f9701SJanice Chang 	if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0)
14358c4f9701SJanice Chang 		return (-1);
14368c4f9701SJanice Chang 
14378c4f9701SJanice Chang 	if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0)
14388c4f9701SJanice Chang 		return (-1);
14398c4f9701SJanice Chang 
14408c4f9701SJanice Chang 	if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0)
14418c4f9701SJanice Chang 		return (-1);
14428c4f9701SJanice Chang 
14438c4f9701SJanice Chang 	if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0)
14448c4f9701SJanice Chang 		return (-1);
14458c4f9701SJanice Chang 
14468c4f9701SJanice Chang 	if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0)
14478c4f9701SJanice Chang 		return (-1);
14488c4f9701SJanice Chang 
14498c4f9701SJanice Chang 	return (0);
14508c4f9701SJanice Chang }
14518c4f9701SJanice Chang 
14528c4f9701SJanice Chang static int
ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t * ndmpd_zfs_args)14538c4f9701SJanice Chang ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args)
14548c4f9701SJanice Chang {
14558c4f9701SJanice Chang 	char *envp;
14568c4f9701SJanice Chang 
14578c4f9701SJanice Chang 	envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE");
14588c4f9701SJanice Chang 
14598c4f9701SJanice Chang 	if (envp == NULL) {
14608c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, "
14618c4f9701SJanice Chang 		    "defaulting to recursive");
14628c4f9701SJanice Chang 		ndmpd_zfs_args->nz_zfs_mode = 'r';
14638c4f9701SJanice Chang 		return (0);
14648c4f9701SJanice Chang 	}
14658c4f9701SJanice Chang 
14668c4f9701SJanice Chang 	if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) {
14678c4f9701SJanice Chang 		ndmpd_zfs_args->nz_zfs_mode = 'd';
14688c4f9701SJanice Chang 	} else if ((strcmp(envp, "recursive") == 0) ||
14698c4f9701SJanice Chang 	    (strcmp(envp, "r") == 0)) {
14708c4f9701SJanice Chang 		ndmpd_zfs_args->nz_zfs_mode = 'r';
14718c4f9701SJanice Chang 	} else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) {
14728c4f9701SJanice Chang 		ndmpd_zfs_args->nz_zfs_mode = 'p';
14738c4f9701SJanice Chang 	} else {
14748c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
14758c4f9701SJanice Chang 		    "Invalid ZFS_MODE value \"%s\".\n", envp);
14768c4f9701SJanice Chang 		return (-1);
14778c4f9701SJanice Chang 	}
14788c4f9701SJanice Chang 
14798c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"",
14808c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_zfs_mode);
14818c4f9701SJanice Chang 
14828c4f9701SJanice Chang 	return (0);
14838c4f9701SJanice Chang }
14848c4f9701SJanice Chang 
1485d0194491SJanice Chang /*
1486d0194491SJanice Chang  * ndmpd_zfs_getenv_zfs_force()
1487d0194491SJanice Chang  *
1488d0194491SJanice Chang  * If SMF property zfs-force-override is set to "yes" or "no", this
1489d0194491SJanice Chang  * value will override any value of NDMP environment variable ZFS_FORCE
1490d0194491SJanice Chang  * as set by the DMA admin (or override the default of 'n', if ZFS_FORCE
1491d0194491SJanice Chang  * is not set).  By default, zfs-force-override is "off", which means it
1492d0194491SJanice Chang  * will not override ZFS_FORCE.
1493d0194491SJanice Chang  */
1494d0194491SJanice Chang 
14958c4f9701SJanice Chang static int
ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t * ndmpd_zfs_args)14968c4f9701SJanice Chang ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args)
14978c4f9701SJanice Chang {
14988c4f9701SJanice Chang 	char *envp_force;
1499d0194491SJanice Chang 	char *override;
1500d0194491SJanice Chang 
1501d0194491SJanice Chang 	override = ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE);
1502d0194491SJanice Chang 
1503d0194491SJanice Chang 	if (strcasecmp(override, "yes") == 0) {
1504d0194491SJanice Chang 		ndmpd_zfs_args->nz_zfs_force = B_TRUE;
1505d0194491SJanice Chang 		NDMP_LOG(LOG_NOTICE,
1506d0194491SJanice Chang 		    "SMF property zfs-force-override set to 'yes', "
1507d0194491SJanice Chang 		    "overriding ZFS_FORCE");
1508d0194491SJanice Chang 		return (0);
1509d0194491SJanice Chang 	}
1510d0194491SJanice Chang 
1511d0194491SJanice Chang 	if (strcasecmp(override, "no") == 0) {
1512d0194491SJanice Chang 		ndmpd_zfs_args->nz_zfs_force = B_FALSE;
1513d0194491SJanice Chang 		NDMP_LOG(LOG_NOTICE,
1514d0194491SJanice Chang 		    "SMF property zfs-force-override set to 'no', "
1515d0194491SJanice Chang 		    "overriding ZFS_FORCE");
1516d0194491SJanice Chang 		return (0);
1517d0194491SJanice Chang 	}
1518d0194491SJanice Chang 
1519d0194491SJanice Chang 	if (strcasecmp(override, "off") != 0) {
1520d0194491SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1521d0194491SJanice Chang 		    "SMF property zfs-force-override set to invalid value of "
1522d0194491SJanice Chang 		    "'%s'; treating it as 'off'.", override);
1523d0194491SJanice Chang 	}
15248c4f9701SJanice Chang 
15258c4f9701SJanice Chang 	envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE");
15268c4f9701SJanice Chang 
15278c4f9701SJanice Chang 	if (envp_force == NULL) {
15288c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG,
15298c4f9701SJanice Chang 		    "env(ZFS_FORCE) not specified, defaulting to FALSE");
15308c4f9701SJanice Chang 		ndmpd_zfs_args->nz_zfs_force = B_FALSE;
15318c4f9701SJanice Chang 		return (0);
15328c4f9701SJanice Chang 	}
15338c4f9701SJanice Chang 
15348c4f9701SJanice Chang 	/*
15358c4f9701SJanice Chang 	 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
15368c4f9701SJanice Chang 	 */
15378c4f9701SJanice Chang 
15388c4f9701SJanice Chang 	if (strchr("tTyY", *envp_force))
15398c4f9701SJanice Chang 		ndmpd_zfs_args->nz_zfs_force = B_TRUE;
15408c4f9701SJanice Chang 
15418c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force);
15428c4f9701SJanice Chang 
15438c4f9701SJanice Chang 	return (0);
15448c4f9701SJanice Chang }
15458c4f9701SJanice Chang 
15468c4f9701SJanice Chang static int
ndmpd_zfs_getenv_level(ndmpd_zfs_args_t * ndmpd_zfs_args)15478c4f9701SJanice Chang ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args)
15488c4f9701SJanice Chang {
15498c4f9701SJanice Chang 	char *envp;
15508c4f9701SJanice Chang 
15518c4f9701SJanice Chang 	envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL");
15528c4f9701SJanice Chang 
15538c4f9701SJanice Chang 	if (envp == NULL) {
15548c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, "
15558c4f9701SJanice Chang 		    "defaulting to 0");
15568c4f9701SJanice Chang 		ndmpd_zfs_args->nz_level = 0;
15578c4f9701SJanice Chang 		return (0);
15588c4f9701SJanice Chang 	}
15598c4f9701SJanice Chang 
15608c4f9701SJanice Chang 	if (envp[1] != '\0') {
15618c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
15628c4f9701SJanice Chang 		    "Invalid backup level \"%s\".\n", envp);
15638c4f9701SJanice Chang 		return (-1);
15648c4f9701SJanice Chang 	}
15658c4f9701SJanice Chang 
15668c4f9701SJanice Chang 	if (!isdigit(*envp)) {
15678c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
15688c4f9701SJanice Chang 		    "Invalid backup level \"%s\".\n", envp);
15698c4f9701SJanice Chang 		return (-1);
15708c4f9701SJanice Chang 	}
15718c4f9701SJanice Chang 
15728c4f9701SJanice Chang 	ndmpd_zfs_args->nz_level = atoi(envp);
15738c4f9701SJanice Chang 
15748c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"",
15758c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_level);
15768c4f9701SJanice Chang 
15778c4f9701SJanice Chang 	return (0);
15788c4f9701SJanice Chang }
15798c4f9701SJanice Chang 
15808c4f9701SJanice Chang static int
ndmpd_zfs_getenv_update(ndmpd_zfs_args_t * ndmpd_zfs_args)15818c4f9701SJanice Chang ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args)
15828c4f9701SJanice Chang {
15838c4f9701SJanice Chang 	char *envp_update;
15848c4f9701SJanice Chang 
15858c4f9701SJanice Chang 	envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE");
15868c4f9701SJanice Chang 
15878c4f9701SJanice Chang 	if (envp_update == NULL) {
15888c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG,
15898c4f9701SJanice Chang 		    "env(UPDATE) not specified, defaulting to TRUE");
15908c4f9701SJanice Chang 		ndmpd_zfs_args->nz_update = B_TRUE;
15918c4f9701SJanice Chang 		return (0);
15928c4f9701SJanice Chang 	}
15938c4f9701SJanice Chang 
15948c4f9701SJanice Chang 	/*
15958c4f9701SJanice Chang 	 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
15968c4f9701SJanice Chang 	 */
15978c4f9701SJanice Chang 
15988c4f9701SJanice Chang 	if (strchr("tTyY", *envp_update))
15998c4f9701SJanice Chang 		ndmpd_zfs_args->nz_update = B_TRUE;
16008c4f9701SJanice Chang 
16018c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update);
16028c4f9701SJanice Chang 
16038c4f9701SJanice Chang 	return (0);
16048c4f9701SJanice Chang }
16058c4f9701SJanice Chang 
16068c4f9701SJanice Chang static int
ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t * ndmpd_zfs_args)16078c4f9701SJanice Chang ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args)
16088c4f9701SJanice Chang {
16098c4f9701SJanice Chang 	char *envp;
16108c4f9701SJanice Chang 
16118c4f9701SJanice Chang 	envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME");
16128c4f9701SJanice Chang 
16138c4f9701SJanice Chang 	if (envp == NULL) {
16148c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG,
16158c4f9701SJanice Chang 		    "env(DMP_NAME) not specified, defaulting to 'level'");
16168c4f9701SJanice Chang 		(void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level",
16178c4f9701SJanice Chang 		    NDMPD_ZFS_DMP_NAME_MAX);
16188c4f9701SJanice Chang 		return (0);
16198c4f9701SJanice Chang 	}
16208c4f9701SJanice Chang 
16218c4f9701SJanice Chang 	if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp))
16228c4f9701SJanice Chang 		return (-1);
16238c4f9701SJanice Chang 
16248c4f9701SJanice Chang 	(void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp,
16258c4f9701SJanice Chang 	    NDMPD_ZFS_DMP_NAME_MAX);
16268c4f9701SJanice Chang 
16278c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp);
16288c4f9701SJanice Chang 
16298c4f9701SJanice Chang 	return (0);
16308c4f9701SJanice Chang }
16318c4f9701SJanice Chang 
1632c1a2c731SJanice Chang static int
ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t * ndmpd_zfs_args)1633c1a2c731SJanice Chang ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args)
1634c1a2c731SJanice Chang {
1635c1a2c731SJanice Chang 	char *zfs_backup_size;
1636c1a2c731SJanice Chang 
1637c1a2c731SJanice Chang 	zfs_backup_size = MOD_GETENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE");
1638c1a2c731SJanice Chang 
1639c1a2c731SJanice Chang 	if (zfs_backup_size == NULL) {
1640c1a2c731SJanice Chang 		NDMP_LOG(LOG_ERR, "ZFS_BACKUP_SIZE env is NULL");
1641c1a2c731SJanice Chang 		return (-1);
1642c1a2c731SJanice Chang 	}
1643c1a2c731SJanice Chang 
1644c1a2c731SJanice Chang 	NDMP_LOG(LOG_DEBUG, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size);
1645c1a2c731SJanice Chang 
1646c1a2c731SJanice Chang 	(void) sscanf(zfs_backup_size, "%llu",
1647c1a2c731SJanice Chang 	    &ndmpd_zfs_args->nz_zfs_backup_size);
1648c1a2c731SJanice Chang 
1649c1a2c731SJanice Chang 	return (0);
1650c1a2c731SJanice Chang }
1651c1a2c731SJanice Chang 
16528c4f9701SJanice Chang /*
16538c4f9701SJanice Chang  * ndmpd_zfs_dmp_name_valid()
16548c4f9701SJanice Chang  *
16558c4f9701SJanice Chang  * This function verifies that the dmp_name is valid.
16568c4f9701SJanice Chang  *
16578c4f9701SJanice Chang  * The dmp_name is restricted to alphanumeric characters plus
16588c4f9701SJanice Chang  * the underscore and hyphen, and must be 31 characters or less.
16598c4f9701SJanice Chang  * This is due to its use in the NDMPD_ZFS_PROP_INCR property
16608c4f9701SJanice Chang  * and in the ZFS snapshot name (if an ndmpd-generated snapshot
16618c4f9701SJanice Chang  * is required).
16628c4f9701SJanice Chang  */
16638c4f9701SJanice Chang 
16648c4f9701SJanice Chang static boolean_t
ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t * ndmpd_zfs_args,char * dmp_name)16658c4f9701SJanice Chang ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name)
16668c4f9701SJanice Chang {
16678c4f9701SJanice Chang 	char *c;
16688c4f9701SJanice Chang 
16698c4f9701SJanice Chang 	if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) {
16708c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
16718c4f9701SJanice Chang 		    "DMP_NAME %s is longer than %d\n",
16728c4f9701SJanice Chang 		    dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1);
16738c4f9701SJanice Chang 		return (B_FALSE);
16748c4f9701SJanice Chang 	}
16758c4f9701SJanice Chang 
16768c4f9701SJanice Chang 	for (c = dmp_name; *c != '\0'; c++) {
16778c4f9701SJanice Chang 		if (!isalpha(*c) && !isdigit(*c) &&
16788c4f9701SJanice Chang 		    (*c != '_') && (*c != '-')) {
16798c4f9701SJanice Chang 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
16808c4f9701SJanice Chang 			    "DMP_NAME %s contains illegal character %c\n",
16818c4f9701SJanice Chang 			    dmp_name, *c);
16828c4f9701SJanice Chang 			return (B_FALSE);
16838c4f9701SJanice Chang 		}
16848c4f9701SJanice Chang 	}
16858c4f9701SJanice Chang 
16868c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name);
16878c4f9701SJanice Chang 	return (B_TRUE);
16888c4f9701SJanice Chang }
16898c4f9701SJanice Chang 
16908c4f9701SJanice Chang /*
16918c4f9701SJanice Chang  * ndmpd_zfs_is_incremental()
16928c4f9701SJanice Chang  *
16938c4f9701SJanice Chang  * This can only be called after ndmpd_zfs_getenv_level()
16948c4f9701SJanice Chang  * has been called.
16958c4f9701SJanice Chang  */
16968c4f9701SJanice Chang 
16978c4f9701SJanice Chang static boolean_t
ndmpd_zfs_is_incremental(ndmpd_zfs_args_t * ndmpd_zfs_args)16988c4f9701SJanice Chang ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args)
16998c4f9701SJanice Chang {
17008c4f9701SJanice Chang 	return (ndmpd_zfs_args->nz_level != 0);
17018c4f9701SJanice Chang }
17028c4f9701SJanice Chang 
17038c4f9701SJanice Chang /*
17048c4f9701SJanice Chang  * ndmpd_zfs_snapshot_prepare()
17058c4f9701SJanice Chang  *
17068c4f9701SJanice Chang  * If no snapshot was supplied by the user, create a snapshot
17078c4f9701SJanice Chang  * for use by ndmpd.
17088c4f9701SJanice Chang  */
17098c4f9701SJanice Chang 
17108c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t * ndmpd_zfs_args)17118c4f9701SJanice Chang ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args)
17128c4f9701SJanice Chang {
17138c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
17148c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
17158c4f9701SJanice Chang 	boolean_t recursive = B_FALSE;
17168c4f9701SJanice Chang 	int zfs_err = 0;
17178c4f9701SJanice Chang 
17188c4f9701SJanice Chang 	if (session->ns_data.dd_abort) {
17198c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
17208c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset);
17218c4f9701SJanice Chang 		return (-1);
17228c4f9701SJanice Chang 	}
17238c4f9701SJanice Chang 
17248c4f9701SJanice Chang 	if (ndmpd_zfs_args->nz_snapname[0] == '\0') {
17258c4f9701SJanice Chang 		ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE;
17268c4f9701SJanice Chang 
17278c4f9701SJanice Chang 		if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) {
17288c4f9701SJanice Chang 			ndmpd_zfs_args->nz_snapname[0] = '\0';
17298c4f9701SJanice Chang 
17308c4f9701SJanice Chang 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
17318c4f9701SJanice Chang 			    "Error creating snapshot for %s\n",
17328c4f9701SJanice Chang 			    ndmpd_zfs_args->nz_dataset);
17338c4f9701SJanice Chang 
17348c4f9701SJanice Chang 			return (-1);
17358c4f9701SJanice Chang 		}
17368c4f9701SJanice Chang 	}
17378c4f9701SJanice Chang 
17388c4f9701SJanice Chang 	if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) {
17398c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG,
17408c4f9701SJanice Chang 		    "ndmpd_zfs_snapshot_prop_add error\n");
17418c4f9701SJanice Chang 
17428c4f9701SJanice Chang 		if (ndmpd_zfs_args->nz_ndmpd_snap) {
17438c4f9701SJanice Chang 
17448c4f9701SJanice Chang 			if (ndmpd_zfs_args->nz_zfs_mode != 'd')
17458c4f9701SJanice Chang 				recursive = B_TRUE;
17468c4f9701SJanice Chang 
17478c4f9701SJanice Chang 			(void) snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1748876b86efSReza Sabdar 			    ndmpd_zfs_args->nz_snapname, recursive, B_FALSE,
1749876b86efSReza Sabdar 			    &zfs_err);
17508c4f9701SJanice Chang 		}
17518c4f9701SJanice Chang 
17528c4f9701SJanice Chang 		return (-1);
17538c4f9701SJanice Chang 	}
17548c4f9701SJanice Chang 
17558c4f9701SJanice Chang 	return (0);
17568c4f9701SJanice Chang }
17578c4f9701SJanice Chang 
17588c4f9701SJanice Chang /*
17598c4f9701SJanice Chang  * ndmpd_zfs_snapshot_cleanup()
17608c4f9701SJanice Chang  *
17618c4f9701SJanice Chang  * If UPDATE = y, find the old snapshot (if any) corresponding to
1762d0194491SJanice Chang  * {LEVEL, DMP_NAME, ZFS_MODE}. If it was ndmpd-generated,
17638c4f9701SJanice Chang  * remove the snapshot.  Otherwise, update its NDMPD_ZFS_PROP_INCR
17648c4f9701SJanice Chang  * property to remove {L, D, Z}.
17658c4f9701SJanice Chang  *
17668c4f9701SJanice Chang  * If UPDATE = n, if an ndmpd-generated snapshot was used for backup,
17678c4f9701SJanice Chang  * remove the snapshot.  Otherwise, update its NDMPD_ZFS_PROP_INCR
17688c4f9701SJanice Chang  * property to remove {L, D, Z}.
17698c4f9701SJanice Chang  */
17708c4f9701SJanice Chang 
17718c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t * ndmpd_zfs_args,int err)17728c4f9701SJanice Chang ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err)
17738c4f9701SJanice Chang {
17748c4f9701SJanice Chang 	ndmpd_session_t *session = (ndmpd_session_t *)
17758c4f9701SJanice Chang 	    (ndmpd_zfs_params->mp_daemon_cookie);
17768c4f9701SJanice Chang 	ndmpd_zfs_snapfind_t snapdata;
17778c4f9701SJanice Chang 	boolean_t ndmpd_generated = B_FALSE;
17788c4f9701SJanice Chang 
17798c4f9701SJanice Chang 	bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t));
17808c4f9701SJanice Chang 
17818c4f9701SJanice Chang 	(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
17828c4f9701SJanice Chang 	    snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE);
17838c4f9701SJanice Chang 
17848c4f9701SJanice Chang 	if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) {
17858c4f9701SJanice Chang 		/*
17868c4f9701SJanice Chang 		 * Find the existing snapshot, if any, to "unuse."
17878c4f9701SJanice Chang 		 * Indicate that the current snapshot used for backup
17888c4f9701SJanice Chang 		 * should be skipped in the search.  (The search is
17898c4f9701SJanice Chang 		 * sorted by creation time but this cannot be relied
17908c4f9701SJanice Chang 		 * upon for user-supplied snapshots.)
17918c4f9701SJanice Chang 		 */
17928c4f9701SJanice Chang 
17939adfa60dSMatthew Ahrens 		(void) snprintf(snapdata.nzs_snapskip, ZFS_MAX_DATASET_NAME_LEN,
17949adfa60dSMatthew Ahrens 		    "%s", ndmpd_zfs_args->nz_snapname);
17958c4f9701SJanice Chang 
17968c4f9701SJanice Chang 		if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) {
17978c4f9701SJanice Chang 			NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n");
17988c4f9701SJanice Chang 			goto _remove_tmp_snap;
17998c4f9701SJanice Chang 		}
18008c4f9701SJanice Chang 
18018c4f9701SJanice Chang 		if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */
18028c4f9701SJanice Chang 			ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated
18038c4f9701SJanice Chang 			    (snapdata.nzs_snapprop);
18048c4f9701SJanice Chang 
18058c4f9701SJanice Chang 			if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
18068c4f9701SJanice Chang 			    ndmpd_generated, &snapdata) != 0) {
18078c4f9701SJanice Chang 				NDMP_LOG(LOG_DEBUG,
18088c4f9701SJanice Chang 				    "ndmpd_zfs_snapshot_unuse error\n");
18098c4f9701SJanice Chang 				goto _remove_tmp_snap;
18108c4f9701SJanice Chang 			}
18118c4f9701SJanice Chang 		}
18128c4f9701SJanice Chang 
18138c4f9701SJanice Chang 		if (session->ns_data.dd_abort)
18148c4f9701SJanice Chang 			goto _remove_tmp_snap;
18158c4f9701SJanice Chang 
18168c4f9701SJanice Chang 		return (0);
18178c4f9701SJanice Chang 	}
18188c4f9701SJanice Chang 
18198c4f9701SJanice Chang _remove_tmp_snap:
18208c4f9701SJanice Chang 
18219adfa60dSMatthew Ahrens 	(void) snprintf(snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN, "%s",
18228c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_snapname);
18238c4f9701SJanice Chang 
18248c4f9701SJanice Chang 	(void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop,
18258c4f9701SJanice Chang 	    ZFS_MAXPROPLEN);
18268c4f9701SJanice Chang 
18278c4f9701SJanice Chang 	snapdata.nzs_snapskip[0] = '\0';
18288c4f9701SJanice Chang 
18298c4f9701SJanice Chang 	if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
18308c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) {
18318c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n");
18328c4f9701SJanice Chang 		return (-1);
18338c4f9701SJanice Chang 	}
18348c4f9701SJanice Chang 
18358c4f9701SJanice Chang 	if (!ndmpd_zfs_args->nz_update)
18368c4f9701SJanice Chang 		return (0);
18378c4f9701SJanice Chang 
18388c4f9701SJanice Chang 	return (-1);
18398c4f9701SJanice Chang }
18408c4f9701SJanice Chang 
18418c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t * ndmpd_zfs_args)18428c4f9701SJanice Chang ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args)
18438c4f9701SJanice Chang {
18448c4f9701SJanice Chang 	boolean_t recursive = B_FALSE;
18458c4f9701SJanice Chang 
18468c4f9701SJanice Chang 	if (ndmpd_zfs_snapname_create(ndmpd_zfs_args,
18479adfa60dSMatthew Ahrens 	    ndmpd_zfs_args->nz_snapname, ZFS_MAX_DATASET_NAME_LEN - 1) < 0) {
18488c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s",
18498c4f9701SJanice Chang 		    errno, ndmpd_zfs_args->nz_dataset);
18508c4f9701SJanice Chang 		return (-1);
18518c4f9701SJanice Chang 	}
18528c4f9701SJanice Chang 
18538c4f9701SJanice Chang 	if (ndmpd_zfs_args->nz_zfs_mode != 'd')
18548c4f9701SJanice Chang 		recursive = B_TRUE;
18558c4f9701SJanice Chang 
18568c4f9701SJanice Chang 	if (snapshot_create(ndmpd_zfs_args->nz_dataset,
1857876b86efSReza Sabdar 	    ndmpd_zfs_args->nz_snapname, recursive, B_FALSE) != 0) {
18588c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s",
18598c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
18608c4f9701SJanice Chang 		return (-1);
18618c4f9701SJanice Chang 	}
18628c4f9701SJanice Chang 
18638c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s",
18648c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
18658c4f9701SJanice Chang 
18668c4f9701SJanice Chang 	return (0);
18678c4f9701SJanice Chang }
18688c4f9701SJanice Chang 
18698c4f9701SJanice Chang /*
18708c4f9701SJanice Chang  * ndmpd_zfs_snapshot_unuse()
18718c4f9701SJanice Chang  *
18728c4f9701SJanice Chang  * Given a pre-existing snapshot of the given {L, D, Z}:
18738c4f9701SJanice Chang  * If snapshot is ndmpd-generated, remove snapshot.
18748c4f9701SJanice Chang  * If not ndmpd-generated, or if the ndmpd-generated snapshot
18758c4f9701SJanice Chang  * cannot be destroyed, remove the {L, D, Z} substring from the
18768c4f9701SJanice Chang  * snapshot's NDMPD_ZFS_PROP_INCR property.
18778c4f9701SJanice Chang  *
18788c4f9701SJanice Chang  * In the event of a failure, it may be that two snapshots will
18798c4f9701SJanice Chang  * have the {L, D, Z} property set on them.  This is not desirable,
18808c4f9701SJanice Chang  * so return an error and log the failure.
18818c4f9701SJanice Chang  */
18828c4f9701SJanice Chang 
18838c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t * ndmpd_zfs_args,boolean_t ndmpd_generated,ndmpd_zfs_snapfind_t * snapdata_p)18848c4f9701SJanice Chang ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args,
18858c4f9701SJanice Chang     boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p)
18868c4f9701SJanice Chang {
18878c4f9701SJanice Chang 	boolean_t recursive = B_FALSE;
18888c4f9701SJanice Chang 	int zfs_err = 0;
18898c4f9701SJanice Chang 	int err = 0;
18908c4f9701SJanice Chang 
18918c4f9701SJanice Chang 	if (ndmpd_generated) {
18928c4f9701SJanice Chang 		if (ndmpd_zfs_args->nz_zfs_mode != 'd')
18938c4f9701SJanice Chang 			recursive = B_TRUE;
18948c4f9701SJanice Chang 
18958c4f9701SJanice Chang 		err = snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1896876b86efSReza Sabdar 		    snapdata_p->nzs_snapname, recursive, B_FALSE, &zfs_err);
18978c4f9701SJanice Chang 
18988c4f9701SJanice Chang 		if (err) {
18998c4f9701SJanice Chang 			NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;"
19008c4f9701SJanice Chang 			    " err: %d; zfs_err: %d",
19018c4f9701SJanice Chang 			    ndmpd_zfs_args->nz_dataset,
19028c4f9701SJanice Chang 			    snapdata_p->nzs_snapname, err, zfs_err);
19038c4f9701SJanice Chang 			return (-1);
19048c4f9701SJanice Chang 		}
19058c4f9701SJanice Chang 	}
19068c4f9701SJanice Chang 
19078c4f9701SJanice Chang 	if (!ndmpd_generated || zfs_err) {
19088c4f9701SJanice Chang 		if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p))
19098c4f9701SJanice Chang 			return (-1);
19108c4f9701SJanice Chang 	}
19118c4f9701SJanice Chang 
19128c4f9701SJanice Chang 	return (0);
19138c4f9701SJanice Chang }
19148c4f9701SJanice Chang 
19158c4f9701SJanice Chang static boolean_t
ndmpd_zfs_snapshot_ndmpd_generated(char * snapprop)19168c4f9701SJanice Chang ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop)
19178c4f9701SJanice Chang {
19188c4f9701SJanice Chang 	char origin;
19198c4f9701SJanice Chang 
19208c4f9701SJanice Chang 	(void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin);
19218c4f9701SJanice Chang 
19228c4f9701SJanice Chang 	return (origin == 'n');
19238c4f9701SJanice Chang }
19248c4f9701SJanice Chang 
19258c4f9701SJanice Chang /*
19268c4f9701SJanice Chang  * ndmpd_zfs_snapshot_find()
19278c4f9701SJanice Chang  *
19288c4f9701SJanice Chang  * Find a snapshot with a particular value for
19298c4f9701SJanice Chang  * the NDMPD_ZFS_PROP_INCR property.
19308c4f9701SJanice Chang  */
19318c4f9701SJanice Chang 
19328c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmpd_zfs_snapfind_t * snapdata)19338c4f9701SJanice Chang ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args,
19348c4f9701SJanice Chang     ndmpd_zfs_snapfind_t *snapdata)
19358c4f9701SJanice Chang {
19368c4f9701SJanice Chang 	zfs_handle_t *zhp;
19378c4f9701SJanice Chang 	int err;
19388c4f9701SJanice Chang 
19398c4f9701SJanice Chang 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
19408c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_type);
19418c4f9701SJanice Chang 
19428c4f9701SJanice Chang 	if (!zhp) {
19438c4f9701SJanice Chang 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
19448c4f9701SJanice Chang 		return (-1);
19458c4f9701SJanice Chang 	}
19468c4f9701SJanice Chang 
19478c4f9701SJanice Chang 	err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find,
19488c4f9701SJanice Chang 	    snapdata);
19498c4f9701SJanice Chang 
19508c4f9701SJanice Chang 	zfs_close(zhp);
19518c4f9701SJanice Chang 
19528c4f9701SJanice Chang 	if (err) {
19538c4f9701SJanice Chang 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d",
19548c4f9701SJanice Chang 		    err);
19558c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
19568c4f9701SJanice Chang 		    "Error iterating snapshots\n");
19578c4f9701SJanice Chang 		return (-1);
19588c4f9701SJanice Chang 	}
19598c4f9701SJanice Chang 
19608c4f9701SJanice Chang 	return (0);
19618c4f9701SJanice Chang }
19628c4f9701SJanice Chang 
19638c4f9701SJanice Chang /*
19648c4f9701SJanice Chang  * ndmpd_zfs_snapshot_prop_find()
19658c4f9701SJanice Chang  *
19668c4f9701SJanice Chang  * Find a snapshot with a particular value for
19678c4f9701SJanice Chang  * NDMPD_ZFS_PROP_INCR.  Fill in data for the first one
19688c4f9701SJanice Chang  * found (sorted by creation time).  However, skip the
19698c4f9701SJanice Chang  * the snapshot indicated in nzs_snapskip, if any.
19708c4f9701SJanice Chang  */
19718c4f9701SJanice Chang 
19728c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_prop_find(zfs_handle_t * zhp,void * arg)19738c4f9701SJanice Chang ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg)
19748c4f9701SJanice Chang {
19758c4f9701SJanice Chang 	ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg;
19768c4f9701SJanice Chang 	char propstr[ZFS_MAXPROPLEN];
19778c4f9701SJanice Chang 	char findprop_plus_slash[ZFS_MAXPROPLEN];
19788c4f9701SJanice Chang 	char *justsnap;
19798c4f9701SJanice Chang 	int err = 0;
19808c4f9701SJanice Chang 
19818c4f9701SJanice Chang 	if (snapdata_p->nzs_snapname[0] != '\0') {
19828c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s",
19838c4f9701SJanice Chang 		    (char *)zfs_get_name(zhp));
19848c4f9701SJanice Chang 		goto _done;
19858c4f9701SJanice Chang 	}
19868c4f9701SJanice Chang 
19878c4f9701SJanice Chang 	err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
19888c4f9701SJanice Chang 
19898c4f9701SJanice Chang 	if (err) {
19908c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed");
19918c4f9701SJanice Chang 		goto _done;
19928c4f9701SJanice Chang 	}
19938c4f9701SJanice Chang 
19948c4f9701SJanice Chang 	if (propstr[0] == '\0') {
19958c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set",
19968c4f9701SJanice Chang 		    (char *)zfs_get_name(zhp));
19978c4f9701SJanice Chang 		goto _done;
19988c4f9701SJanice Chang 	}
19998c4f9701SJanice Chang 
20008c4f9701SJanice Chang 	(void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
20018c4f9701SJanice Chang 	    snapdata_p->nzs_findprop);
20028c4f9701SJanice Chang 
20038c4f9701SJanice Chang 	if (!strstr((const char *)propstr,
20048c4f9701SJanice Chang 	    (const char *)findprop_plus_slash)) {
20058c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)",
20068c4f9701SJanice Chang 		    (char *)zfs_get_name(zhp), propstr,
20078c4f9701SJanice Chang 		    snapdata_p->nzs_findprop);
20088c4f9701SJanice Chang 		goto _done;
20098c4f9701SJanice Chang 	}
20108c4f9701SJanice Chang 
20118c4f9701SJanice Chang 	if (!ndmpd_zfs_prop_version_check(propstr,
20128c4f9701SJanice Chang 	    &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) {
20138c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)",
20148c4f9701SJanice Chang 		    (char *)zfs_get_name(zhp),  propstr,
20158c4f9701SJanice Chang 		    snapdata_p->nzs_findprop);
20168c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "did not pass version check");
20178c4f9701SJanice Chang 		goto _done;
20188c4f9701SJanice Chang 	}
20198c4f9701SJanice Chang 
20208c4f9701SJanice Chang 	justsnap = strchr(zfs_get_name(zhp), '@') + 1;
20218c4f9701SJanice Chang 
20228c4f9701SJanice Chang 	if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) {
20238c4f9701SJanice Chang 		(void) strlcpy(snapdata_p->nzs_snapname, justsnap,
20249adfa60dSMatthew Ahrens 		    ZFS_MAX_DATASET_NAME_LEN);
20258c4f9701SJanice Chang 
20268c4f9701SJanice Chang 		(void) strlcpy(snapdata_p->nzs_snapprop, propstr,
20278c4f9701SJanice Chang 		    ZFS_MAXPROPLEN);
20288c4f9701SJanice Chang 
20298c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n",
20308c4f9701SJanice Chang 		    snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop);
20318c4f9701SJanice Chang 	}
20328c4f9701SJanice Chang 
20338c4f9701SJanice Chang _done:
20348c4f9701SJanice Chang 	zfs_close(zhp);
20358c4f9701SJanice Chang 	return (err);
20368c4f9701SJanice Chang }
20378c4f9701SJanice Chang 
20388c4f9701SJanice Chang /*
20398c4f9701SJanice Chang  * ndmpd_zfs_snapshot_prop_get()
20408c4f9701SJanice Chang  *
20418c4f9701SJanice Chang  * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot
20428c4f9701SJanice Chang  */
20438c4f9701SJanice Chang 
20448c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_prop_get(zfs_handle_t * zhp,char * propstr)20458c4f9701SJanice Chang ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr)
20468c4f9701SJanice Chang {
20478c4f9701SJanice Chang 	nvlist_t *userprop;
20488c4f9701SJanice Chang 	nvlist_t *propval;
20498c4f9701SJanice Chang 	char *strval;
20508c4f9701SJanice Chang 	int err;
20518c4f9701SJanice Chang 
20528c4f9701SJanice Chang 	propstr[0] = '\0';
20538c4f9701SJanice Chang 
20548c4f9701SJanice Chang 	userprop = zfs_get_user_props(zhp);
20558c4f9701SJanice Chang 
20568c4f9701SJanice Chang 	if (userprop == NULL)
20578c4f9701SJanice Chang 		return (0);
20588c4f9701SJanice Chang 
20598c4f9701SJanice Chang 	err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval);
20608c4f9701SJanice Chang 
20618c4f9701SJanice Chang 	if (err != 0) {
20628c4f9701SJanice Chang 		if (err == ENOENT)
20638c4f9701SJanice Chang 			return (0);
20648c4f9701SJanice Chang 
20658c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err);
20668c4f9701SJanice Chang 
20678c4f9701SJanice Chang 		return (-1);
20688c4f9701SJanice Chang 	}
20698c4f9701SJanice Chang 
20708c4f9701SJanice Chang 	err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
20718c4f9701SJanice Chang 
20728c4f9701SJanice Chang 	if (err != 0) {
20738c4f9701SJanice Chang 		if (err == ENOENT)
20748c4f9701SJanice Chang 			return (0);
20758c4f9701SJanice Chang 
20768c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err);
20778c4f9701SJanice Chang 
20788c4f9701SJanice Chang 		return (-1);
20798c4f9701SJanice Chang 	}
20808c4f9701SJanice Chang 
20818c4f9701SJanice Chang 	(void) strlcpy(propstr, strval, ZFS_MAXPROPLEN);
20828c4f9701SJanice Chang 
20838c4f9701SJanice Chang 	return (0);
20848c4f9701SJanice Chang }
20858c4f9701SJanice Chang 
20868c4f9701SJanice Chang /*
20878c4f9701SJanice Chang  * ndmpd_zfs_snapshot_prop_add()
20888c4f9701SJanice Chang  *
20898c4f9701SJanice Chang  * Update snapshot's NDMPD_ZFS_PROP_INCR property with
2090d0194491SJanice Chang  * the current LEVEL, DMP_NAME, and ZFS_MODE values
20918c4f9701SJanice Chang  * (add property if it doesn't exist)
20928c4f9701SJanice Chang  */
20938c4f9701SJanice Chang 
20948c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t * ndmpd_zfs_args)20958c4f9701SJanice Chang ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args)
20968c4f9701SJanice Chang {
20979adfa60dSMatthew Ahrens 	char fullname[ZFS_MAX_DATASET_NAME_LEN];
20988c4f9701SJanice Chang 	char propstr[ZFS_MAXPROPLEN];
20998c4f9701SJanice Chang 	zfs_handle_t *zhp;
21008c4f9701SJanice Chang 	boolean_t set;
21018c4f9701SJanice Chang 	int err;
21028c4f9701SJanice Chang 
21039adfa60dSMatthew Ahrens 	(void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
21048c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_dataset,
21058c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_snapname);
21068c4f9701SJanice Chang 
21078c4f9701SJanice Chang 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
21088c4f9701SJanice Chang 
21098c4f9701SJanice Chang 	if (!zhp) {
21108c4f9701SJanice Chang 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)");
21118c4f9701SJanice Chang 		return (-1);
21128c4f9701SJanice Chang 	}
21138c4f9701SJanice Chang 
21148c4f9701SJanice Chang 	bzero(propstr, ZFS_MAXPROPLEN);
21158c4f9701SJanice Chang 
21168c4f9701SJanice Chang 	if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) {
21178c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "error getting property");
21188c4f9701SJanice Chang 		zfs_close(zhp);
21198c4f9701SJanice Chang 		return (-1);
21208c4f9701SJanice Chang 	}
21218c4f9701SJanice Chang 
21228c4f9701SJanice Chang 	if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) {
21238c4f9701SJanice Chang 		zfs_close(zhp);
21248c4f9701SJanice Chang 		return (-1);
21258c4f9701SJanice Chang 	}
21268c4f9701SJanice Chang 
21278c4f9701SJanice Chang 	if (set) {
21288c4f9701SJanice Chang 		err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr);
21298c4f9701SJanice Chang 		if (err) {
21308c4f9701SJanice Chang 			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
21318c4f9701SJanice Chang 			    err);
21328c4f9701SJanice Chang 			NDMP_LOG(LOG_ERR, "error setting property %s",
21338c4f9701SJanice Chang 			    propstr);
21348c4f9701SJanice Chang 			zfs_close(zhp);
21358c4f9701SJanice Chang 			return (-1);
21368c4f9701SJanice Chang 		}
21378c4f9701SJanice Chang 	}
21388c4f9701SJanice Chang 
21398c4f9701SJanice Chang 	zfs_close(zhp);
21408c4f9701SJanice Chang 
21418c4f9701SJanice Chang 	(void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN);
21428c4f9701SJanice Chang 
21438c4f9701SJanice Chang 	return (0);
21448c4f9701SJanice Chang }
21458c4f9701SJanice Chang 
21468c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t * ndmpd_zfs_args,char * propstr,boolean_t * set)21478c4f9701SJanice Chang ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
21488c4f9701SJanice Chang     char *propstr, boolean_t *set)
21498c4f9701SJanice Chang {
21508c4f9701SJanice Chang 	char subprop[ZFS_MAXPROPLEN];
2151d0194491SJanice Chang 	char *p = propstr;
2152d0194491SJanice Chang 	int slash_count = 0;
21538c4f9701SJanice Chang 
21548c4f9701SJanice Chang 	*set = B_TRUE;
21558c4f9701SJanice Chang 
21568c4f9701SJanice Chang 	(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
21578c4f9701SJanice Chang 	    subprop, ZFS_MAXPROPLEN, B_FALSE);
21588c4f9701SJanice Chang 
21598c4f9701SJanice Chang 	if (propstr[0] == '\0') {
21608c4f9701SJanice Chang 		(void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s",
21618c4f9701SJanice Chang 		    NDMPD_ZFS_PROP_MAJOR_VERSION,
21628c4f9701SJanice Chang 		    NDMPD_ZFS_PROP_MINOR_VERSION,
21638c4f9701SJanice Chang 		    (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u',
21648c4f9701SJanice Chang 		    subprop);
21658c4f9701SJanice Chang 		return (0);
21668c4f9701SJanice Chang 	}
21678c4f9701SJanice Chang 
21688c4f9701SJanice Chang 	if (strstr((const char *)propstr, (const char *)subprop)) {
21698c4f9701SJanice Chang 		NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists",
21708c4f9701SJanice Chang 		    subprop);
21718c4f9701SJanice Chang 		*set = B_FALSE;
21728c4f9701SJanice Chang 		return (0);
21738c4f9701SJanice Chang 	}
21748c4f9701SJanice Chang 
2175d0194491SJanice Chang 	while (*p) {
2176d0194491SJanice Chang 		if (*(p++) == '/')
2177d0194491SJanice Chang 			slash_count++;
2178d0194491SJanice Chang 	}
2179d0194491SJanice Chang 
2180d0194491SJanice Chang 	if (slash_count >= NDMPD_ZFS_SUBPROP_MAX) {
2181d0194491SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2182d0194491SJanice Chang 		    "snapshot %s: user property %s limit of %d subprops "
2183d0194491SJanice Chang 		    "reached; cannot complete operation",
21848c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_snapname,
2185d0194491SJanice Chang 		    NDMPD_ZFS_PROP_INCR,
2186d0194491SJanice Chang 		    NDMPD_ZFS_SUBPROP_MAX);
21878c4f9701SJanice Chang 		return (-1);
21888c4f9701SJanice Chang 	}
21898c4f9701SJanice Chang 
2190d0194491SJanice Chang 	assert((strlen(propstr) + strlen(subprop) + 2) < ZFS_MAXPROPLEN);
2191d0194491SJanice Chang 
21928c4f9701SJanice Chang 	(void) strlcat(propstr, "/", ZFS_MAXPROPLEN);
21938c4f9701SJanice Chang 	(void) strlcat(propstr, subprop, ZFS_MAXPROPLEN);
21948c4f9701SJanice Chang 
21958c4f9701SJanice Chang 	return (0);
21968c4f9701SJanice Chang }
21978c4f9701SJanice Chang 
21988c4f9701SJanice Chang static int
ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t * ndmpd_zfs_args,char * subprop,int len,boolean_t prev_level)21998c4f9701SJanice Chang ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args,
22008c4f9701SJanice Chang     char *subprop, int len, boolean_t prev_level)
22018c4f9701SJanice Chang {
22028c4f9701SJanice Chang 	return (snprintf(subprop, len, "%d.%s.%c",
22038c4f9701SJanice Chang 	    prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level,
22048c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_dmp_name,
22058c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_zfs_mode));
22068c4f9701SJanice Chang }
22078c4f9701SJanice Chang 
22088c4f9701SJanice Chang /*
22098c4f9701SJanice Chang  * ndmpd_zfs_snapshot_prop_remove()
22108c4f9701SJanice Chang  *
22118c4f9701SJanice Chang  * Remove specified substring from the snapshot's
22128c4f9701SJanice Chang  * NDMPD_ZFS_PROP_INCR property
22138c4f9701SJanice Chang  */
22148c4f9701SJanice Chang 
22158c4f9701SJanice Chang static int
ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmpd_zfs_snapfind_t * snapdata_p)22168c4f9701SJanice Chang ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args,
22178c4f9701SJanice Chang     ndmpd_zfs_snapfind_t *snapdata_p)
22188c4f9701SJanice Chang {
22198c4f9701SJanice Chang 	char findprop_plus_slash[ZFS_MAXPROPLEN];
22209adfa60dSMatthew Ahrens 	char fullname[ZFS_MAX_DATASET_NAME_LEN];
22218c4f9701SJanice Chang 	char newprop[ZFS_MAXPROPLEN];
22228c4f9701SJanice Chang 	char tmpstr[ZFS_MAXPROPLEN];
22238c4f9701SJanice Chang 	zfs_handle_t *zhp;
22248c4f9701SJanice Chang 	char *ptr;
22258c4f9701SJanice Chang 	int err;
22268c4f9701SJanice Chang 
22279adfa60dSMatthew Ahrens 	(void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
22288c4f9701SJanice Chang 	    ndmpd_zfs_args->nz_dataset,
22298c4f9701SJanice Chang 	    snapdata_p->nzs_snapname);
22308c4f9701SJanice Chang 
22318c4f9701SJanice Chang 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
22328c4f9701SJanice Chang 
22338c4f9701SJanice Chang 	if (!zhp) {
22348c4f9701SJanice Chang 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
22358c4f9701SJanice Chang 		return (-1);
22368c4f9701SJanice Chang 	}
22378c4f9701SJanice Chang 
22388c4f9701SJanice Chang 	bzero(newprop, ZFS_MAXPROPLEN);
22398c4f9701SJanice Chang 
22408c4f9701SJanice Chang 	/*
22418c4f9701SJanice Chang 	 * If the substring to be removed is the only {L, D, Z}
22428c4f9701SJanice Chang 	 * in the property, remove the entire property
22438c4f9701SJanice Chang 	 */
22448c4f9701SJanice Chang 
22458c4f9701SJanice Chang 	tmpstr[0] = '\0';
22468c4f9701SJanice Chang 
22478c4f9701SJanice Chang 	(void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr);
22488c4f9701SJanice Chang 
22498c4f9701SJanice Chang 	if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) {
22508c4f9701SJanice Chang 
22518c4f9701SJanice Chang 		err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
22528c4f9701SJanice Chang 
22538c4f9701SJanice Chang 		zfs_close(zhp);
22548c4f9701SJanice Chang 
22558c4f9701SJanice Chang 		if (err) {
22568c4f9701SJanice Chang 			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
22578c4f9701SJanice Chang 			    err);
22588c4f9701SJanice Chang 			NDMP_LOG(LOG_ERR, "error setting property %s", newprop);
22598c4f9701SJanice Chang 			return (-1);
22608c4f9701SJanice Chang 		}
22618c4f9701SJanice Chang 
22628c4f9701SJanice Chang 		return (0);
22638c4f9701SJanice Chang 	}
22648c4f9701SJanice Chang 
22658c4f9701SJanice Chang 	(void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
22668c4f9701SJanice Chang 	    snapdata_p->nzs_findprop);
22678c4f9701SJanice Chang 
22688c4f9701SJanice Chang 	ptr = strstr((const char *)snapdata_p->nzs_snapprop,
22698c4f9701SJanice Chang 	    (const char *)findprop_plus_slash);
22708c4f9701SJanice Chang 
22718c4f9701SJanice Chang 	if (ptr == NULL) {
22728c4f9701SJanice Chang 		/*
22738c4f9701SJanice Chang 		 * This shouldn't happen.  Just return success.
22748c4f9701SJanice Chang 		 */
22758c4f9701SJanice Chang 		zfs_close(zhp);
22768c4f9701SJanice Chang 
22778c4f9701SJanice Chang 		return (0);
22788c4f9701SJanice Chang 	}
22798c4f9701SJanice Chang 
22808c4f9701SJanice Chang 	/*
22818c4f9701SJanice Chang 	 * Remove "nzs_findprop" substring from property
22828c4f9701SJanice Chang 	 *
22838c4f9701SJanice Chang 	 * Example property:
22848c4f9701SJanice Chang 	 *	0.0.u/1.bob.p/0.jane.d
22858c4f9701SJanice Chang 	 *
22868c4f9701SJanice Chang 	 * Note that there will always be a prefix to the
22878c4f9701SJanice Chang 	 * strstr() result.  Hence the below code works for
22888c4f9701SJanice Chang 	 * all cases.
22898c4f9701SJanice Chang 	 */
22908c4f9701SJanice Chang 
22918c4f9701SJanice Chang 	ptr--;
22928c4f9701SJanice Chang 	(void) strncpy(newprop, snapdata_p->nzs_snapprop,
22938c4f9701SJanice Chang 	    (char *)ptr - snapdata_p->nzs_snapprop);
22948c4f9701SJanice Chang 	ptr += strlen(snapdata_p->nzs_findprop) + 1;
22958c4f9701SJanice Chang 	(void) strlcat(newprop, ptr, ZFS_MAXPROPLEN);
22968c4f9701SJanice Chang 
22978c4f9701SJanice Chang 	err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
22988c4f9701SJanice Chang 
22998c4f9701SJanice Chang 	zfs_close(zhp);
23008c4f9701SJanice Chang 
23018c4f9701SJanice Chang 	if (err) {
23028c4f9701SJanice Chang 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err);
23038c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "error modifying property %s", newprop);
23048c4f9701SJanice Chang 		return (-1);
23058c4f9701SJanice Chang 	}
23068c4f9701SJanice Chang 
23078c4f9701SJanice Chang 	return (0);
23088c4f9701SJanice Chang }
23098c4f9701SJanice Chang 
23108c4f9701SJanice Chang static boolean_t
ndmpd_zfs_prop_version_check(char * propstr,uint32_t * major,uint32_t * minor)23118c4f9701SJanice Chang ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor)
23128c4f9701SJanice Chang {
23138c4f9701SJanice Chang 	(void) sscanf(propstr, "%u.%u.%*c%*s", major, minor);
23148c4f9701SJanice Chang 
23158c4f9701SJanice Chang 	if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) {
23168c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)",
23178c4f9701SJanice Chang 		    *major, NDMPD_ZFS_PROP_MAJOR_VERSION);
23188c4f9701SJanice Chang 		return (B_FALSE);
23198c4f9701SJanice Chang 	}
23208c4f9701SJanice Chang 
23218c4f9701SJanice Chang 	if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) {
23228c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)",
23238c4f9701SJanice Chang 		    *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
23248c4f9701SJanice Chang 	}
23258c4f9701SJanice Chang 
23268c4f9701SJanice Chang 	NDMP_LOG(LOG_DEBUG, "passed version check: "
23278c4f9701SJanice Chang 	    "supported prop major (%u <= %u); (snapprop minor: %u [%u])",
23288c4f9701SJanice Chang 	    *major, NDMPD_ZFS_PROP_MAJOR_VERSION,
23298c4f9701SJanice Chang 	    *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
23308c4f9701SJanice Chang 
23318c4f9701SJanice Chang 	return (B_TRUE);
23328c4f9701SJanice Chang }
23338c4f9701SJanice Chang 
23348c4f9701SJanice Chang static int
ndmpd_zfs_snapname_create(ndmpd_zfs_args_t * ndmpd_zfs_args,char * snapname,int namelen)23358c4f9701SJanice Chang ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
23368c4f9701SJanice Chang     char *snapname, int namelen)
23378c4f9701SJanice Chang {
23388c4f9701SJanice Chang 	char subprop[ZFS_MAXPROPLEN];
23398c4f9701SJanice Chang 	struct timeval tp;
23408c4f9701SJanice Chang 	int err = 0;
23418c4f9701SJanice Chang 
23428c4f9701SJanice Chang 	(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
23438c4f9701SJanice Chang 	    subprop, ZFS_MAXPROPLEN, B_FALSE);
23448c4f9701SJanice Chang 
23458c4f9701SJanice Chang 	(void) gettimeofday(&tp, NULL);
23468c4f9701SJanice Chang 
23478c4f9701SJanice Chang 	err = snprintf(snapname, namelen,
23488c4f9701SJanice Chang 	    "ndmp.%s.%ld.%ld",
23498c4f9701SJanice Chang 	    subprop,
23508c4f9701SJanice Chang 	    tp.tv_sec,
23518c4f9701SJanice Chang 	    tp.tv_usec);
23528c4f9701SJanice Chang 
23538c4f9701SJanice Chang 	if (err > namelen) {
23548c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d",
23558c4f9701SJanice Chang 		    snapname, namelen);
23568c4f9701SJanice Chang 		return (-1);
23578c4f9701SJanice Chang 	}
23588c4f9701SJanice Chang 
23598c4f9701SJanice Chang 	return (0);
23608c4f9701SJanice Chang }
23618c4f9701SJanice Chang 
23628c4f9701SJanice Chang static void
ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t * ndmpd_zfs_args)23638c4f9701SJanice Chang ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args)
23648c4f9701SJanice Chang {
23658c4f9701SJanice Chang 	switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) {
23668c4f9701SJanice Chang 	case EZFS_EXISTS:
23678c4f9701SJanice Chang 	case EZFS_BUSY:
23688c4f9701SJanice Chang 	case EZFS_NOENT:
23698c4f9701SJanice Chang 	case EZFS_INVALIDNAME:
23708c4f9701SJanice Chang 	case EZFS_MOUNTFAILED:
23718c4f9701SJanice Chang 	case EZFS_UMOUNTFAILED:
23728c4f9701SJanice Chang 	case EZFS_NAMETOOLONG:
23738c4f9701SJanice Chang 	case EZFS_BADRESTORE:
23748c4f9701SJanice Chang 
23758c4f9701SJanice Chang 		/* use existing error text */
23768c4f9701SJanice Chang 
23778c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
23788c4f9701SJanice Chang 		    "%s: %s: %s\n",
23798c4f9701SJanice Chang 		    ndmpd_zfs_args->nz_dataset,
23808c4f9701SJanice Chang 		    libzfs_error_action(ndmpd_zfs_args->nz_zlibh),
23818c4f9701SJanice Chang 		    libzfs_error_description(ndmpd_zfs_args->nz_zlibh));
23828c4f9701SJanice Chang 
23838c4f9701SJanice Chang 		break;
23848c4f9701SJanice Chang 
23858c4f9701SJanice Chang 	case EZFS_NOMEM:
23868c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
23878c4f9701SJanice Chang 		    "Unable to obtain memory for operation\n");
23888c4f9701SJanice Chang 		break;
23898c4f9701SJanice Chang 
23908c4f9701SJanice Chang 	case EZFS_PROPSPACE:
23918c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
23928c4f9701SJanice Chang 		    "A bad ZFS quota or reservation was encountered.\n");
23938c4f9701SJanice Chang 		break;
23948c4f9701SJanice Chang 
23958c4f9701SJanice Chang 	case EZFS_BADSTREAM:
23968c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
23978c4f9701SJanice Chang 		    "The backup stream is invalid.\n");
23988c4f9701SJanice Chang 		break;
23998c4f9701SJanice Chang 
24008c4f9701SJanice Chang 	case EZFS_ZONED:
24018c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
24028c4f9701SJanice Chang 		    "An error related to the local zone occurred.\n");
24038c4f9701SJanice Chang 		break;
24048c4f9701SJanice Chang 
24058c4f9701SJanice Chang 	case EZFS_NOSPC:
24068c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
24078c4f9701SJanice Chang 		    "No more space is available\n");
24088c4f9701SJanice Chang 		break;
24098c4f9701SJanice Chang 
24108c4f9701SJanice Chang 	case EZFS_IO:
24118c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
24128c4f9701SJanice Chang 		    "An I/O error occurred.\n");
24138c4f9701SJanice Chang 		break;
24148c4f9701SJanice Chang 
24158c4f9701SJanice Chang 	default:
24168c4f9701SJanice Chang 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
24178c4f9701SJanice Chang 		    "An internal ndmpd error occurred.  "
24188c4f9701SJanice Chang 		    "Please contact support\n");
24198c4f9701SJanice Chang 		break;
24208c4f9701SJanice Chang 	}
24218c4f9701SJanice Chang }
24228c4f9701SJanice Chang 
24238c4f9701SJanice Chang void
ndmpd_zfs_dma_log(ndmpd_zfs_args_t * ndmpd_zfs_args,ndmp_log_type log_type,char * format,...)24248c4f9701SJanice Chang ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type,
24258c4f9701SJanice Chang     char *format, ...)
24268c4f9701SJanice Chang {
24278c4f9701SJanice Chang 	static char buf[1024];
24288c4f9701SJanice Chang 	va_list ap;
24298c4f9701SJanice Chang 
24308c4f9701SJanice Chang 	va_start(ap, format);
24318c4f9701SJanice Chang 
24328c4f9701SJanice Chang 	/*LINTED variable format specifier */
24338c4f9701SJanice Chang 	(void) vsnprintf(buf, sizeof (buf), format, ap);
24348c4f9701SJanice Chang 	va_end(ap);
24358c4f9701SJanice Chang 
24368c4f9701SJanice Chang 	MOD_LOGV3(ndmpd_zfs_params, log_type, buf);
24378c4f9701SJanice Chang 
24388c4f9701SJanice Chang 	if ((log_type) == NDMP_LOG_ERROR) {
24398c4f9701SJanice Chang 		NDMP_LOG(LOG_ERR, buf);
24408c4f9701SJanice Chang 	} else {
2441d0194491SJanice Chang 		NDMP_LOG(LOG_NOTICE, buf);
24428c4f9701SJanice Chang 	}
24438c4f9701SJanice Chang }
2444