xref: /onnv-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c (revision 12296:7cf402a7f374)
112186SJanice.Chang@Sun.COM /*
212186SJanice.Chang@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
312186SJanice.Chang@Sun.COM  */
412186SJanice.Chang@Sun.COM 
512186SJanice.Chang@Sun.COM /*
612186SJanice.Chang@Sun.COM  * BSD 3 Clause License
712186SJanice.Chang@Sun.COM  *
812186SJanice.Chang@Sun.COM  * Copyright (c) 2007, The Storage Networking Industry Association.
912186SJanice.Chang@Sun.COM  *
1012186SJanice.Chang@Sun.COM  * Redistribution and use in source and binary forms, with or without
1112186SJanice.Chang@Sun.COM  * modification, are permitted provided that the following conditions
1212186SJanice.Chang@Sun.COM  * are met:
1312186SJanice.Chang@Sun.COM  * 	- Redistributions of source code must retain the above copyright
1412186SJanice.Chang@Sun.COM  *	  notice, this list of conditions and the following disclaimer.
1512186SJanice.Chang@Sun.COM  *
1612186SJanice.Chang@Sun.COM  * 	- Redistributions in binary form must reproduce the above copyright
1712186SJanice.Chang@Sun.COM  *	  notice, this list of conditions and the following disclaimer in
1812186SJanice.Chang@Sun.COM  *	  the documentation and/or other materials provided with the
1912186SJanice.Chang@Sun.COM  *	  distribution.
2012186SJanice.Chang@Sun.COM  *
2112186SJanice.Chang@Sun.COM  *	- Neither the name of The Storage Networking Industry Association (SNIA)
2212186SJanice.Chang@Sun.COM  *	  nor the names of its contributors may be used to endorse or promote
2312186SJanice.Chang@Sun.COM  *	  products derived from this software without specific prior written
2412186SJanice.Chang@Sun.COM  *	  permission.
2512186SJanice.Chang@Sun.COM  *
2612186SJanice.Chang@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2712186SJanice.Chang@Sun.COM  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2812186SJanice.Chang@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2912186SJanice.Chang@Sun.COM  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
3012186SJanice.Chang@Sun.COM  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3112186SJanice.Chang@Sun.COM  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3212186SJanice.Chang@Sun.COM  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3312186SJanice.Chang@Sun.COM  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3412186SJanice.Chang@Sun.COM  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3512186SJanice.Chang@Sun.COM  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3612186SJanice.Chang@Sun.COM  * POSSIBILITY OF SUCH DAMAGE.
3712186SJanice.Chang@Sun.COM  */
3812186SJanice.Chang@Sun.COM /* Copyright (c) 2007, The Storage Networking Industry Association. */
3912186SJanice.Chang@Sun.COM /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
4012186SJanice.Chang@Sun.COM 
4112186SJanice.Chang@Sun.COM #include <sys/types.h>
4212186SJanice.Chang@Sun.COM #include <sys/param.h>
4312186SJanice.Chang@Sun.COM #include <sys/lwp.h>
4412186SJanice.Chang@Sun.COM #include <sys/fs/zfs.h>
4512186SJanice.Chang@Sun.COM #include <sys/mtio.h>
4612186SJanice.Chang@Sun.COM #include <sys/time.h>
4712186SJanice.Chang@Sun.COM #include <unistd.h>
4812186SJanice.Chang@Sun.COM #include <errno.h>
4912186SJanice.Chang@Sun.COM #include <stdlib.h>
5012186SJanice.Chang@Sun.COM #include <string.h>
5112186SJanice.Chang@Sun.COM #include <ctype.h>
5212186SJanice.Chang@Sun.COM #include <libzfs.h>
5312186SJanice.Chang@Sun.COM #include <stdio.h>
5412186SJanice.Chang@Sun.COM #include "ndmpd_common.h"
5512186SJanice.Chang@Sun.COM #include "ndmpd.h"
5612186SJanice.Chang@Sun.COM 
5712186SJanice.Chang@Sun.COM typedef struct {
5812186SJanice.Chang@Sun.COM 	char nzs_findprop[ZFS_MAXPROPLEN]; /* prop substring to find */
5912186SJanice.Chang@Sun.COM 	char nzs_snapname[ZFS_MAXNAMELEN]; /* snap's name */
6012186SJanice.Chang@Sun.COM 	char nzs_snapprop[ZFS_MAXPROPLEN]; /* snap's prop value */
6112186SJanice.Chang@Sun.COM 	char nzs_snapskip[ZFS_MAXPROPLEN]; /* snap to skip */
6212186SJanice.Chang@Sun.COM 	uint32_t nzs_prop_major;	   /* property major version */
6312186SJanice.Chang@Sun.COM 	uint32_t nzs_prop_minor;	   /* property minor version */
6412186SJanice.Chang@Sun.COM } ndmpd_zfs_snapfind_t;
6512186SJanice.Chang@Sun.COM 
6612186SJanice.Chang@Sun.COM mutex_t ndmpd_zfs_fd_lock;
6712186SJanice.Chang@Sun.COM 
6812186SJanice.Chang@Sun.COM static int ndmpd_zfs_open_fds(ndmpd_zfs_args_t *);
6912186SJanice.Chang@Sun.COM static void ndmpd_zfs_close_fds(ndmpd_zfs_args_t *);
7012186SJanice.Chang@Sun.COM 
7112186SJanice.Chang@Sun.COM static void ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *, int);
7212186SJanice.Chang@Sun.COM 
7312186SJanice.Chang@Sun.COM static int ndmpd_zfs_header_write(ndmpd_session_t *);
7412186SJanice.Chang@Sun.COM static int ndmpd_zfs_header_read(ndmpd_zfs_args_t *);
7512186SJanice.Chang@Sun.COM 
7612186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *);
7712186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *);
7812186SJanice.Chang@Sun.COM 
7912186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore(ndmpd_zfs_args_t *);
8012186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *);
8112186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *);
8212186SJanice.Chang@Sun.COM 
8312186SJanice.Chang@Sun.COM static int ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *, int **, int **);
8412186SJanice.Chang@Sun.COM 
8512186SJanice.Chang@Sun.COM static int ndmpd_zfs_is_spanning(ndmpd_zfs_args_t *);
8612186SJanice.Chang@Sun.COM 
8712186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *);
8812186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *, char *, int);
8912186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *);
9012186SJanice.Chang@Sun.COM 
9112186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *);
9212186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *);
9312186SJanice.Chang@Sun.COM static int ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *);
9412186SJanice.Chang@Sun.COM 
9512186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv(ndmpd_zfs_args_t *);
9612186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *);
9712186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *);
9812186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *);
9912186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *);
10012186SJanice.Chang@Sun.COM static int ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *);
10112186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *, char *);
10212186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *);
10312186SJanice.Chang@Sun.COM 
10412186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *);
10512186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *, int);
10612186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *);
10712186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *,
10812186SJanice.Chang@Sun.COM     boolean_t, ndmpd_zfs_snapfind_t *);
10912186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_snapshot_ndmpd_generated(char *);
11012186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *, ndmpd_zfs_snapfind_t *);
11112186SJanice.Chang@Sun.COM 
11212186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_find(zfs_handle_t *, void *);
11312186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_get(zfs_handle_t *, char *);
11412186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *);
11512186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *, char *,
11612186SJanice.Chang@Sun.COM     boolean_t *);
11712186SJanice.Chang@Sun.COM static int ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *, char *, int,
11812186SJanice.Chang@Sun.COM     boolean_t);
11912186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *,
12012186SJanice.Chang@Sun.COM     ndmpd_zfs_snapfind_t *);
12112186SJanice.Chang@Sun.COM static boolean_t ndmpd_zfs_prop_version_check(char *, uint32_t *, uint32_t *);
12212186SJanice.Chang@Sun.COM 
12312186SJanice.Chang@Sun.COM static int ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *, char *, int);
12412186SJanice.Chang@Sun.COM 
12512186SJanice.Chang@Sun.COM static void ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *);
12612186SJanice.Chang@Sun.COM 
12712186SJanice.Chang@Sun.COM static int ndmpd_zfs_backup(ndmpd_zfs_args_t *);
12812186SJanice.Chang@Sun.COM 
12912186SJanice.Chang@Sun.COM #define	snapshot_create chkpnt_backup_prepare
13012186SJanice.Chang@Sun.COM #define	snapshot_destroy chkpnt_backup_successful
13112186SJanice.Chang@Sun.COM 
13212186SJanice.Chang@Sun.COM /*
13312186SJanice.Chang@Sun.COM  * Syntax for com.sun.ndmp:incr property value:
13412186SJanice.Chang@Sun.COM  *	#.#.n|u/$LEVEL.$DMP_NAME.$ZFS_MODE(/ ...)
13512186SJanice.Chang@Sun.COM  *
13612186SJanice.Chang@Sun.COM  * where
13712186SJanice.Chang@Sun.COM  *	#.# is the version number
13812186SJanice.Chang@Sun.COM  *	'n' means ndmp-generated; 'u' means user-supplied
13912186SJanice.Chang@Sun.COM  *	$LEVEL: backup (incremental) level [0-9]
14012186SJanice.Chang@Sun.COM  *	$DMP_NAME: set name [default: "level"]
14112186SJanice.Chang@Sun.COM  *	$ZFS_MODE: d | r | p [for dataset, recursive, or package]
14212186SJanice.Chang@Sun.COM  *
14312186SJanice.Chang@Sun.COM  * Examples:
14412186SJanice.Chang@Sun.COM  *
14512186SJanice.Chang@Sun.COM  * 	0.0.n/0.bob.p
14612186SJanice.Chang@Sun.COM  * 	0.0.u/1.bob.p/0.jane.d
14712186SJanice.Chang@Sun.COM  */
14812186SJanice.Chang@Sun.COM 
14912186SJanice.Chang@Sun.COM #define	NDMPD_ZFS_PROP_INCR "com.sun.ndmp:incr"
15012186SJanice.Chang@Sun.COM 
15112186SJanice.Chang@Sun.COM /*
15212186SJanice.Chang@Sun.COM  * NDMPD_ZFS_LOG_ZERR
15312186SJanice.Chang@Sun.COM  *
15412186SJanice.Chang@Sun.COM  * As coded, there should be no races in the retrieval of the ZFS errno
15512186SJanice.Chang@Sun.COM  * from the ndmpd_zfs_args->nz_zlibh.  I.e., for a given ndmpd_zfs backup
15612186SJanice.Chang@Sun.COM  * or restore, there should only ever be one ZFS library call taking place
15712186SJanice.Chang@Sun.COM  * at any one moment in time.
15812186SJanice.Chang@Sun.COM  */
15912186SJanice.Chang@Sun.COM 
16012186SJanice.Chang@Sun.COM #define	NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, ...) {			\
16112186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_ERR, __VA_ARGS__);					\
16212186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_ERR, "%s--%s",					\
16312186SJanice.Chang@Sun.COM 	    libzfs_error_action((ndmpd_zfs_args)->nz_zlibh),           	\
16412186SJanice.Chang@Sun.COM 	    libzfs_error_description((ndmpd_zfs_args)->nz_zlibh));     	\
16512186SJanice.Chang@Sun.COM 	ndmpd_zfs_zerr_dma_log((ndmpd_zfs_args));			\
16612186SJanice.Chang@Sun.COM }
16712186SJanice.Chang@Sun.COM 
16812186SJanice.Chang@Sun.COM int
16912186SJanice.Chang@Sun.COM ndmpd_zfs_init(ndmpd_session_t *session)
17012186SJanice.Chang@Sun.COM {
17112186SJanice.Chang@Sun.COM 	ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
17212186SJanice.Chang@Sun.COM 	int version = session->ns_protocol_version;
17312186SJanice.Chang@Sun.COM 
17412186SJanice.Chang@Sun.COM 	bzero(ndmpd_zfs_args, sizeof (*ndmpd_zfs_args));
17512186SJanice.Chang@Sun.COM 
17612186SJanice.Chang@Sun.COM 	if ((version < NDMPV3) || (version > NDMPV4)) {
17712186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "Unknown or unsupported version %d", version);
17812186SJanice.Chang@Sun.COM 		return (-1);
17912186SJanice.Chang@Sun.COM 	}
18012186SJanice.Chang@Sun.COM 
18112186SJanice.Chang@Sun.COM 	if ((ndmpd_zfs_args->nz_zlibh = libzfs_init()) == NULL) {
18212186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "libzfs init error [%d]", errno);
18312186SJanice.Chang@Sun.COM 		return (-1);
18412186SJanice.Chang@Sun.COM 	}
18512186SJanice.Chang@Sun.COM 
18612186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_open_fds(ndmpd_zfs_args) < 0) {
18712186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "open_fds() failure(): %d\n", errno);
18812186SJanice.Chang@Sun.COM 		return (-1);
18912186SJanice.Chang@Sun.COM 	}
19012186SJanice.Chang@Sun.COM 
19112186SJanice.Chang@Sun.COM 	ndmpd_zfs_args->nz_bufsize = ndmp_buffer_get_size(session);
19212186SJanice.Chang@Sun.COM 	ndmpd_zfs_args->nz_window_len = session->ns_mover.md_window_length;
19312186SJanice.Chang@Sun.COM 
19412186SJanice.Chang@Sun.COM 	ndmpd_zfs_args->nz_nlp = ndmp_get_nlp(session);
19512186SJanice.Chang@Sun.COM 
19612186SJanice.Chang@Sun.COM 	assert(ndmpd_zfs_args->nz_nlp != NULL);
19712186SJanice.Chang@Sun.COM 
19812186SJanice.Chang@Sun.COM 	ndmpd_zfs_args->nz_nlp->nlp_bytes_total = 0;
19912186SJanice.Chang@Sun.COM 
20012186SJanice.Chang@Sun.COM 	session->ns_data.dd_module.dm_module_cookie = ndmpd_zfs_args;
20112186SJanice.Chang@Sun.COM 	session->ns_data.dd_data_size = 0;
20212186SJanice.Chang@Sun.COM 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
20312186SJanice.Chang@Sun.COM 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining  = 0;
20412186SJanice.Chang@Sun.COM 
20512186SJanice.Chang@Sun.COM 	session->ns_data.dd_bytes_left_to_read = 0;
20612186SJanice.Chang@Sun.COM 	session->ns_data.dd_position = 0;
20712186SJanice.Chang@Sun.COM 	session->ns_data.dd_discard_length = 0;
20812186SJanice.Chang@Sun.COM 	session->ns_data.dd_read_offset = 0;
20912186SJanice.Chang@Sun.COM 	session->ns_data.dd_read_length = 0;
21012186SJanice.Chang@Sun.COM 
21112186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_get_env_func = ndmpd_api_get_env;
21212186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_add_env_func = ndmpd_api_add_env;
21312186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_set_env_func = ndmpd_api_set_env;
21412186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_dispatch_func = ndmpd_api_dispatch;
21512186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_daemon_cookie = (void *)session;
21612186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_protocol_version = session->ns_protocol_version;
21712186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_stats = &session->ns_data.dd_module.dm_stats;
21812186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_add_file_handler_func =
21912186SJanice.Chang@Sun.COM 	    ndmpd_api_add_file_handler;
22012186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_remove_file_handler_func =
22112186SJanice.Chang@Sun.COM 	    ndmpd_api_remove_file_handler;
22212186SJanice.Chang@Sun.COM 	ndmpd_zfs_params->mp_seek_func = 0;
22312186SJanice.Chang@Sun.COM 
22412186SJanice.Chang@Sun.COM 	switch (version) {
22512186SJanice.Chang@Sun.COM 	case NDMPV3:
22612186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
22712186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
22812186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
22912186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
23012186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v3;
23112186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_file_recovered_func =
23212186SJanice.Chang@Sun.COM 		    ndmpd_api_file_recovered_v3;
23312186SJanice.Chang@Sun.COM 		break;
23412186SJanice.Chang@Sun.COM 	case NDMPV4:
23512186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
23612186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
23712186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
23812186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
23912186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v4;
24012186SJanice.Chang@Sun.COM 		ndmpd_zfs_params->mp_file_recovered_func =
24112186SJanice.Chang@Sun.COM 		    ndmpd_api_file_recovered_v4;
24212186SJanice.Chang@Sun.COM 		break;
24312186SJanice.Chang@Sun.COM 	default:
24412186SJanice.Chang@Sun.COM 		/* error already returned above for this case */
24512186SJanice.Chang@Sun.COM 		break;
24612186SJanice.Chang@Sun.COM 	}
24712186SJanice.Chang@Sun.COM 
24812186SJanice.Chang@Sun.COM 	return (0);
24912186SJanice.Chang@Sun.COM }
25012186SJanice.Chang@Sun.COM 
25112186SJanice.Chang@Sun.COM void
25212186SJanice.Chang@Sun.COM ndmpd_zfs_fini(ndmpd_zfs_args_t *ndmpd_zfs_args)
25312186SJanice.Chang@Sun.COM {
25412186SJanice.Chang@Sun.COM 	libzfs_fini(ndmpd_zfs_args->nz_zlibh);
25512186SJanice.Chang@Sun.COM 
25612186SJanice.Chang@Sun.COM 	ndmpd_zfs_close_fds(ndmpd_zfs_args);
25712186SJanice.Chang@Sun.COM }
25812186SJanice.Chang@Sun.COM 
25912186SJanice.Chang@Sun.COM static int
26012186SJanice.Chang@Sun.COM ndmpd_zfs_open_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
26112186SJanice.Chang@Sun.COM {
26212186SJanice.Chang@Sun.COM 	int err;
26312186SJanice.Chang@Sun.COM 
26412186SJanice.Chang@Sun.COM 	err = pipe(ndmpd_zfs_args->nz_pipe_fd);
26512186SJanice.Chang@Sun.COM 	if (err)
26612186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n", strerror(errno));
26712186SJanice.Chang@Sun.COM 
26812186SJanice.Chang@Sun.COM 	return (err);
26912186SJanice.Chang@Sun.COM }
27012186SJanice.Chang@Sun.COM 
27112186SJanice.Chang@Sun.COM /*
27212186SJanice.Chang@Sun.COM  * ndmpd_zfs_close_fds()
27312186SJanice.Chang@Sun.COM  *
27412186SJanice.Chang@Sun.COM  * In the abort case, use dup2() to redirect the end of the pipe that is
27512186SJanice.Chang@Sun.COM  * being written to (to a new pipe).  Close the ends of the new pipe to cause
27612186SJanice.Chang@Sun.COM  * EPIPE to be returned to the writing thread.  This will cause the writer
27712186SJanice.Chang@Sun.COM  * and reader to terminate without having any of the writer's data erroneously
27812186SJanice.Chang@Sun.COM  * go to any reopened descriptor.
27912186SJanice.Chang@Sun.COM  */
28012186SJanice.Chang@Sun.COM 
28112186SJanice.Chang@Sun.COM static void
28212186SJanice.Chang@Sun.COM ndmpd_zfs_close_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
28312186SJanice.Chang@Sun.COM {
28412186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
28512186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
28612186SJanice.Chang@Sun.COM 	int pipe_end;
28712186SJanice.Chang@Sun.COM 	int fds[2];
28812186SJanice.Chang@Sun.COM 
28912186SJanice.Chang@Sun.COM 	if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE) {
29012186SJanice.Chang@Sun.COM 		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
29112186SJanice.Chang@Sun.COM 		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
29212186SJanice.Chang@Sun.COM 		return;
29312186SJanice.Chang@Sun.COM 	}
29412186SJanice.Chang@Sun.COM 
29512186SJanice.Chang@Sun.COM 	(void) mutex_lock(&ndmpd_zfs_fd_lock);
29612186SJanice.Chang@Sun.COM 
29712186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) {
29812186SJanice.Chang@Sun.COM 		pipe_end = PIPE_ZFS;
29912186SJanice.Chang@Sun.COM 	} else {
30012186SJanice.Chang@Sun.COM 		pipe_end = PIPE_TAPE;
30112186SJanice.Chang@Sun.COM 	}
30212186SJanice.Chang@Sun.COM 
30312186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_args->nz_pipe_fd[pipe_end] != -1) {
30412186SJanice.Chang@Sun.COM 		if (pipe(fds) != 0) {
30512186SJanice.Chang@Sun.COM 			(void) mutex_unlock(&ndmpd_zfs_fd_lock);
30612186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n",
30712186SJanice.Chang@Sun.COM 			    strerror(errno));
30812186SJanice.Chang@Sun.COM 			return;
30912186SJanice.Chang@Sun.COM 		}
31012186SJanice.Chang@Sun.COM 
31112186SJanice.Chang@Sun.COM 		(void) dup2(fds[0], ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
31212186SJanice.Chang@Sun.COM 		(void) close(fds[0]);
31312186SJanice.Chang@Sun.COM 		(void) close(fds[1]);
31412186SJanice.Chang@Sun.COM 
31512186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
31612186SJanice.Chang@Sun.COM 	}
31712186SJanice.Chang@Sun.COM 
31812186SJanice.Chang@Sun.COM 	(void) mutex_unlock(&ndmpd_zfs_fd_lock);
31912186SJanice.Chang@Sun.COM }
32012186SJanice.Chang@Sun.COM 
32112186SJanice.Chang@Sun.COM static void
32212186SJanice.Chang@Sun.COM ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *ndmpd_zfs_args, int pipe_end)
32312186SJanice.Chang@Sun.COM {
32412186SJanice.Chang@Sun.COM 	(void) mutex_lock(&ndmpd_zfs_fd_lock);
32512186SJanice.Chang@Sun.COM 	(void) close(ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
32612186SJanice.Chang@Sun.COM 	ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
32712186SJanice.Chang@Sun.COM 	(void) mutex_unlock(&ndmpd_zfs_fd_lock);
32812186SJanice.Chang@Sun.COM }
32912186SJanice.Chang@Sun.COM 
33012186SJanice.Chang@Sun.COM static int
33112186SJanice.Chang@Sun.COM ndmpd_zfs_header_write(ndmpd_session_t *session)
33212186SJanice.Chang@Sun.COM {
33312186SJanice.Chang@Sun.COM 	ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
33412186SJanice.Chang@Sun.COM 	int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
33512186SJanice.Chang@Sun.COM 	ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
33612186SJanice.Chang@Sun.COM 	char *buf;
33712186SJanice.Chang@Sun.COM 
33812186SJanice.Chang@Sun.COM 	buf = ndmp_malloc(bufsize);
33912186SJanice.Chang@Sun.COM 	if (buf == NULL) {
34012186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "buf NULL");
34112186SJanice.Chang@Sun.COM 		return (-1);
34212186SJanice.Chang@Sun.COM 	}
34312186SJanice.Chang@Sun.COM 
34412186SJanice.Chang@Sun.COM 	(void) strlcpy(tape_header->nzh_magic, NDMPUTF8MAGIC,
34512186SJanice.Chang@Sun.COM 	    sizeof (NDMPUTF8MAGIC));
34612186SJanice.Chang@Sun.COM 	tape_header->nzh_major = LE_32(NDMPD_ZFS_MAJOR_VERSION);
34712186SJanice.Chang@Sun.COM 	tape_header->nzh_minor = LE_32(NDMPD_ZFS_MINOR_VERSION);
34812186SJanice.Chang@Sun.COM 	tape_header->nzh_hdrlen = LE_32(bufsize);
34912186SJanice.Chang@Sun.COM 
35012186SJanice.Chang@Sun.COM 	bzero(buf, bufsize);
35112186SJanice.Chang@Sun.COM 	(void) memcpy(buf, tape_header, sizeof (ndmpd_zfs_header_t));
35212186SJanice.Chang@Sun.COM 
35312186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "header (major, minor, length): %u %u %u",
35412186SJanice.Chang@Sun.COM 	    NDMPD_ZFS_MAJOR_VERSION,
35512186SJanice.Chang@Sun.COM 	    NDMPD_ZFS_MINOR_VERSION,
35612186SJanice.Chang@Sun.COM 	    bufsize);
35712186SJanice.Chang@Sun.COM 
35812186SJanice.Chang@Sun.COM 	if (MOD_WRITE(ndmpd_zfs_params, buf, bufsize) != 0) {
35912186SJanice.Chang@Sun.COM 		free(buf);
36012186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "MOD_WRITE error");
36112186SJanice.Chang@Sun.COM 		return (-1);
36212186SJanice.Chang@Sun.COM 	}
36312186SJanice.Chang@Sun.COM 
36412186SJanice.Chang@Sun.COM 	free(buf);
36512186SJanice.Chang@Sun.COM 
36612186SJanice.Chang@Sun.COM 	session->ns_data.dd_module.dm_stats.ms_bytes_processed = bufsize;
36712186SJanice.Chang@Sun.COM 
36812186SJanice.Chang@Sun.COM 	return (0);
36912186SJanice.Chang@Sun.COM }
37012186SJanice.Chang@Sun.COM 
37112186SJanice.Chang@Sun.COM static int
37212186SJanice.Chang@Sun.COM ndmpd_zfs_header_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
37312186SJanice.Chang@Sun.COM {
37412186SJanice.Chang@Sun.COM 	int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
37512186SJanice.Chang@Sun.COM 	ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
37612186SJanice.Chang@Sun.COM 	uint32_t hdrlen;
37712186SJanice.Chang@Sun.COM 	int32_t header_left;
37812186SJanice.Chang@Sun.COM 	int err;
37912186SJanice.Chang@Sun.COM 	char *buf;
38012186SJanice.Chang@Sun.COM 
38112186SJanice.Chang@Sun.COM 	buf = ndmp_malloc(bufsize);
38212186SJanice.Chang@Sun.COM 	if (buf == NULL) {
38312186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "buf NULL");
38412186SJanice.Chang@Sun.COM 		return (-1);
38512186SJanice.Chang@Sun.COM 	}
38612186SJanice.Chang@Sun.COM 
38712186SJanice.Chang@Sun.COM 	bzero(buf, bufsize);
38812186SJanice.Chang@Sun.COM 
38912186SJanice.Chang@Sun.COM 	/*
39012186SJanice.Chang@Sun.COM 	 * Read nz_bufsize worth of bytes first (the size of a mover record).
39112186SJanice.Chang@Sun.COM 	 */
39212186SJanice.Chang@Sun.COM 
39312186SJanice.Chang@Sun.COM 	err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
39412186SJanice.Chang@Sun.COM 
39512186SJanice.Chang@Sun.COM 	if (err != 0) {
39612186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "MOD_READ error: %d", err);
39712186SJanice.Chang@Sun.COM 		free(buf);
39812186SJanice.Chang@Sun.COM 		return (-1);
39912186SJanice.Chang@Sun.COM 	}
40012186SJanice.Chang@Sun.COM 
40112186SJanice.Chang@Sun.COM 	(void) memcpy(tape_header, buf, sizeof (ndmpd_zfs_header_t));
40212186SJanice.Chang@Sun.COM 
40312186SJanice.Chang@Sun.COM 
40412186SJanice.Chang@Sun.COM 	if (strcmp(tape_header->nzh_magic, NDMPUTF8MAGIC) != 0) {
40512186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
40612186SJanice.Chang@Sun.COM 		    "bad magic string\n");
40712186SJanice.Chang@Sun.COM 		goto _err;
40812186SJanice.Chang@Sun.COM 	}
40912186SJanice.Chang@Sun.COM 
41012186SJanice.Chang@Sun.COM 	if (tape_header->nzh_major > LE_32(NDMPD_ZFS_MAJOR_VERSION)) {
41112186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
41212186SJanice.Chang@Sun.COM 		    "major number larger than supported: (%d %d)\n",
41312186SJanice.Chang@Sun.COM 		    LE_32(tape_header->nzh_major), NDMPD_ZFS_MAJOR_VERSION);
41412186SJanice.Chang@Sun.COM 		goto _err;
41512186SJanice.Chang@Sun.COM 	}
41612186SJanice.Chang@Sun.COM 
41712186SJanice.Chang@Sun.COM 	/*
41812186SJanice.Chang@Sun.COM 	 * Major version 0 (regardless of minor version):
41912186SJanice.Chang@Sun.COM 	 * Header must be a multiple of the mover record size.
42012186SJanice.Chang@Sun.COM 	 */
42112186SJanice.Chang@Sun.COM 
42212186SJanice.Chang@Sun.COM 	hdrlen = LE_32(tape_header->nzh_hdrlen);
42312186SJanice.Chang@Sun.COM 	if (hdrlen > bufsize) {
42412186SJanice.Chang@Sun.COM 		header_left = hdrlen - bufsize;
42512186SJanice.Chang@Sun.COM 		while (header_left > 0) {
42612186SJanice.Chang@Sun.COM 			err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
42712186SJanice.Chang@Sun.COM 			if (err == -1) {
42812186SJanice.Chang@Sun.COM 				ndmpd_zfs_dma_log(ndmpd_zfs_args,
42912186SJanice.Chang@Sun.COM 				    NDMP_LOG_ERROR, "bad header\n");
43012186SJanice.Chang@Sun.COM 				goto _err;
43112186SJanice.Chang@Sun.COM 			}
43212186SJanice.Chang@Sun.COM 			header_left -= bufsize;
43312186SJanice.Chang@Sun.COM 		}
43412186SJanice.Chang@Sun.COM 	}
43512186SJanice.Chang@Sun.COM 
43612186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "tape header: %s; %u %u; %u ",
43712186SJanice.Chang@Sun.COM 	    tape_header->nzh_magic,
43812186SJanice.Chang@Sun.COM 	    LE_32(tape_header->nzh_major),
43912186SJanice.Chang@Sun.COM 	    LE_32(tape_header->nzh_minor),
44012186SJanice.Chang@Sun.COM 	    LE_32(tape_header->nzh_hdrlen));
44112186SJanice.Chang@Sun.COM 
44212186SJanice.Chang@Sun.COM 	ndmpd_zfs_args->nz_nlp->nlp_bytes_total = hdrlen;
44312186SJanice.Chang@Sun.COM 
44412186SJanice.Chang@Sun.COM 	free(buf);
44512186SJanice.Chang@Sun.COM 	return (0);
44612186SJanice.Chang@Sun.COM 
44712186SJanice.Chang@Sun.COM _err:
44812186SJanice.Chang@Sun.COM 
44912186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_ERR, "tape header: %s; %u %u; %u ",
45012186SJanice.Chang@Sun.COM 	    tape_header->nzh_magic,
45112186SJanice.Chang@Sun.COM 	    LE_32(tape_header->nzh_major),
45212186SJanice.Chang@Sun.COM 	    LE_32(tape_header->nzh_minor),
45312186SJanice.Chang@Sun.COM 	    LE_32(tape_header->nzh_hdrlen));
45412186SJanice.Chang@Sun.COM 
45512186SJanice.Chang@Sun.COM 	free(buf);
45612186SJanice.Chang@Sun.COM 	return (-1);
45712186SJanice.Chang@Sun.COM }
45812186SJanice.Chang@Sun.COM 
45912186SJanice.Chang@Sun.COM int
46012186SJanice.Chang@Sun.COM ndmpd_zfs_backup_starter(void *arg)
46112186SJanice.Chang@Sun.COM {
46212186SJanice.Chang@Sun.COM 	ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
46312186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
46412186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
46512186SJanice.Chang@Sun.COM 	int cleanup_err = 0;
46612186SJanice.Chang@Sun.COM 	int err = 0;
46712186SJanice.Chang@Sun.COM 
46812186SJanice.Chang@Sun.COM 	ndmp_session_ref(session);
46912186SJanice.Chang@Sun.COM 
47012186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args) != 0) {
47112186SJanice.Chang@Sun.COM 		err = -1;
47212186SJanice.Chang@Sun.COM 		goto _done;
47312186SJanice.Chang@Sun.COM 	}
47412186SJanice.Chang@Sun.COM 
47512186SJanice.Chang@Sun.COM 	err = ndmpd_zfs_backup(ndmpd_zfs_args);
47612186SJanice.Chang@Sun.COM 
47712186SJanice.Chang@Sun.COM 	cleanup_err = ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args, err);
47812186SJanice.Chang@Sun.COM 
47912186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG,
48012186SJanice.Chang@Sun.COM 	    "data bytes_total(including header):%llu",
48112186SJanice.Chang@Sun.COM 	    session->ns_data.dd_module.dm_stats.ms_bytes_processed);
48212186SJanice.Chang@Sun.COM 
48312186SJanice.Chang@Sun.COM 	err |= cleanup_err;
48412186SJanice.Chang@Sun.COM 
48512186SJanice.Chang@Sun.COM _done:
48612186SJanice.Chang@Sun.COM 	NS_DEC(nbk);
48712186SJanice.Chang@Sun.COM 	MOD_DONE(ndmpd_zfs_params, err ? err : cleanup_err);
48812186SJanice.Chang@Sun.COM 	ndmp_session_unref(session);
48912186SJanice.Chang@Sun.COM 	ndmpd_zfs_fini(ndmpd_zfs_args);
49012186SJanice.Chang@Sun.COM 
49112186SJanice.Chang@Sun.COM 	return (err);
49212186SJanice.Chang@Sun.COM }
49312186SJanice.Chang@Sun.COM 
49412186SJanice.Chang@Sun.COM static int
49512186SJanice.Chang@Sun.COM ndmpd_zfs_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
49612186SJanice.Chang@Sun.COM {
49712186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
49812186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
49912186SJanice.Chang@Sun.COM 	int *read_err = NULL;
50012186SJanice.Chang@Sun.COM 	int *write_err = NULL;
50112186SJanice.Chang@Sun.COM 	int result = 0;
50212186SJanice.Chang@Sun.COM 	int err;
50312186SJanice.Chang@Sun.COM 
50412186SJanice.Chang@Sun.COM 	if (session->ns_eof)
50512186SJanice.Chang@Sun.COM 		return (-1);
50612186SJanice.Chang@Sun.COM 
50712186SJanice.Chang@Sun.COM 	if (!session->ns_data.dd_abort) {
50812186SJanice.Chang@Sun.COM 		if (ndmpd_zfs_header_write(session)) {
50912186SJanice.Chang@Sun.COM 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
51012186SJanice.Chang@Sun.COM 			    "ndmpd_zfs header write error\n");
51112186SJanice.Chang@Sun.COM 			return (-1);
51212186SJanice.Chang@Sun.COM 		}
51312186SJanice.Chang@Sun.COM 
51412186SJanice.Chang@Sun.COM 		err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
51512186SJanice.Chang@Sun.COM 		    &read_err, &write_err);
51612186SJanice.Chang@Sun.COM 
51712186SJanice.Chang@Sun.COM 		if (err || read_err || write_err || session->ns_eof)
51812186SJanice.Chang@Sun.COM 			result = EPIPE;
51912186SJanice.Chang@Sun.COM 	}
52012186SJanice.Chang@Sun.COM 
52112186SJanice.Chang@Sun.COM 	if (session->ns_data.dd_abort) {
52212186SJanice.Chang@Sun.COM 		ndmpd_audit_backup(session->ns_connection,
52312186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset,
52412186SJanice.Chang@Sun.COM 		    session->ns_data.dd_data_addr.addr_type,
52512186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset, EINTR);
52612186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
52712186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset);
52812186SJanice.Chang@Sun.COM 
52912186SJanice.Chang@Sun.COM 		(void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
53012186SJanice.Chang@Sun.COM 		err = -1;
53112186SJanice.Chang@Sun.COM 	} else {
53212186SJanice.Chang@Sun.COM 		ndmpd_audit_backup(session->ns_connection,
53312186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset,
53412186SJanice.Chang@Sun.COM 		    session->ns_data.dd_data_addr.addr_type,
53512186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset, result);
53612186SJanice.Chang@Sun.COM 
53712186SJanice.Chang@Sun.COM 		err = ndmpd_zfs_post_backup(ndmpd_zfs_args);
53812186SJanice.Chang@Sun.COM 		if (err || result)
53912186SJanice.Chang@Sun.COM 			err = -1;
54012186SJanice.Chang@Sun.COM 
54112186SJanice.Chang@Sun.COM 		if (err == 0)  {
54212186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished.",
54312186SJanice.Chang@Sun.COM 			    ndmpd_zfs_args->nz_dataset);
54412186SJanice.Chang@Sun.COM 		} else {
54512186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "An error occurred while backing up"
54612186SJanice.Chang@Sun.COM 			    " \"%s\"", ndmpd_zfs_args->nz_dataset);
54712186SJanice.Chang@Sun.COM 		}
54812186SJanice.Chang@Sun.COM 	}
54912186SJanice.Chang@Sun.COM 
55012186SJanice.Chang@Sun.COM 	return (err);
55112186SJanice.Chang@Sun.COM }
55212186SJanice.Chang@Sun.COM 
55312186SJanice.Chang@Sun.COM /*
55412186SJanice.Chang@Sun.COM  * ndmpd_zfs_backup_send_read()
55512186SJanice.Chang@Sun.COM  *
55612186SJanice.Chang@Sun.COM  * This routine executes zfs_send() to create the backup data stream.
55712186SJanice.Chang@Sun.COM  * The value of ZFS_MODE determines the type of zfs_send():
55812186SJanice.Chang@Sun.COM  * 	dataset ('d'): Only the dataset specified (i.e., top level) is backed up
55912186SJanice.Chang@Sun.COM  * 	recursive ('r'): The dataset and its child file systems are backed up
56012186SJanice.Chang@Sun.COM  * 	package ('p'): Same as 'r', except all intermediate snapshots are also
56112186SJanice.Chang@Sun.COM  *			backed up
56212186SJanice.Chang@Sun.COM  *
56312186SJanice.Chang@Sun.COM  * Volumes do not have descednants, so 'd' and 'r' produce equivalent results.
56412186SJanice.Chang@Sun.COM  */
56512186SJanice.Chang@Sun.COM 
56612186SJanice.Chang@Sun.COM static int
56712186SJanice.Chang@Sun.COM ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
56812186SJanice.Chang@Sun.COM {
56912186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
57012186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
57112186SJanice.Chang@Sun.COM 	sendflags_t flags = { 0 };
57212186SJanice.Chang@Sun.COM 	char *fromsnap = NULL;
57312186SJanice.Chang@Sun.COM 	zfs_handle_t *zhp;
57412186SJanice.Chang@Sun.COM 	int err;
57512186SJanice.Chang@Sun.COM 
57612186SJanice.Chang@Sun.COM 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
57712186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
57812186SJanice.Chang@Sun.COM 
57912186SJanice.Chang@Sun.COM 	if (!zhp) {
58012186SJanice.Chang@Sun.COM 		if (!session->ns_data.dd_abort)
58112186SJanice.Chang@Sun.COM 			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
58212186SJanice.Chang@Sun.COM 		return (-1);
58312186SJanice.Chang@Sun.COM 	}
58412186SJanice.Chang@Sun.COM 
58512186SJanice.Chang@Sun.COM 	switch (ndmpd_zfs_args->nz_zfs_mode) {
58612186SJanice.Chang@Sun.COM 	case ('d'):
58712186SJanice.Chang@Sun.COM 		flags.props = B_TRUE;
58812186SJanice.Chang@Sun.COM 		break;
58912186SJanice.Chang@Sun.COM 	case ('r'):
59012186SJanice.Chang@Sun.COM 		flags.replicate = B_TRUE;
59112186SJanice.Chang@Sun.COM 		break;
59212186SJanice.Chang@Sun.COM 	case ('p'):
59312186SJanice.Chang@Sun.COM 		flags.doall = B_TRUE;
59412186SJanice.Chang@Sun.COM 		flags.replicate = B_TRUE;
59512186SJanice.Chang@Sun.COM 		break;
59612186SJanice.Chang@Sun.COM 	default:
59712186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c",
59812186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_zfs_mode);
59912186SJanice.Chang@Sun.COM 		zfs_close(zhp);
60012186SJanice.Chang@Sun.COM 		return (-1);
60112186SJanice.Chang@Sun.COM 	}
60212186SJanice.Chang@Sun.COM 
60312186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
60412186SJanice.Chang@Sun.COM 		if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') {
60512186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_ERR, "no fromsnap");
60612186SJanice.Chang@Sun.COM 			zfs_close(zhp);
60712186SJanice.Chang@Sun.COM 			return (-1);
60812186SJanice.Chang@Sun.COM 		}
60912186SJanice.Chang@Sun.COM 		fromsnap = ndmpd_zfs_args->nz_fromsnap;
61012186SJanice.Chang@Sun.COM 	}
61112186SJanice.Chang@Sun.COM 
61212186SJanice.Chang@Sun.COM 	err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, flags,
613*12296SLin.Ling@Sun.COM 	    ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL);
61412186SJanice.Chang@Sun.COM 
61512186SJanice.Chang@Sun.COM 	if (err && !session->ns_data.dd_abort)
61612186SJanice.Chang@Sun.COM 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err);
61712186SJanice.Chang@Sun.COM 
61812186SJanice.Chang@Sun.COM 	zfs_close(zhp);
61912186SJanice.Chang@Sun.COM 
62012186SJanice.Chang@Sun.COM 	return (err);
62112186SJanice.Chang@Sun.COM }
62212186SJanice.Chang@Sun.COM 
62312186SJanice.Chang@Sun.COM /*
62412186SJanice.Chang@Sun.COM  * ndmpd_zfs_backup_tape_write()
62512186SJanice.Chang@Sun.COM  *
62612186SJanice.Chang@Sun.COM  * The data begins on a mover record boundary (because
62712186SJanice.Chang@Sun.COM  * the header is the size of a mover record--i.e.
62812186SJanice.Chang@Sun.COM  * ndmpd_zfs_args->nz_bufsize).
62912186SJanice.Chang@Sun.COM  */
63012186SJanice.Chang@Sun.COM 
63112186SJanice.Chang@Sun.COM static int
63212186SJanice.Chang@Sun.COM ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
63312186SJanice.Chang@Sun.COM {
63412186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
63512186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
63612186SJanice.Chang@Sun.COM 	int bufsize = ndmpd_zfs_args->nz_bufsize;
63712186SJanice.Chang@Sun.COM 	u_longlong_t *bytes_totalp;
63812186SJanice.Chang@Sun.COM 	int count;
63912186SJanice.Chang@Sun.COM 	char *buf;
64012186SJanice.Chang@Sun.COM 
64112186SJanice.Chang@Sun.COM 	buf = ndmp_malloc(bufsize);
64212186SJanice.Chang@Sun.COM 	if (buf == NULL) {
64312186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "buf NULL");
64412186SJanice.Chang@Sun.COM 		return (-1);
64512186SJanice.Chang@Sun.COM 	}
64612186SJanice.Chang@Sun.COM 
64712186SJanice.Chang@Sun.COM 	bytes_totalp =
64812186SJanice.Chang@Sun.COM 	    &(session->ns_data.dd_module.dm_stats.ms_bytes_processed);
64912186SJanice.Chang@Sun.COM 
65012186SJanice.Chang@Sun.COM 	for (;;) {
65112186SJanice.Chang@Sun.COM 		bzero(buf, bufsize);
65212186SJanice.Chang@Sun.COM 
65312186SJanice.Chang@Sun.COM 		count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
65412186SJanice.Chang@Sun.COM 		    bufsize);
65512186SJanice.Chang@Sun.COM 
65612186SJanice.Chang@Sun.COM 		if (count == 0) /* EOF */ {
65712186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG,
65812186SJanice.Chang@Sun.COM 			    "zfs_send stream size: %llu bytes (sans header)",
65912186SJanice.Chang@Sun.COM 			    *bytes_totalp - bufsize);
66012186SJanice.Chang@Sun.COM 			free(buf);
66112186SJanice.Chang@Sun.COM 			return (0);
66212186SJanice.Chang@Sun.COM 		}
66312186SJanice.Chang@Sun.COM 
66412186SJanice.Chang@Sun.COM 		if (count == -1) {
66512186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)",
66612186SJanice.Chang@Sun.COM 			    errno);
66712186SJanice.Chang@Sun.COM 			free(buf);
66812186SJanice.Chang@Sun.COM 			return (-1);
66912186SJanice.Chang@Sun.COM 		}
67012186SJanice.Chang@Sun.COM 
67112186SJanice.Chang@Sun.COM 		if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) {
67212186SJanice.Chang@Sun.COM 			(void) ndmpd_zfs_abort((void *) ndmpd_zfs_args);
67312186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_ERR, "MOD_WRITE error");
67412186SJanice.Chang@Sun.COM 			free(buf);
67512186SJanice.Chang@Sun.COM 			return (-1);
67612186SJanice.Chang@Sun.COM 		}
67712186SJanice.Chang@Sun.COM 
67812186SJanice.Chang@Sun.COM 		*bytes_totalp += count;
67912186SJanice.Chang@Sun.COM 	}
68012186SJanice.Chang@Sun.COM 	/* NOTREACHED */
68112186SJanice.Chang@Sun.COM }
68212186SJanice.Chang@Sun.COM 
68312186SJanice.Chang@Sun.COM int
68412186SJanice.Chang@Sun.COM ndmpd_zfs_restore_starter(void *arg)
68512186SJanice.Chang@Sun.COM {
68612186SJanice.Chang@Sun.COM 	ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
68712186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
68812186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
68912186SJanice.Chang@Sun.COM 	int err;
69012186SJanice.Chang@Sun.COM 
69112186SJanice.Chang@Sun.COM 	ndmp_session_ref(session);
69212186SJanice.Chang@Sun.COM 
69312186SJanice.Chang@Sun.COM 	err = ndmpd_zfs_restore(ndmpd_zfs_args);
69412186SJanice.Chang@Sun.COM 
69512186SJanice.Chang@Sun.COM 	MOD_DONE(ndmpd_zfs_params, err);
69612186SJanice.Chang@Sun.COM 
69712186SJanice.Chang@Sun.COM 	NS_DEC(nrs);
69812186SJanice.Chang@Sun.COM 
69912186SJanice.Chang@Sun.COM 	ndmp_session_unref(session);
70012186SJanice.Chang@Sun.COM 
70112186SJanice.Chang@Sun.COM 	ndmpd_zfs_fini(ndmpd_zfs_args);
70212186SJanice.Chang@Sun.COM 
70312186SJanice.Chang@Sun.COM 	return (err);
70412186SJanice.Chang@Sun.COM }
70512186SJanice.Chang@Sun.COM 
70612186SJanice.Chang@Sun.COM static int
70712186SJanice.Chang@Sun.COM ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
70812186SJanice.Chang@Sun.COM {
70912186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
71012186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
71112186SJanice.Chang@Sun.COM 	int *read_err = NULL;
71212186SJanice.Chang@Sun.COM 	int *write_err = NULL;
71312186SJanice.Chang@Sun.COM 	int result = 0;
71412186SJanice.Chang@Sun.COM 	int err;
71512186SJanice.Chang@Sun.COM 
71612186SJanice.Chang@Sun.COM 	if (!session->ns_data.dd_abort) {
71712186SJanice.Chang@Sun.COM 		if (ndmpd_zfs_header_read(ndmpd_zfs_args)) {
71812186SJanice.Chang@Sun.COM 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
71912186SJanice.Chang@Sun.COM 			    "ndmpd_zfs header read error\n");
72012186SJanice.Chang@Sun.COM 			return (-1);
72112186SJanice.Chang@Sun.COM 		}
72212186SJanice.Chang@Sun.COM 
72312186SJanice.Chang@Sun.COM 		err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
72412186SJanice.Chang@Sun.COM 		    &write_err, &read_err);
72512186SJanice.Chang@Sun.COM 
72612186SJanice.Chang@Sun.COM 		if (err || read_err || write_err || session->ns_eof)
72712186SJanice.Chang@Sun.COM 			result = EIO;
72812186SJanice.Chang@Sun.COM 	}
72912186SJanice.Chang@Sun.COM 
73012186SJanice.Chang@Sun.COM 	if (session->ns_data.dd_abort) {
73112186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
73212186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset);
73312186SJanice.Chang@Sun.COM 		ndmpd_audit_restore(session->ns_connection,
73412186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset,
73512186SJanice.Chang@Sun.COM 		    session->ns_data.dd_data_addr.addr_type,
73612186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset, EINTR);
73712186SJanice.Chang@Sun.COM 		(void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
73812186SJanice.Chang@Sun.COM 		err = -1;
73912186SJanice.Chang@Sun.COM 	} else {
74012186SJanice.Chang@Sun.COM 		ndmpd_audit_restore(session->ns_connection,
74112186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset,
74212186SJanice.Chang@Sun.COM 		    session->ns_data.dd_data_addr.addr_type,
74312186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset, result);
74412186SJanice.Chang@Sun.COM 		err = ndmpd_zfs_post_restore(ndmpd_zfs_args);
74512186SJanice.Chang@Sun.COM 		if (err || result)
74612186SJanice.Chang@Sun.COM 			err = -1;
74712186SJanice.Chang@Sun.COM 
74812186SJanice.Chang@Sun.COM 		if (err == 0) {
74912186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished",
75012186SJanice.Chang@Sun.COM 			    ndmpd_zfs_args->nz_dataset);
75112186SJanice.Chang@Sun.COM 		} else {
75212186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "An error occurred while restoring"
75312186SJanice.Chang@Sun.COM 			    " to \"%s\"", ndmpd_zfs_args->nz_dataset);
75412186SJanice.Chang@Sun.COM 		}
75512186SJanice.Chang@Sun.COM 	}
75612186SJanice.Chang@Sun.COM 
75712186SJanice.Chang@Sun.COM 	return (err);
75812186SJanice.Chang@Sun.COM }
75912186SJanice.Chang@Sun.COM 
76012186SJanice.Chang@Sun.COM static int
76112186SJanice.Chang@Sun.COM ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
76212186SJanice.Chang@Sun.COM {
76312186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
76412186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
76512186SJanice.Chang@Sun.COM 	int bufsize = ndmpd_zfs_args->nz_bufsize;
76612186SJanice.Chang@Sun.COM 	u_longlong_t *bytes_totalp;
76712186SJanice.Chang@Sun.COM 	char *buf;
76812186SJanice.Chang@Sun.COM 	int count;
76912186SJanice.Chang@Sun.COM 	int err;
77012186SJanice.Chang@Sun.COM 
77112186SJanice.Chang@Sun.COM 	buf = ndmp_malloc(bufsize);
77212186SJanice.Chang@Sun.COM 	if (buf == NULL) {
77312186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "buf NULL");
77412186SJanice.Chang@Sun.COM 		return (-1);
77512186SJanice.Chang@Sun.COM 	}
77612186SJanice.Chang@Sun.COM 
77712186SJanice.Chang@Sun.COM 	bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total;
77812186SJanice.Chang@Sun.COM 
77912186SJanice.Chang@Sun.COM 	for (;;) {
78012186SJanice.Chang@Sun.COM 		err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
78112186SJanice.Chang@Sun.COM 
78212186SJanice.Chang@Sun.COM 		if (err == -1) {
78312186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "end of data (%llu) bytes",
78412186SJanice.Chang@Sun.COM 			    *bytes_totalp);
78512186SJanice.Chang@Sun.COM 			(void) write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE],
78612186SJanice.Chang@Sun.COM 			    buf, bufsize);
78712186SJanice.Chang@Sun.COM 			break;
78812186SJanice.Chang@Sun.COM 		}
78912186SJanice.Chang@Sun.COM 
79012186SJanice.Chang@Sun.COM 		count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
79112186SJanice.Chang@Sun.COM 		    bufsize);
79212186SJanice.Chang@Sun.COM 
79312186SJanice.Chang@Sun.COM 		if (count == -1) {
79412186SJanice.Chang@Sun.COM 			free(buf);
79512186SJanice.Chang@Sun.COM 
79612186SJanice.Chang@Sun.COM 			if ((errno == EPIPE) && !session->ns_data.dd_abort) {
79712186SJanice.Chang@Sun.COM 				NDMP_LOG(LOG_DEBUG, "EPIPE; count == -1; "
79812186SJanice.Chang@Sun.COM 				    "[%llu bytes] returning success",
79912186SJanice.Chang@Sun.COM 				    *bytes_totalp);
80012186SJanice.Chang@Sun.COM 				return (0);
80112186SJanice.Chang@Sun.COM 			}
80212186SJanice.Chang@Sun.COM 
80312186SJanice.Chang@Sun.COM 			if (session->ns_data.dd_abort)
80412186SJanice.Chang@Sun.COM 				NDMP_LOG(LOG_DEBUG, "abort set");
80512186SJanice.Chang@Sun.COM 
80612186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "pipe write error:"
80712186SJanice.Chang@Sun.COM 			    "errno: %d", errno);
80812186SJanice.Chang@Sun.COM 
80912186SJanice.Chang@Sun.COM 			return (-1);
81012186SJanice.Chang@Sun.COM 		}
81112186SJanice.Chang@Sun.COM 
81212186SJanice.Chang@Sun.COM 		*bytes_totalp += count;
81312186SJanice.Chang@Sun.COM 
81412186SJanice.Chang@Sun.COM 		/*
81512186SJanice.Chang@Sun.COM 		 * A short write to the pipe indicates the
81612186SJanice.Chang@Sun.COM 		 * other peer is terminated so we should exit
81712186SJanice.Chang@Sun.COM 		 */
81812186SJanice.Chang@Sun.COM 
81912186SJanice.Chang@Sun.COM 		if (count != bufsize) {
82012186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "count != bufsize:"
82112186SJanice.Chang@Sun.COM 			    "count: %d; bufsize: %d",
82212186SJanice.Chang@Sun.COM 			    count, bufsize);
82312186SJanice.Chang@Sun.COM 			free(buf);
82412186SJanice.Chang@Sun.COM 			return (0);
82512186SJanice.Chang@Sun.COM 		}
82612186SJanice.Chang@Sun.COM 
82712186SJanice.Chang@Sun.COM 		/* Checks for local mover */
82812186SJanice.Chang@Sun.COM 		if (*bytes_totalp == ndmpd_zfs_args->nz_window_len) {
82912186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "Reached EOW at %lld",
83012186SJanice.Chang@Sun.COM 			    *bytes_totalp);
83112186SJanice.Chang@Sun.COM 			if (ndmpd_zfs_is_spanning(ndmpd_zfs_args) == 0) {
83212186SJanice.Chang@Sun.COM 				NDMP_LOG(LOG_DEBUG, "Exit");
83312186SJanice.Chang@Sun.COM 				break;
83412186SJanice.Chang@Sun.COM 			}
83512186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "Continue through spanning");
83612186SJanice.Chang@Sun.COM 		}
83712186SJanice.Chang@Sun.COM 	}
83812186SJanice.Chang@Sun.COM 
83912186SJanice.Chang@Sun.COM 	free(buf);
84012186SJanice.Chang@Sun.COM 	return (0);
84112186SJanice.Chang@Sun.COM }
84212186SJanice.Chang@Sun.COM 
84312186SJanice.Chang@Sun.COM /*
84412186SJanice.Chang@Sun.COM  * ndmpd_zfs_restore_recv_write()
84512186SJanice.Chang@Sun.COM  *
84612186SJanice.Chang@Sun.COM  * This routine executes zfs_receive() to restore the backup.
84712186SJanice.Chang@Sun.COM  */
84812186SJanice.Chang@Sun.COM 
84912186SJanice.Chang@Sun.COM static int
85012186SJanice.Chang@Sun.COM ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
85112186SJanice.Chang@Sun.COM {
85212186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
85312186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
85412186SJanice.Chang@Sun.COM 	recvflags_t flags;
85512186SJanice.Chang@Sun.COM 	int err;
85612186SJanice.Chang@Sun.COM 
85712186SJanice.Chang@Sun.COM 	bzero(&flags, sizeof (recvflags_t));
85812186SJanice.Chang@Sun.COM 
85912186SJanice.Chang@Sun.COM 	flags.nomount = B_TRUE;
86012186SJanice.Chang@Sun.COM 
86112186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_args->nz_zfs_force)
86212186SJanice.Chang@Sun.COM 		flags.force = B_TRUE;
86312186SJanice.Chang@Sun.COM 
86412186SJanice.Chang@Sun.COM 	err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
86512186SJanice.Chang@Sun.COM 	    flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL);
86612186SJanice.Chang@Sun.COM 
86712186SJanice.Chang@Sun.COM 	if (err && !session->ns_data.dd_abort)
86812186SJanice.Chang@Sun.COM 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err);
86912186SJanice.Chang@Sun.COM 
87012186SJanice.Chang@Sun.COM 	return (err);
87112186SJanice.Chang@Sun.COM }
87212186SJanice.Chang@Sun.COM 
87312186SJanice.Chang@Sun.COM /*
87412186SJanice.Chang@Sun.COM  * ndmpd_zfs_is_spanning()
87512186SJanice.Chang@Sun.COM  *
87612186SJanice.Chang@Sun.COM  * Check to see if the tape is at spanning point
87712186SJanice.Chang@Sun.COM  */
87812186SJanice.Chang@Sun.COM 
87912186SJanice.Chang@Sun.COM static int
88012186SJanice.Chang@Sun.COM ndmpd_zfs_is_spanning(ndmpd_zfs_args_t *ndmpd_zfs_args)
88112186SJanice.Chang@Sun.COM {
88212186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
88312186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
88412186SJanice.Chang@Sun.COM 	int count = session->ns_mover.md_record_size;
88512186SJanice.Chang@Sun.COM 	char *buf;
88612186SJanice.Chang@Sun.COM 
88712186SJanice.Chang@Sun.COM 	if ((buf = ndmp_malloc(count)) == NULL)
88812186SJanice.Chang@Sun.COM 		return (0);
88912186SJanice.Chang@Sun.COM 
89012186SJanice.Chang@Sun.COM 	if (read(session->ns_tape.td_fd, buf, count) == 0) {
89112186SJanice.Chang@Sun.COM 		free(buf);
89212186SJanice.Chang@Sun.COM 		return (1);
89312186SJanice.Chang@Sun.COM 	}
89412186SJanice.Chang@Sun.COM 
89512186SJanice.Chang@Sun.COM 	(void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSR, 1);
89612186SJanice.Chang@Sun.COM 	free(buf);
89712186SJanice.Chang@Sun.COM 	return (0);
89812186SJanice.Chang@Sun.COM }
89912186SJanice.Chang@Sun.COM 
90012186SJanice.Chang@Sun.COM /*
90112186SJanice.Chang@Sun.COM  * ndmpd_zfs_reader_writer()
90212186SJanice.Chang@Sun.COM  *
90312186SJanice.Chang@Sun.COM  * Two separate threads are used for actual backup or restore.
90412186SJanice.Chang@Sun.COM  */
90512186SJanice.Chang@Sun.COM 
90612186SJanice.Chang@Sun.COM static int
90712186SJanice.Chang@Sun.COM ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args,
90812186SJanice.Chang@Sun.COM     int **sendrecv_errp, int **tape_errp)
90912186SJanice.Chang@Sun.COM {
91012186SJanice.Chang@Sun.COM 	funct_t sendrecv_func;
91112186SJanice.Chang@Sun.COM 	funct_t tape_func;
91212186SJanice.Chang@Sun.COM 	int sendrecv_err;
91312186SJanice.Chang@Sun.COM 	int tape_err;
91412186SJanice.Chang@Sun.COM 
91512186SJanice.Chang@Sun.COM 	switch (ndmpd_zfs_params->mp_operation) {
91612186SJanice.Chang@Sun.COM 	case NDMP_DATA_OP_BACKUP:
91712186SJanice.Chang@Sun.COM 		sendrecv_func = (funct_t)ndmpd_zfs_backup_send_read;
91812186SJanice.Chang@Sun.COM 		tape_func = (funct_t)ndmpd_zfs_backup_tape_write;
91912186SJanice.Chang@Sun.COM 		break;
92012186SJanice.Chang@Sun.COM 	case NDMP_DATA_OP_RECOVER:
92112186SJanice.Chang@Sun.COM 		sendrecv_func = (funct_t)ndmpd_zfs_restore_recv_write;
92212186SJanice.Chang@Sun.COM 		tape_func = (funct_t)ndmpd_zfs_restore_tape_read;
92312186SJanice.Chang@Sun.COM 		break;
92412186SJanice.Chang@Sun.COM 	}
92512186SJanice.Chang@Sun.COM 
92612186SJanice.Chang@Sun.COM 	sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread,
92712186SJanice.Chang@Sun.COM 	    NULL, sendrecv_func, ndmpd_zfs_args);
92812186SJanice.Chang@Sun.COM 
92912186SJanice.Chang@Sun.COM 	if (sendrecv_err == 0) {
93012186SJanice.Chang@Sun.COM 		tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread,
93112186SJanice.Chang@Sun.COM 		    NULL, tape_func, ndmpd_zfs_args);
93212186SJanice.Chang@Sun.COM 
93312186SJanice.Chang@Sun.COM 		if (tape_err) {
93412186SJanice.Chang@Sun.COM 			/*
93512186SJanice.Chang@Sun.COM 			 * The close of the tape side of the pipe will cause
93612186SJanice.Chang@Sun.COM 			 * nz_sendrecv_thread to error in the zfs_send/recv()
93712186SJanice.Chang@Sun.COM 			 * call and to return.  Hence we do not need
93812186SJanice.Chang@Sun.COM 			 * to explicitly cancel the sendrecv_thread here
93912186SJanice.Chang@Sun.COM 			 * (the pthread_join() below is sufficient).
94012186SJanice.Chang@Sun.COM 			 */
94112186SJanice.Chang@Sun.COM 
94212186SJanice.Chang@Sun.COM 			(void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]);
94312186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_ERR, "Could not start tape thread; "
94412186SJanice.Chang@Sun.COM 			    "aborting z-op");
94512186SJanice.Chang@Sun.COM 		}
94612186SJanice.Chang@Sun.COM 
94712186SJanice.Chang@Sun.COM 		(void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread,
94812186SJanice.Chang@Sun.COM 		    (void **) sendrecv_errp);
94912186SJanice.Chang@Sun.COM 	}
95012186SJanice.Chang@Sun.COM 
95112186SJanice.Chang@Sun.COM 	if ((tape_err == 0) &&
95212186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER))
95312186SJanice.Chang@Sun.COM 		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
95412186SJanice.Chang@Sun.COM 
95512186SJanice.Chang@Sun.COM 	ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
95612186SJanice.Chang@Sun.COM 
95712186SJanice.Chang@Sun.COM 	if ((sendrecv_err == 0) && (tape_err == 0)) {
95812186SJanice.Chang@Sun.COM 		(void) pthread_join(ndmpd_zfs_args->nz_tape_thread,
95912186SJanice.Chang@Sun.COM 		    (void **) tape_errp);
96012186SJanice.Chang@Sun.COM 	}
96112186SJanice.Chang@Sun.COM 
96212186SJanice.Chang@Sun.COM 	if ((tape_err == 0) &&
96312186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP))
96412186SJanice.Chang@Sun.COM 		ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
96512186SJanice.Chang@Sun.COM 
96612186SJanice.Chang@Sun.COM 	return (sendrecv_err ? sendrecv_err : tape_err);
96712186SJanice.Chang@Sun.COM }
96812186SJanice.Chang@Sun.COM 
96912186SJanice.Chang@Sun.COM int
97012186SJanice.Chang@Sun.COM ndmpd_zfs_abort(void *arg)
97112186SJanice.Chang@Sun.COM {
97212186SJanice.Chang@Sun.COM 	ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
97312186SJanice.Chang@Sun.COM 	char str[8];
97412186SJanice.Chang@Sun.COM 
97512186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)
97612186SJanice.Chang@Sun.COM 		(void) strlcpy(str, "backup", 8);
97712186SJanice.Chang@Sun.COM 	else
97812186SJanice.Chang@Sun.COM 		(void) strlcpy(str, "recover", 8);
97912186SJanice.Chang@Sun.COM 
98012186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation",
98112186SJanice.Chang@Sun.COM 	    str);
98212186SJanice.Chang@Sun.COM 
98312186SJanice.Chang@Sun.COM 	ndmpd_zfs_close_fds(ndmpd_zfs_args);
98412186SJanice.Chang@Sun.COM 
98512186SJanice.Chang@Sun.COM 	return (0);
98612186SJanice.Chang@Sun.COM }
98712186SJanice.Chang@Sun.COM 
98812186SJanice.Chang@Sun.COM /*
98912186SJanice.Chang@Sun.COM  * ndmpd_zfs_pre_backup()
99012186SJanice.Chang@Sun.COM  *
99112186SJanice.Chang@Sun.COM  * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL.
99212186SJanice.Chang@Sun.COM  * This ensures that ndmp_include_zfs() will fail, which is
99312186SJanice.Chang@Sun.COM  * a requirement for "zfs"-type backup.
99412186SJanice.Chang@Sun.COM  */
99512186SJanice.Chang@Sun.COM 
99612186SJanice.Chang@Sun.COM int
99712186SJanice.Chang@Sun.COM ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
99812186SJanice.Chang@Sun.COM {
99912186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
100012186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
100112186SJanice.Chang@Sun.COM 	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
100212186SJanice.Chang@Sun.COM 	int err;
100312186SJanice.Chang@Sun.COM 
100412186SJanice.Chang@Sun.COM 	if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL)
100512186SJanice.Chang@Sun.COM 		return (0);
100612186SJanice.Chang@Sun.COM 
100712186SJanice.Chang@Sun.COM 	(void) memset(nctxp, 0, sizeof (ndmp_context_t));
100812186SJanice.Chang@Sun.COM 	nctxp->nc_plversion = ndmp_pl->np_plversion;
100912186SJanice.Chang@Sun.COM 	nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
101012186SJanice.Chang@Sun.COM 	nctxp->nc_ddata = (void *) session;
101112186SJanice.Chang@Sun.COM 
101212186SJanice.Chang@Sun.COM 	err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp,
101312186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_dataset);
101412186SJanice.Chang@Sun.COM 
101512186SJanice.Chang@Sun.COM 	if (err != 0) {
101612186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m");
101712186SJanice.Chang@Sun.COM 		(void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
101812186SJanice.Chang@Sun.COM 	}
101912186SJanice.Chang@Sun.COM 
102012186SJanice.Chang@Sun.COM 	return (err);
102112186SJanice.Chang@Sun.COM }
102212186SJanice.Chang@Sun.COM 
102312186SJanice.Chang@Sun.COM int
102412186SJanice.Chang@Sun.COM ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
102512186SJanice.Chang@Sun.COM {
102612186SJanice.Chang@Sun.COM 	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
102712186SJanice.Chang@Sun.COM 	int err = 0;
102812186SJanice.Chang@Sun.COM 
102912186SJanice.Chang@Sun.COM 	if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL)
103012186SJanice.Chang@Sun.COM 		return (0);
103112186SJanice.Chang@Sun.COM 
103212186SJanice.Chang@Sun.COM 	err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err);
103312186SJanice.Chang@Sun.COM 
103412186SJanice.Chang@Sun.COM 	if (err == -1)
103512186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
103612186SJanice.Chang@Sun.COM 
103712186SJanice.Chang@Sun.COM 	return (err);
103812186SJanice.Chang@Sun.COM }
103912186SJanice.Chang@Sun.COM 
104012186SJanice.Chang@Sun.COM int
104112186SJanice.Chang@Sun.COM ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
104212186SJanice.Chang@Sun.COM {
104312186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
104412186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
104512186SJanice.Chang@Sun.COM 	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
104612186SJanice.Chang@Sun.COM 	char bkpath[ZFS_MAXNAMELEN];
104712186SJanice.Chang@Sun.COM 	int err;
104812186SJanice.Chang@Sun.COM 
104912186SJanice.Chang@Sun.COM 	if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL)
105012186SJanice.Chang@Sun.COM 		return (0);
105112186SJanice.Chang@Sun.COM 
105212186SJanice.Chang@Sun.COM 	err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath, ZFS_MAXNAMELEN);
105312186SJanice.Chang@Sun.COM 
105412186SJanice.Chang@Sun.COM 	if (err != 0) {
105512186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err);
105612186SJanice.Chang@Sun.COM 		return (-1);
105712186SJanice.Chang@Sun.COM 	}
105812186SJanice.Chang@Sun.COM 
105912186SJanice.Chang@Sun.COM 	err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args);
106012186SJanice.Chang@Sun.COM 
106112186SJanice.Chang@Sun.COM 	if (err != 0) {
106212186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err);
106312186SJanice.Chang@Sun.COM 		return (-1);
106412186SJanice.Chang@Sun.COM 	}
106512186SJanice.Chang@Sun.COM 
106612186SJanice.Chang@Sun.COM 	(void) memset(nctxp, 0, sizeof (ndmp_context_t));
106712186SJanice.Chang@Sun.COM 	nctxp->nc_ddata = (void *) session;
106812186SJanice.Chang@Sun.COM 
106912186SJanice.Chang@Sun.COM 	err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath,
107012186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_dataset);
107112186SJanice.Chang@Sun.COM 
107212186SJanice.Chang@Sun.COM 	if (err != 0) {
107312186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
107412186SJanice.Chang@Sun.COM 		return (-1);
107512186SJanice.Chang@Sun.COM 	}
107612186SJanice.Chang@Sun.COM 
107712186SJanice.Chang@Sun.COM 	return (0);
107812186SJanice.Chang@Sun.COM }
107912186SJanice.Chang@Sun.COM 
108012186SJanice.Chang@Sun.COM int
108112186SJanice.Chang@Sun.COM ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
108212186SJanice.Chang@Sun.COM {
108312186SJanice.Chang@Sun.COM 	ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
108412186SJanice.Chang@Sun.COM 	int err = 0;
108512186SJanice.Chang@Sun.COM 
108612186SJanice.Chang@Sun.COM 	if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL)
108712186SJanice.Chang@Sun.COM 		return (0);
108812186SJanice.Chang@Sun.COM 
108912186SJanice.Chang@Sun.COM 	err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err);
109012186SJanice.Chang@Sun.COM 
109112186SJanice.Chang@Sun.COM 	if (err == -1)
109212186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
109312186SJanice.Chang@Sun.COM 
109412186SJanice.Chang@Sun.COM 	return (err);
109512186SJanice.Chang@Sun.COM }
109612186SJanice.Chang@Sun.COM 
109712186SJanice.Chang@Sun.COM boolean_t
109812186SJanice.Chang@Sun.COM ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
109912186SJanice.Chang@Sun.COM {
110012186SJanice.Chang@Sun.COM 	ndmpd_zfs_snapfind_t snapdata;
110112186SJanice.Chang@Sun.COM 
110212186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0)
110312186SJanice.Chang@Sun.COM 		return (B_FALSE);
110412186SJanice.Chang@Sun.COM 
110512186SJanice.Chang@Sun.COM 	if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args))
110612186SJanice.Chang@Sun.COM 		return (B_FALSE);
110712186SJanice.Chang@Sun.COM 
110812186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
110912186SJanice.Chang@Sun.COM 		(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
111012186SJanice.Chang@Sun.COM 		    snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE);
111112186SJanice.Chang@Sun.COM 
111212186SJanice.Chang@Sun.COM 		snapdata.nzs_snapname[0] = '\0';
111312186SJanice.Chang@Sun.COM 		snapdata.nzs_snapprop[0] = '\0';
111412186SJanice.Chang@Sun.COM 
111512186SJanice.Chang@Sun.COM 		if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata))
111612186SJanice.Chang@Sun.COM 			return (B_FALSE);
111712186SJanice.Chang@Sun.COM 
111812186SJanice.Chang@Sun.COM 		if (snapdata.nzs_snapname[0] == '\0') { /* not found */
111912186SJanice.Chang@Sun.COM 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
112012186SJanice.Chang@Sun.COM 			    "Snapshot for level %d does not exist\n",
112112186SJanice.Chang@Sun.COM 			    ndmpd_zfs_args->nz_level-1);
112212186SJanice.Chang@Sun.COM 			return (B_FALSE);
112312186SJanice.Chang@Sun.COM 		}
112412186SJanice.Chang@Sun.COM 
112512186SJanice.Chang@Sun.COM 		(void) strlcpy(ndmpd_zfs_args->nz_fromsnap,
112612186SJanice.Chang@Sun.COM 		    snapdata.nzs_snapname, ZFS_MAXNAMELEN);
112712186SJanice.Chang@Sun.COM 	}
112812186SJanice.Chang@Sun.COM 
112912186SJanice.Chang@Sun.COM 	return (B_TRUE);
113012186SJanice.Chang@Sun.COM }
113112186SJanice.Chang@Sun.COM 
113212186SJanice.Chang@Sun.COM /*
113312186SJanice.Chang@Sun.COM  * ndmpd_zfs_backup_pathvalid()
113412186SJanice.Chang@Sun.COM  *
113512186SJanice.Chang@Sun.COM  * Make sure the path is of an existing dataset
113612186SJanice.Chang@Sun.COM  */
113712186SJanice.Chang@Sun.COM 
113812186SJanice.Chang@Sun.COM static boolean_t
113912186SJanice.Chang@Sun.COM ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
114012186SJanice.Chang@Sun.COM {
114112186SJanice.Chang@Sun.COM 	char zpath[ZFS_MAXNAMELEN];
114212186SJanice.Chang@Sun.COM 	char propstr[ZFS_MAXPROPLEN];
114312186SJanice.Chang@Sun.COM 	zfs_handle_t *zhp;
114412186SJanice.Chang@Sun.COM 	zfs_type_t ztype = 0;
114512186SJanice.Chang@Sun.COM 	int err;
114612186SJanice.Chang@Sun.COM 
114712186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, ZFS_MAXNAMELEN)
114812186SJanice.Chang@Sun.COM 	    != 0)
114912186SJanice.Chang@Sun.COM 		return (B_FALSE);
115012186SJanice.Chang@Sun.COM 
115112186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_args->nz_snapname[0] != '\0') {
115212186SJanice.Chang@Sun.COM 		zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath,
115312186SJanice.Chang@Sun.COM 		    ZFS_TYPE_SNAPSHOT);
115412186SJanice.Chang@Sun.COM 
115512186SJanice.Chang@Sun.COM 		if (!zhp) {
115612186SJanice.Chang@Sun.COM 			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args,
115712186SJanice.Chang@Sun.COM 			    "zfs_open (snap)");
115812186SJanice.Chang@Sun.COM 			ndmpd_zfs_args->nz_snapname[0] = '\0';
115912186SJanice.Chang@Sun.COM 			ndmpd_zfs_args->nz_dataset[0] = '\0';
116012186SJanice.Chang@Sun.COM 			return (B_FALSE);
116112186SJanice.Chang@Sun.COM 		}
116212186SJanice.Chang@Sun.COM 
116312186SJanice.Chang@Sun.COM 		err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
116412186SJanice.Chang@Sun.COM 
116512186SJanice.Chang@Sun.COM 		zfs_close(zhp);
116612186SJanice.Chang@Sun.COM 
116712186SJanice.Chang@Sun.COM 		if (err) {
116812186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG,
116912186SJanice.Chang@Sun.COM 			    "ndmpd_zfs_snapshot_prop_get failed");
117012186SJanice.Chang@Sun.COM 			return (-1);
117112186SJanice.Chang@Sun.COM 		}
117212186SJanice.Chang@Sun.COM 
117312186SJanice.Chang@Sun.COM 		if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) {
117412186SJanice.Chang@Sun.COM 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
117512186SJanice.Chang@Sun.COM 			    "cannot use an ndmpd-generated snapshot\n");
117612186SJanice.Chang@Sun.COM 			return (B_FALSE);
117712186SJanice.Chang@Sun.COM 		}
117812186SJanice.Chang@Sun.COM 	}
117912186SJanice.Chang@Sun.COM 
118012186SJanice.Chang@Sun.COM 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
118112186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET);
118212186SJanice.Chang@Sun.COM 
118312186SJanice.Chang@Sun.COM 	if (zhp) {
118412186SJanice.Chang@Sun.COM 		ztype = zfs_get_type(zhp);
118512186SJanice.Chang@Sun.COM 		zfs_close(zhp);
118612186SJanice.Chang@Sun.COM 	}
118712186SJanice.Chang@Sun.COM 
118812186SJanice.Chang@Sun.COM 	if ((ztype == ZFS_TYPE_VOLUME) ||
118912186SJanice.Chang@Sun.COM 	    (ztype == ZFS_TYPE_FILESYSTEM)) {
119012186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_type = ztype;
119112186SJanice.Chang@Sun.COM 		return (B_TRUE);
119212186SJanice.Chang@Sun.COM 	}
119312186SJanice.Chang@Sun.COM 
119412186SJanice.Chang@Sun.COM 	ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
119512186SJanice.Chang@Sun.COM 	    "Invalid file system or volume.\n");
119612186SJanice.Chang@Sun.COM 
119712186SJanice.Chang@Sun.COM 	return (B_FALSE);
119812186SJanice.Chang@Sun.COM }
119912186SJanice.Chang@Sun.COM 
120012186SJanice.Chang@Sun.COM /*
120112186SJanice.Chang@Sun.COM  * ndmpd_zfs_backup_getpath()
120212186SJanice.Chang@Sun.COM  *
120312186SJanice.Chang@Sun.COM  * Retrieve the backup path from the environment, which should
120412186SJanice.Chang@Sun.COM  * be of the form "/dataset[@snap]".  The leading slash is required
120512186SJanice.Chang@Sun.COM  * by certain DMA's but can otherwise be ignored.
120612186SJanice.Chang@Sun.COM  *
120712186SJanice.Chang@Sun.COM  * (Note: "dataset" can consist of more than one component,
120812186SJanice.Chang@Sun.COM  * e.g. "pool", "pool/volume", "pool/fs/fs2".)
120912186SJanice.Chang@Sun.COM  *
121012186SJanice.Chang@Sun.COM  * The dataset name and the snapshot name (if any) will be
121112186SJanice.Chang@Sun.COM  * stored in ndmpd_zfs_args.
121212186SJanice.Chang@Sun.COM  */
121312186SJanice.Chang@Sun.COM 
121412186SJanice.Chang@Sun.COM static int
121512186SJanice.Chang@Sun.COM ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath,
121612186SJanice.Chang@Sun.COM     int zlen)
121712186SJanice.Chang@Sun.COM {
121812186SJanice.Chang@Sun.COM 	char *env_path;
121912186SJanice.Chang@Sun.COM 	char *at;
122012186SJanice.Chang@Sun.COM 
122112186SJanice.Chang@Sun.COM 	env_path = get_backup_path_v3(ndmpd_zfs_params);
122212186SJanice.Chang@Sun.COM 	if (env_path == NULL)
122312186SJanice.Chang@Sun.COM 		return (-1);
122412186SJanice.Chang@Sun.COM 
122512186SJanice.Chang@Sun.COM 	if (env_path[0] != '/') {
122612186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
122712186SJanice.Chang@Sun.COM 		    "Invalid path: %s (leading slash required)\n", env_path);
122812186SJanice.Chang@Sun.COM 		return (-1);
122912186SJanice.Chang@Sun.COM 	}
123012186SJanice.Chang@Sun.COM 
123112186SJanice.Chang@Sun.COM 	(void) strlcpy(zpath, &env_path[1], zlen);
123212186SJanice.Chang@Sun.COM 	(void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1],
123312186SJanice.Chang@Sun.COM 	    ZFS_MAXNAMELEN);
123412186SJanice.Chang@Sun.COM 
123512186SJanice.Chang@Sun.COM 	at = strchr(ndmpd_zfs_args->nz_dataset, '@');
123612186SJanice.Chang@Sun.COM 	if (at) {
123712186SJanice.Chang@Sun.COM 		*at = '\0';
123812186SJanice.Chang@Sun.COM 		(void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at,
123912186SJanice.Chang@Sun.COM 		    ZFS_MAXNAMELEN);
124012186SJanice.Chang@Sun.COM 	} else {
124112186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_snapname[0] = '\0';
124212186SJanice.Chang@Sun.COM 	}
124312186SJanice.Chang@Sun.COM 
124412186SJanice.Chang@Sun.COM 	return (0);
124512186SJanice.Chang@Sun.COM }
124612186SJanice.Chang@Sun.COM 
124712186SJanice.Chang@Sun.COM static int
124812186SJanice.Chang@Sun.COM ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
124912186SJanice.Chang@Sun.COM {
125012186SJanice.Chang@Sun.COM 	return (ndmpd_zfs_getenv(ndmpd_zfs_args));
125112186SJanice.Chang@Sun.COM }
125212186SJanice.Chang@Sun.COM 
125312186SJanice.Chang@Sun.COM boolean_t
125412186SJanice.Chang@Sun.COM ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
125512186SJanice.Chang@Sun.COM {
125612186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0)
125712186SJanice.Chang@Sun.COM 		return (B_FALSE);
125812186SJanice.Chang@Sun.COM 
125912186SJanice.Chang@Sun.COM 	if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args))
126012186SJanice.Chang@Sun.COM 		return (B_FALSE);
126112186SJanice.Chang@Sun.COM 
126212186SJanice.Chang@Sun.COM 	return (B_TRUE);
126312186SJanice.Chang@Sun.COM }
126412186SJanice.Chang@Sun.COM 
126512186SJanice.Chang@Sun.COM static boolean_t
126612186SJanice.Chang@Sun.COM ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
126712186SJanice.Chang@Sun.COM {
126812186SJanice.Chang@Sun.COM 	zfs_handle_t *zhp;
126912186SJanice.Chang@Sun.COM 	char *at;
127012186SJanice.Chang@Sun.COM 
127112186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0)
127212186SJanice.Chang@Sun.COM 		return (B_FALSE);
127312186SJanice.Chang@Sun.COM 
127412186SJanice.Chang@Sun.COM 	at = strchr(ndmpd_zfs_args->nz_dataset, '@');
127512186SJanice.Chang@Sun.COM 
127612186SJanice.Chang@Sun.COM 	if (at) {
127712186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
127812186SJanice.Chang@Sun.COM 		    "%s ignored in restore path\n", at);
127912186SJanice.Chang@Sun.COM 		*at = '\0';
128012186SJanice.Chang@Sun.COM 	}
128112186SJanice.Chang@Sun.COM 
128212186SJanice.Chang@Sun.COM 	ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
128312186SJanice.Chang@Sun.COM 
128412186SJanice.Chang@Sun.COM 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
128512186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
128612186SJanice.Chang@Sun.COM 
128712186SJanice.Chang@Sun.COM 	if (zhp) {
128812186SJanice.Chang@Sun.COM 		zfs_close(zhp);
128912186SJanice.Chang@Sun.COM 
129012186SJanice.Chang@Sun.COM 		if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
129112186SJanice.Chang@Sun.COM 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
129212186SJanice.Chang@Sun.COM 			    "Restore dataset exists.\n"
129312186SJanice.Chang@Sun.COM 			    "A nonexistent dataset must be specified "
129412186SJanice.Chang@Sun.COM 			    "for 'zfs' non-incremental restore.\n");
129512186SJanice.Chang@Sun.COM 			return (B_FALSE);
129612186SJanice.Chang@Sun.COM 		}
129712186SJanice.Chang@Sun.COM 	}
129812186SJanice.Chang@Sun.COM 
129912186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset);
130012186SJanice.Chang@Sun.COM 
130112186SJanice.Chang@Sun.COM 	return (B_TRUE);
130212186SJanice.Chang@Sun.COM }
130312186SJanice.Chang@Sun.COM 
130412186SJanice.Chang@Sun.COM /*
130512186SJanice.Chang@Sun.COM  * ndmpd_zfs_restore_getpath()
130612186SJanice.Chang@Sun.COM  *
130712186SJanice.Chang@Sun.COM  * Be sure to not include the leading slash, which is required for
130812186SJanice.Chang@Sun.COM  * compatibility with backup applications (NBU) but which is not part
130912186SJanice.Chang@Sun.COM  * of the ZFS syntax.  (Note that this done explicitly in all paths
131012186SJanice.Chang@Sun.COM  * below except those calling ndmpd_zfs_backup_getpath(), because it is
131112186SJanice.Chang@Sun.COM  * already stripped in that function.)
131212186SJanice.Chang@Sun.COM  *
131312186SJanice.Chang@Sun.COM  * In addition, the DMA might add a trailing slash to the path.
131412186SJanice.Chang@Sun.COM  * Strip all such slashes.
131512186SJanice.Chang@Sun.COM  */
131612186SJanice.Chang@Sun.COM 
131712186SJanice.Chang@Sun.COM static int
131812186SJanice.Chang@Sun.COM ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args)
131912186SJanice.Chang@Sun.COM {
132012186SJanice.Chang@Sun.COM 	int version = ndmpd_zfs_params->mp_protocol_version;
132112186SJanice.Chang@Sun.COM 	char zpath[ZFS_MAXNAMELEN];
132212186SJanice.Chang@Sun.COM 	mem_ndmp_name_v3_t *namep_v3;
132312186SJanice.Chang@Sun.COM 	char *dataset = ndmpd_zfs_args->nz_dataset;
132412186SJanice.Chang@Sun.COM 	char *nm;
132512186SJanice.Chang@Sun.COM 	char *p;
132612186SJanice.Chang@Sun.COM 	int len;
132712186SJanice.Chang@Sun.COM 	int err;
132812186SJanice.Chang@Sun.COM 
132912186SJanice.Chang@Sun.COM 	dataset = ndmpd_zfs_args->nz_dataset;
133012186SJanice.Chang@Sun.COM 
133112186SJanice.Chang@Sun.COM 	namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0);
133212186SJanice.Chang@Sun.COM 
133312186SJanice.Chang@Sun.COM 	if (namep_v3 == NULL) {
133412186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]");
133512186SJanice.Chang@Sun.COM 		return (-1);
133612186SJanice.Chang@Sun.COM 	}
133712186SJanice.Chang@Sun.COM 
133812186SJanice.Chang@Sun.COM 	if (namep_v3->nm3_dpath) {
133912186SJanice.Chang@Sun.COM 		if (namep_v3->nm3_dpath[0] != '/') {
134012186SJanice.Chang@Sun.COM 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
134112186SJanice.Chang@Sun.COM 			    "Invalid path: %s (leading slash required)\n",
134212186SJanice.Chang@Sun.COM 			    namep_v3->nm3_dpath);
134312186SJanice.Chang@Sun.COM 			return (-1);
134412186SJanice.Chang@Sun.COM 		}
134512186SJanice.Chang@Sun.COM 
134612186SJanice.Chang@Sun.COM 		(void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]),
134712186SJanice.Chang@Sun.COM 		    ZFS_MAXNAMELEN);
134812186SJanice.Chang@Sun.COM 
134912186SJanice.Chang@Sun.COM 		if (namep_v3->nm3_newnm) {
135012186SJanice.Chang@Sun.COM 			(void) strlcat(dataset, "/", ZFS_MAXNAMELEN);
135112186SJanice.Chang@Sun.COM 			(void) strlcat(dataset, namep_v3->nm3_newnm,
135212186SJanice.Chang@Sun.COM 			    ZFS_MAXNAMELEN);
135312186SJanice.Chang@Sun.COM 
135412186SJanice.Chang@Sun.COM 		} else {
135512186SJanice.Chang@Sun.COM 			if (version == NDMPV3) {
135612186SJanice.Chang@Sun.COM 				/*
135712186SJanice.Chang@Sun.COM 				 * The following does not apply for V4.
135812186SJanice.Chang@Sun.COM 				 *
135912186SJanice.Chang@Sun.COM 				 * Find the last component of nm3_opath.
136012186SJanice.Chang@Sun.COM 				 * nm3_opath has no trailing '/'.
136112186SJanice.Chang@Sun.COM 				 */
136212186SJanice.Chang@Sun.COM 				p = strrchr(namep_v3->nm3_opath, '/');
136312186SJanice.Chang@Sun.COM 				nm = p? p : namep_v3->nm3_opath;
136412186SJanice.Chang@Sun.COM 				(void) strlcat(dataset, "/", ZFS_MAXNAMELEN);
136512186SJanice.Chang@Sun.COM 				(void) strlcat(dataset, nm, ZFS_MAXNAMELEN);
136612186SJanice.Chang@Sun.COM 			}
136712186SJanice.Chang@Sun.COM 		}
136812186SJanice.Chang@Sun.COM 	} else {
136912186SJanice.Chang@Sun.COM 		err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
137012186SJanice.Chang@Sun.COM 		    ZFS_MAXNAMELEN);
137112186SJanice.Chang@Sun.COM 		if (err)
137212186SJanice.Chang@Sun.COM 			return (err);
137312186SJanice.Chang@Sun.COM 	}
137412186SJanice.Chang@Sun.COM 
137512186SJanice.Chang@Sun.COM 	len = strlen(dataset);
137612186SJanice.Chang@Sun.COM 	while (dataset[len-1] == '/') {
137712186SJanice.Chang@Sun.COM 		dataset[len-1] = '\0';
137812186SJanice.Chang@Sun.COM 		len--;
137912186SJanice.Chang@Sun.COM 	}
138012186SJanice.Chang@Sun.COM 
138112186SJanice.Chang@Sun.COM 	return (0);
138212186SJanice.Chang@Sun.COM }
138312186SJanice.Chang@Sun.COM 
138412186SJanice.Chang@Sun.COM static int
138512186SJanice.Chang@Sun.COM ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
138612186SJanice.Chang@Sun.COM {
138712186SJanice.Chang@Sun.COM 	return (ndmpd_zfs_getenv(ndmpd_zfs_args));
138812186SJanice.Chang@Sun.COM }
138912186SJanice.Chang@Sun.COM 
139012186SJanice.Chang@Sun.COM static int
139112186SJanice.Chang@Sun.COM ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
139212186SJanice.Chang@Sun.COM {
139312186SJanice.Chang@Sun.COM 
139412186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0)
139512186SJanice.Chang@Sun.COM 		return (-1);
139612186SJanice.Chang@Sun.COM 
139712186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0)
139812186SJanice.Chang@Sun.COM 		return (-1);
139912186SJanice.Chang@Sun.COM 
140012186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0)
140112186SJanice.Chang@Sun.COM 		return (-1);
140212186SJanice.Chang@Sun.COM 
140312186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0)
140412186SJanice.Chang@Sun.COM 		return (-1);
140512186SJanice.Chang@Sun.COM 
140612186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0)
140712186SJanice.Chang@Sun.COM 		return (-1);
140812186SJanice.Chang@Sun.COM 
140912186SJanice.Chang@Sun.COM 	return (0);
141012186SJanice.Chang@Sun.COM }
141112186SJanice.Chang@Sun.COM 
141212186SJanice.Chang@Sun.COM static int
141312186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args)
141412186SJanice.Chang@Sun.COM {
141512186SJanice.Chang@Sun.COM 	char *envp;
141612186SJanice.Chang@Sun.COM 
141712186SJanice.Chang@Sun.COM 	envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE");
141812186SJanice.Chang@Sun.COM 
141912186SJanice.Chang@Sun.COM 	if (envp == NULL) {
142012186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, "
142112186SJanice.Chang@Sun.COM 		    "defaulting to recursive");
142212186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_zfs_mode = 'r';
142312186SJanice.Chang@Sun.COM 		return (0);
142412186SJanice.Chang@Sun.COM 	}
142512186SJanice.Chang@Sun.COM 
142612186SJanice.Chang@Sun.COM 	if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) {
142712186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_zfs_mode = 'd';
142812186SJanice.Chang@Sun.COM 	} else if ((strcmp(envp, "recursive") == 0) ||
142912186SJanice.Chang@Sun.COM 	    (strcmp(envp, "r") == 0)) {
143012186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_zfs_mode = 'r';
143112186SJanice.Chang@Sun.COM 	} else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) {
143212186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_zfs_mode = 'p';
143312186SJanice.Chang@Sun.COM 	} else {
143412186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
143512186SJanice.Chang@Sun.COM 		    "Invalid ZFS_MODE value \"%s\".\n", envp);
143612186SJanice.Chang@Sun.COM 		return (-1);
143712186SJanice.Chang@Sun.COM 	}
143812186SJanice.Chang@Sun.COM 
143912186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"",
144012186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_zfs_mode);
144112186SJanice.Chang@Sun.COM 
144212186SJanice.Chang@Sun.COM 	return (0);
144312186SJanice.Chang@Sun.COM }
144412186SJanice.Chang@Sun.COM 
144512186SJanice.Chang@Sun.COM static int
144612186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args)
144712186SJanice.Chang@Sun.COM {
144812186SJanice.Chang@Sun.COM 	char *envp_force;
144912186SJanice.Chang@Sun.COM 
145012186SJanice.Chang@Sun.COM 	envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE");
145112186SJanice.Chang@Sun.COM 
145212186SJanice.Chang@Sun.COM 	if (envp_force == NULL) {
145312186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG,
145412186SJanice.Chang@Sun.COM 		    "env(ZFS_FORCE) not specified, defaulting to FALSE");
145512186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_zfs_force = B_FALSE;
145612186SJanice.Chang@Sun.COM 		return (0);
145712186SJanice.Chang@Sun.COM 	}
145812186SJanice.Chang@Sun.COM 
145912186SJanice.Chang@Sun.COM 	/*
146012186SJanice.Chang@Sun.COM 	 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
146112186SJanice.Chang@Sun.COM 	 */
146212186SJanice.Chang@Sun.COM 
146312186SJanice.Chang@Sun.COM 	if (strchr("tTyY", *envp_force))
146412186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_zfs_force = B_TRUE;
146512186SJanice.Chang@Sun.COM 
146612186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force);
146712186SJanice.Chang@Sun.COM 
146812186SJanice.Chang@Sun.COM 	return (0);
146912186SJanice.Chang@Sun.COM }
147012186SJanice.Chang@Sun.COM 
147112186SJanice.Chang@Sun.COM static int
147212186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args)
147312186SJanice.Chang@Sun.COM {
147412186SJanice.Chang@Sun.COM 	char *envp;
147512186SJanice.Chang@Sun.COM 
147612186SJanice.Chang@Sun.COM 	envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL");
147712186SJanice.Chang@Sun.COM 
147812186SJanice.Chang@Sun.COM 	if (envp == NULL) {
147912186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, "
148012186SJanice.Chang@Sun.COM 		    "defaulting to 0");
148112186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_level = 0;
148212186SJanice.Chang@Sun.COM 		return (0);
148312186SJanice.Chang@Sun.COM 	}
148412186SJanice.Chang@Sun.COM 
148512186SJanice.Chang@Sun.COM 	if (envp[1] != '\0') {
148612186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
148712186SJanice.Chang@Sun.COM 		    "Invalid backup level \"%s\".\n", envp);
148812186SJanice.Chang@Sun.COM 		return (-1);
148912186SJanice.Chang@Sun.COM 	}
149012186SJanice.Chang@Sun.COM 
149112186SJanice.Chang@Sun.COM 	if (!isdigit(*envp)) {
149212186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
149312186SJanice.Chang@Sun.COM 		    "Invalid backup level \"%s\".\n", envp);
149412186SJanice.Chang@Sun.COM 		return (-1);
149512186SJanice.Chang@Sun.COM 	}
149612186SJanice.Chang@Sun.COM 
149712186SJanice.Chang@Sun.COM 	ndmpd_zfs_args->nz_level = atoi(envp);
149812186SJanice.Chang@Sun.COM 
149912186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"",
150012186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_level);
150112186SJanice.Chang@Sun.COM 
150212186SJanice.Chang@Sun.COM 	return (0);
150312186SJanice.Chang@Sun.COM }
150412186SJanice.Chang@Sun.COM 
150512186SJanice.Chang@Sun.COM static int
150612186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args)
150712186SJanice.Chang@Sun.COM {
150812186SJanice.Chang@Sun.COM 	char *envp_update;
150912186SJanice.Chang@Sun.COM 
151012186SJanice.Chang@Sun.COM 	envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE");
151112186SJanice.Chang@Sun.COM 
151212186SJanice.Chang@Sun.COM 	if (envp_update == NULL) {
151312186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG,
151412186SJanice.Chang@Sun.COM 		    "env(UPDATE) not specified, defaulting to TRUE");
151512186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_update = B_TRUE;
151612186SJanice.Chang@Sun.COM 		return (0);
151712186SJanice.Chang@Sun.COM 	}
151812186SJanice.Chang@Sun.COM 
151912186SJanice.Chang@Sun.COM 	/*
152012186SJanice.Chang@Sun.COM 	 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
152112186SJanice.Chang@Sun.COM 	 */
152212186SJanice.Chang@Sun.COM 
152312186SJanice.Chang@Sun.COM 	if (strchr("tTyY", *envp_update))
152412186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_update = B_TRUE;
152512186SJanice.Chang@Sun.COM 
152612186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update);
152712186SJanice.Chang@Sun.COM 
152812186SJanice.Chang@Sun.COM 	return (0);
152912186SJanice.Chang@Sun.COM }
153012186SJanice.Chang@Sun.COM 
153112186SJanice.Chang@Sun.COM static int
153212186SJanice.Chang@Sun.COM ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args)
153312186SJanice.Chang@Sun.COM {
153412186SJanice.Chang@Sun.COM 	char *envp;
153512186SJanice.Chang@Sun.COM 
153612186SJanice.Chang@Sun.COM 	envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME");
153712186SJanice.Chang@Sun.COM 
153812186SJanice.Chang@Sun.COM 	if (envp == NULL) {
153912186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG,
154012186SJanice.Chang@Sun.COM 		    "env(DMP_NAME) not specified, defaulting to 'level'");
154112186SJanice.Chang@Sun.COM 		(void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level",
154212186SJanice.Chang@Sun.COM 		    NDMPD_ZFS_DMP_NAME_MAX);
154312186SJanice.Chang@Sun.COM 		return (0);
154412186SJanice.Chang@Sun.COM 	}
154512186SJanice.Chang@Sun.COM 
154612186SJanice.Chang@Sun.COM 	if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp))
154712186SJanice.Chang@Sun.COM 		return (-1);
154812186SJanice.Chang@Sun.COM 
154912186SJanice.Chang@Sun.COM 	(void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp,
155012186SJanice.Chang@Sun.COM 	    NDMPD_ZFS_DMP_NAME_MAX);
155112186SJanice.Chang@Sun.COM 
155212186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp);
155312186SJanice.Chang@Sun.COM 
155412186SJanice.Chang@Sun.COM 	return (0);
155512186SJanice.Chang@Sun.COM }
155612186SJanice.Chang@Sun.COM 
155712186SJanice.Chang@Sun.COM /*
155812186SJanice.Chang@Sun.COM  * ndmpd_zfs_dmp_name_valid()
155912186SJanice.Chang@Sun.COM  *
156012186SJanice.Chang@Sun.COM  * This function verifies that the dmp_name is valid.
156112186SJanice.Chang@Sun.COM  *
156212186SJanice.Chang@Sun.COM  * The dmp_name is restricted to alphanumeric characters plus
156312186SJanice.Chang@Sun.COM  * the underscore and hyphen, and must be 31 characters or less.
156412186SJanice.Chang@Sun.COM  * This is due to its use in the NDMPD_ZFS_PROP_INCR property
156512186SJanice.Chang@Sun.COM  * and in the ZFS snapshot name (if an ndmpd-generated snapshot
156612186SJanice.Chang@Sun.COM  * is required).
156712186SJanice.Chang@Sun.COM  */
156812186SJanice.Chang@Sun.COM 
156912186SJanice.Chang@Sun.COM static boolean_t
157012186SJanice.Chang@Sun.COM ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name)
157112186SJanice.Chang@Sun.COM {
157212186SJanice.Chang@Sun.COM 	char *c;
157312186SJanice.Chang@Sun.COM 
157412186SJanice.Chang@Sun.COM 	if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) {
157512186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
157612186SJanice.Chang@Sun.COM 		    "DMP_NAME %s is longer than %d\n",
157712186SJanice.Chang@Sun.COM 		    dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1);
157812186SJanice.Chang@Sun.COM 		return (B_FALSE);
157912186SJanice.Chang@Sun.COM 	}
158012186SJanice.Chang@Sun.COM 
158112186SJanice.Chang@Sun.COM 	for (c = dmp_name; *c != '\0'; c++) {
158212186SJanice.Chang@Sun.COM 		if (!isalpha(*c) && !isdigit(*c) &&
158312186SJanice.Chang@Sun.COM 		    (*c != '_') && (*c != '-')) {
158412186SJanice.Chang@Sun.COM 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
158512186SJanice.Chang@Sun.COM 			    "DMP_NAME %s contains illegal character %c\n",
158612186SJanice.Chang@Sun.COM 			    dmp_name, *c);
158712186SJanice.Chang@Sun.COM 			return (B_FALSE);
158812186SJanice.Chang@Sun.COM 		}
158912186SJanice.Chang@Sun.COM 	}
159012186SJanice.Chang@Sun.COM 
159112186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name);
159212186SJanice.Chang@Sun.COM 	return (B_TRUE);
159312186SJanice.Chang@Sun.COM }
159412186SJanice.Chang@Sun.COM 
159512186SJanice.Chang@Sun.COM /*
159612186SJanice.Chang@Sun.COM  * ndmpd_zfs_is_incremental()
159712186SJanice.Chang@Sun.COM  *
159812186SJanice.Chang@Sun.COM  * This can only be called after ndmpd_zfs_getenv_level()
159912186SJanice.Chang@Sun.COM  * has been called.
160012186SJanice.Chang@Sun.COM  */
160112186SJanice.Chang@Sun.COM 
160212186SJanice.Chang@Sun.COM static boolean_t
160312186SJanice.Chang@Sun.COM ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args)
160412186SJanice.Chang@Sun.COM {
160512186SJanice.Chang@Sun.COM 	return (ndmpd_zfs_args->nz_level != 0);
160612186SJanice.Chang@Sun.COM }
160712186SJanice.Chang@Sun.COM 
160812186SJanice.Chang@Sun.COM /*
160912186SJanice.Chang@Sun.COM  * ndmpd_zfs_snapshot_prepare()
161012186SJanice.Chang@Sun.COM  *
161112186SJanice.Chang@Sun.COM  * If no snapshot was supplied by the user, create a snapshot
161212186SJanice.Chang@Sun.COM  * for use by ndmpd.
161312186SJanice.Chang@Sun.COM  */
161412186SJanice.Chang@Sun.COM 
161512186SJanice.Chang@Sun.COM static int
161612186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args)
161712186SJanice.Chang@Sun.COM {
161812186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
161912186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
162012186SJanice.Chang@Sun.COM 	boolean_t recursive = B_FALSE;
162112186SJanice.Chang@Sun.COM 	int zfs_err = 0;
162212186SJanice.Chang@Sun.COM 
162312186SJanice.Chang@Sun.COM 	if (session->ns_data.dd_abort) {
162412186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
162512186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset);
162612186SJanice.Chang@Sun.COM 		return (-1);
162712186SJanice.Chang@Sun.COM 	}
162812186SJanice.Chang@Sun.COM 
162912186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_args->nz_snapname[0] == '\0') {
163012186SJanice.Chang@Sun.COM 		ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE;
163112186SJanice.Chang@Sun.COM 
163212186SJanice.Chang@Sun.COM 		if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) {
163312186SJanice.Chang@Sun.COM 			ndmpd_zfs_args->nz_snapname[0] = '\0';
163412186SJanice.Chang@Sun.COM 
163512186SJanice.Chang@Sun.COM 			ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
163612186SJanice.Chang@Sun.COM 			    "Error creating snapshot for %s\n",
163712186SJanice.Chang@Sun.COM 			    ndmpd_zfs_args->nz_dataset);
163812186SJanice.Chang@Sun.COM 
163912186SJanice.Chang@Sun.COM 			return (-1);
164012186SJanice.Chang@Sun.COM 		}
164112186SJanice.Chang@Sun.COM 	}
164212186SJanice.Chang@Sun.COM 
164312186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) {
164412186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG,
164512186SJanice.Chang@Sun.COM 		    "ndmpd_zfs_snapshot_prop_add error\n");
164612186SJanice.Chang@Sun.COM 
164712186SJanice.Chang@Sun.COM 		if (ndmpd_zfs_args->nz_ndmpd_snap) {
164812186SJanice.Chang@Sun.COM 
164912186SJanice.Chang@Sun.COM 			if (ndmpd_zfs_args->nz_zfs_mode != 'd')
165012186SJanice.Chang@Sun.COM 				recursive = B_TRUE;
165112186SJanice.Chang@Sun.COM 
165212186SJanice.Chang@Sun.COM 			(void) snapshot_destroy(ndmpd_zfs_args->nz_dataset,
165312186SJanice.Chang@Sun.COM 			    ndmpd_zfs_args->nz_snapname, recursive, &zfs_err);
165412186SJanice.Chang@Sun.COM 		}
165512186SJanice.Chang@Sun.COM 
165612186SJanice.Chang@Sun.COM 		return (-1);
165712186SJanice.Chang@Sun.COM 	}
165812186SJanice.Chang@Sun.COM 
165912186SJanice.Chang@Sun.COM 	return (0);
166012186SJanice.Chang@Sun.COM }
166112186SJanice.Chang@Sun.COM 
166212186SJanice.Chang@Sun.COM /*
166312186SJanice.Chang@Sun.COM  * ndmpd_zfs_snapshot_cleanup()
166412186SJanice.Chang@Sun.COM  *
166512186SJanice.Chang@Sun.COM  * If UPDATE = y, find the old snapshot (if any) corresponding to
166612186SJanice.Chang@Sun.COM  * {LEVEL, DMPNAME, ZFS_MODE}. If it was ndmpd-generated,
166712186SJanice.Chang@Sun.COM  * remove the snapshot.  Otherwise, update its NDMPD_ZFS_PROP_INCR
166812186SJanice.Chang@Sun.COM  * property to remove {L, D, Z}.
166912186SJanice.Chang@Sun.COM  *
167012186SJanice.Chang@Sun.COM  * If UPDATE = n, if an ndmpd-generated snapshot was used for backup,
167112186SJanice.Chang@Sun.COM  * remove the snapshot.  Otherwise, update its NDMPD_ZFS_PROP_INCR
167212186SJanice.Chang@Sun.COM  * property to remove {L, D, Z}.
167312186SJanice.Chang@Sun.COM  */
167412186SJanice.Chang@Sun.COM 
167512186SJanice.Chang@Sun.COM static int
167612186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err)
167712186SJanice.Chang@Sun.COM {
167812186SJanice.Chang@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)
167912186SJanice.Chang@Sun.COM 	    (ndmpd_zfs_params->mp_daemon_cookie);
168012186SJanice.Chang@Sun.COM 	ndmpd_zfs_snapfind_t snapdata;
168112186SJanice.Chang@Sun.COM 	boolean_t ndmpd_generated = B_FALSE;
168212186SJanice.Chang@Sun.COM 
168312186SJanice.Chang@Sun.COM 	bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t));
168412186SJanice.Chang@Sun.COM 
168512186SJanice.Chang@Sun.COM 	(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
168612186SJanice.Chang@Sun.COM 	    snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE);
168712186SJanice.Chang@Sun.COM 
168812186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) {
168912186SJanice.Chang@Sun.COM 		/*
169012186SJanice.Chang@Sun.COM 		 * Find the existing snapshot, if any, to "unuse."
169112186SJanice.Chang@Sun.COM 		 * Indicate that the current snapshot used for backup
169212186SJanice.Chang@Sun.COM 		 * should be skipped in the search.  (The search is
169312186SJanice.Chang@Sun.COM 		 * sorted by creation time but this cannot be relied
169412186SJanice.Chang@Sun.COM 		 * upon for user-supplied snapshots.)
169512186SJanice.Chang@Sun.COM 		 */
169612186SJanice.Chang@Sun.COM 
169712186SJanice.Chang@Sun.COM 		(void) snprintf(snapdata.nzs_snapskip, ZFS_MAXNAMELEN, "%s",
169812186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_snapname);
169912186SJanice.Chang@Sun.COM 
170012186SJanice.Chang@Sun.COM 		if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) {
170112186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n");
170212186SJanice.Chang@Sun.COM 			goto _remove_tmp_snap;
170312186SJanice.Chang@Sun.COM 		}
170412186SJanice.Chang@Sun.COM 
170512186SJanice.Chang@Sun.COM 		if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */
170612186SJanice.Chang@Sun.COM 			ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated
170712186SJanice.Chang@Sun.COM 			    (snapdata.nzs_snapprop);
170812186SJanice.Chang@Sun.COM 
170912186SJanice.Chang@Sun.COM 			if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
171012186SJanice.Chang@Sun.COM 			    ndmpd_generated, &snapdata) != 0) {
171112186SJanice.Chang@Sun.COM 				NDMP_LOG(LOG_DEBUG,
171212186SJanice.Chang@Sun.COM 				    "ndmpd_zfs_snapshot_unuse error\n");
171312186SJanice.Chang@Sun.COM 				goto _remove_tmp_snap;
171412186SJanice.Chang@Sun.COM 			}
171512186SJanice.Chang@Sun.COM 		}
171612186SJanice.Chang@Sun.COM 
171712186SJanice.Chang@Sun.COM 		if (session->ns_data.dd_abort)
171812186SJanice.Chang@Sun.COM 			goto _remove_tmp_snap;
171912186SJanice.Chang@Sun.COM 
172012186SJanice.Chang@Sun.COM 		return (0);
172112186SJanice.Chang@Sun.COM 	}
172212186SJanice.Chang@Sun.COM 
172312186SJanice.Chang@Sun.COM _remove_tmp_snap:
172412186SJanice.Chang@Sun.COM 
172512186SJanice.Chang@Sun.COM 	(void) snprintf(snapdata.nzs_snapname, ZFS_MAXNAMELEN, "%s",
172612186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_snapname);
172712186SJanice.Chang@Sun.COM 
172812186SJanice.Chang@Sun.COM 	(void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop,
172912186SJanice.Chang@Sun.COM 	    ZFS_MAXPROPLEN);
173012186SJanice.Chang@Sun.COM 
173112186SJanice.Chang@Sun.COM 	snapdata.nzs_snapskip[0] = '\0';
173212186SJanice.Chang@Sun.COM 
173312186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
173412186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) {
173512186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n");
173612186SJanice.Chang@Sun.COM 		return (-1);
173712186SJanice.Chang@Sun.COM 	}
173812186SJanice.Chang@Sun.COM 
173912186SJanice.Chang@Sun.COM 	if (!ndmpd_zfs_args->nz_update)
174012186SJanice.Chang@Sun.COM 		return (0);
174112186SJanice.Chang@Sun.COM 
174212186SJanice.Chang@Sun.COM 	return (-1);
174312186SJanice.Chang@Sun.COM }
174412186SJanice.Chang@Sun.COM 
174512186SJanice.Chang@Sun.COM static int
174612186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args)
174712186SJanice.Chang@Sun.COM {
174812186SJanice.Chang@Sun.COM 	boolean_t recursive = B_FALSE;
174912186SJanice.Chang@Sun.COM 
175012186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_snapname_create(ndmpd_zfs_args,
175112186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_snapname, ZFS_MAXNAMELEN -1) < 0) {
175212186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s",
175312186SJanice.Chang@Sun.COM 		    errno, ndmpd_zfs_args->nz_dataset);
175412186SJanice.Chang@Sun.COM 		return (-1);
175512186SJanice.Chang@Sun.COM 	}
175612186SJanice.Chang@Sun.COM 
175712186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_args->nz_zfs_mode != 'd')
175812186SJanice.Chang@Sun.COM 		recursive = B_TRUE;
175912186SJanice.Chang@Sun.COM 
176012186SJanice.Chang@Sun.COM 	if (snapshot_create(ndmpd_zfs_args->nz_dataset,
176112186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_snapname, recursive) != 0) {
176212186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s",
176312186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
176412186SJanice.Chang@Sun.COM 		return (-1);
176512186SJanice.Chang@Sun.COM 	}
176612186SJanice.Chang@Sun.COM 
176712186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s",
176812186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
176912186SJanice.Chang@Sun.COM 
177012186SJanice.Chang@Sun.COM 	return (0);
177112186SJanice.Chang@Sun.COM }
177212186SJanice.Chang@Sun.COM 
177312186SJanice.Chang@Sun.COM /*
177412186SJanice.Chang@Sun.COM  * ndmpd_zfs_snapshot_unuse()
177512186SJanice.Chang@Sun.COM  *
177612186SJanice.Chang@Sun.COM  * Given a pre-existing snapshot of the given {L, D, Z}:
177712186SJanice.Chang@Sun.COM  * If snapshot is ndmpd-generated, remove snapshot.
177812186SJanice.Chang@Sun.COM  * If not ndmpd-generated, or if the ndmpd-generated snapshot
177912186SJanice.Chang@Sun.COM  * cannot be destroyed, remove the {L, D, Z} substring from the
178012186SJanice.Chang@Sun.COM  * snapshot's NDMPD_ZFS_PROP_INCR property.
178112186SJanice.Chang@Sun.COM  *
178212186SJanice.Chang@Sun.COM  * In the event of a failure, it may be that two snapshots will
178312186SJanice.Chang@Sun.COM  * have the {L, D, Z} property set on them.  This is not desirable,
178412186SJanice.Chang@Sun.COM  * so return an error and log the failure.
178512186SJanice.Chang@Sun.COM  */
178612186SJanice.Chang@Sun.COM 
178712186SJanice.Chang@Sun.COM static int
178812186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args,
178912186SJanice.Chang@Sun.COM     boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p)
179012186SJanice.Chang@Sun.COM {
179112186SJanice.Chang@Sun.COM 	boolean_t recursive = B_FALSE;
179212186SJanice.Chang@Sun.COM 	int zfs_err = 0;
179312186SJanice.Chang@Sun.COM 	int err = 0;
179412186SJanice.Chang@Sun.COM 
179512186SJanice.Chang@Sun.COM 	if (ndmpd_generated) {
179612186SJanice.Chang@Sun.COM 		if (ndmpd_zfs_args->nz_zfs_mode != 'd')
179712186SJanice.Chang@Sun.COM 			recursive = B_TRUE;
179812186SJanice.Chang@Sun.COM 
179912186SJanice.Chang@Sun.COM 		err = snapshot_destroy(ndmpd_zfs_args->nz_dataset,
180012186SJanice.Chang@Sun.COM 		    snapdata_p->nzs_snapname, recursive, &zfs_err);
180112186SJanice.Chang@Sun.COM 
180212186SJanice.Chang@Sun.COM 		if (err) {
180312186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;"
180412186SJanice.Chang@Sun.COM 			    " err: %d; zfs_err: %d",
180512186SJanice.Chang@Sun.COM 			    ndmpd_zfs_args->nz_dataset,
180612186SJanice.Chang@Sun.COM 			    snapdata_p->nzs_snapname, err, zfs_err);
180712186SJanice.Chang@Sun.COM 			return (-1);
180812186SJanice.Chang@Sun.COM 		}
180912186SJanice.Chang@Sun.COM 	}
181012186SJanice.Chang@Sun.COM 
181112186SJanice.Chang@Sun.COM 	if (!ndmpd_generated || zfs_err) {
181212186SJanice.Chang@Sun.COM 		if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p))
181312186SJanice.Chang@Sun.COM 			return (-1);
181412186SJanice.Chang@Sun.COM 	}
181512186SJanice.Chang@Sun.COM 
181612186SJanice.Chang@Sun.COM 	return (0);
181712186SJanice.Chang@Sun.COM }
181812186SJanice.Chang@Sun.COM 
181912186SJanice.Chang@Sun.COM static boolean_t
182012186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop)
182112186SJanice.Chang@Sun.COM {
182212186SJanice.Chang@Sun.COM 	char origin;
182312186SJanice.Chang@Sun.COM 
182412186SJanice.Chang@Sun.COM 	(void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin);
182512186SJanice.Chang@Sun.COM 
182612186SJanice.Chang@Sun.COM 	return (origin == 'n');
182712186SJanice.Chang@Sun.COM }
182812186SJanice.Chang@Sun.COM 
182912186SJanice.Chang@Sun.COM /*
183012186SJanice.Chang@Sun.COM  * ndmpd_zfs_snapshot_find()
183112186SJanice.Chang@Sun.COM  *
183212186SJanice.Chang@Sun.COM  * Find a snapshot with a particular value for
183312186SJanice.Chang@Sun.COM  * the NDMPD_ZFS_PROP_INCR property.
183412186SJanice.Chang@Sun.COM  */
183512186SJanice.Chang@Sun.COM 
183612186SJanice.Chang@Sun.COM static int
183712186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args,
183812186SJanice.Chang@Sun.COM     ndmpd_zfs_snapfind_t *snapdata)
183912186SJanice.Chang@Sun.COM {
184012186SJanice.Chang@Sun.COM 	zfs_handle_t *zhp;
184112186SJanice.Chang@Sun.COM 	int err;
184212186SJanice.Chang@Sun.COM 
184312186SJanice.Chang@Sun.COM 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
184412186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_type);
184512186SJanice.Chang@Sun.COM 
184612186SJanice.Chang@Sun.COM 	if (!zhp) {
184712186SJanice.Chang@Sun.COM 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
184812186SJanice.Chang@Sun.COM 		return (-1);
184912186SJanice.Chang@Sun.COM 	}
185012186SJanice.Chang@Sun.COM 
185112186SJanice.Chang@Sun.COM 	err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find,
185212186SJanice.Chang@Sun.COM 	    snapdata);
185312186SJanice.Chang@Sun.COM 
185412186SJanice.Chang@Sun.COM 	zfs_close(zhp);
185512186SJanice.Chang@Sun.COM 
185612186SJanice.Chang@Sun.COM 	if (err) {
185712186SJanice.Chang@Sun.COM 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d",
185812186SJanice.Chang@Sun.COM 		    err);
185912186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
186012186SJanice.Chang@Sun.COM 		    "Error iterating snapshots\n");
186112186SJanice.Chang@Sun.COM 		return (-1);
186212186SJanice.Chang@Sun.COM 	}
186312186SJanice.Chang@Sun.COM 
186412186SJanice.Chang@Sun.COM 	return (0);
186512186SJanice.Chang@Sun.COM }
186612186SJanice.Chang@Sun.COM 
186712186SJanice.Chang@Sun.COM /*
186812186SJanice.Chang@Sun.COM  * ndmpd_zfs_snapshot_prop_find()
186912186SJanice.Chang@Sun.COM  *
187012186SJanice.Chang@Sun.COM  * Find a snapshot with a particular value for
187112186SJanice.Chang@Sun.COM  * NDMPD_ZFS_PROP_INCR.  Fill in data for the first one
187212186SJanice.Chang@Sun.COM  * found (sorted by creation time).  However, skip the
187312186SJanice.Chang@Sun.COM  * the snapshot indicated in nzs_snapskip, if any.
187412186SJanice.Chang@Sun.COM  */
187512186SJanice.Chang@Sun.COM 
187612186SJanice.Chang@Sun.COM static int
187712186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg)
187812186SJanice.Chang@Sun.COM {
187912186SJanice.Chang@Sun.COM 	ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg;
188012186SJanice.Chang@Sun.COM 	char propstr[ZFS_MAXPROPLEN];
188112186SJanice.Chang@Sun.COM 	char findprop_plus_slash[ZFS_MAXPROPLEN];
188212186SJanice.Chang@Sun.COM 	char *justsnap;
188312186SJanice.Chang@Sun.COM 	int err = 0;
188412186SJanice.Chang@Sun.COM 
188512186SJanice.Chang@Sun.COM 	if (snapdata_p->nzs_snapname[0] != '\0') {
188612186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s",
188712186SJanice.Chang@Sun.COM 		    (char *)zfs_get_name(zhp));
188812186SJanice.Chang@Sun.COM 		goto _done;
188912186SJanice.Chang@Sun.COM 	}
189012186SJanice.Chang@Sun.COM 
189112186SJanice.Chang@Sun.COM 	err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
189212186SJanice.Chang@Sun.COM 
189312186SJanice.Chang@Sun.COM 	if (err) {
189412186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed");
189512186SJanice.Chang@Sun.COM 		goto _done;
189612186SJanice.Chang@Sun.COM 	}
189712186SJanice.Chang@Sun.COM 
189812186SJanice.Chang@Sun.COM 	if (propstr[0] == '\0') {
189912186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set",
190012186SJanice.Chang@Sun.COM 		    (char *)zfs_get_name(zhp));
190112186SJanice.Chang@Sun.COM 		goto _done;
190212186SJanice.Chang@Sun.COM 	}
190312186SJanice.Chang@Sun.COM 
190412186SJanice.Chang@Sun.COM 	(void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
190512186SJanice.Chang@Sun.COM 	    snapdata_p->nzs_findprop);
190612186SJanice.Chang@Sun.COM 
190712186SJanice.Chang@Sun.COM 	if (!strstr((const char *)propstr,
190812186SJanice.Chang@Sun.COM 	    (const char *)findprop_plus_slash)) {
190912186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)",
191012186SJanice.Chang@Sun.COM 		    (char *)zfs_get_name(zhp), propstr,
191112186SJanice.Chang@Sun.COM 		    snapdata_p->nzs_findprop);
191212186SJanice.Chang@Sun.COM 		goto _done;
191312186SJanice.Chang@Sun.COM 	}
191412186SJanice.Chang@Sun.COM 
191512186SJanice.Chang@Sun.COM 	if (!ndmpd_zfs_prop_version_check(propstr,
191612186SJanice.Chang@Sun.COM 	    &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) {
191712186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)",
191812186SJanice.Chang@Sun.COM 		    (char *)zfs_get_name(zhp),  propstr,
191912186SJanice.Chang@Sun.COM 		    snapdata_p->nzs_findprop);
192012186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "did not pass version check");
192112186SJanice.Chang@Sun.COM 		goto _done;
192212186SJanice.Chang@Sun.COM 	}
192312186SJanice.Chang@Sun.COM 
192412186SJanice.Chang@Sun.COM 	justsnap = strchr(zfs_get_name(zhp), '@') + 1;
192512186SJanice.Chang@Sun.COM 
192612186SJanice.Chang@Sun.COM 	if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) {
192712186SJanice.Chang@Sun.COM 		(void) strlcpy(snapdata_p->nzs_snapname, justsnap,
192812186SJanice.Chang@Sun.COM 		    ZFS_MAXNAMELEN);
192912186SJanice.Chang@Sun.COM 
193012186SJanice.Chang@Sun.COM 		(void) strlcpy(snapdata_p->nzs_snapprop, propstr,
193112186SJanice.Chang@Sun.COM 		    ZFS_MAXPROPLEN);
193212186SJanice.Chang@Sun.COM 
193312186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n",
193412186SJanice.Chang@Sun.COM 		    snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop);
193512186SJanice.Chang@Sun.COM 	}
193612186SJanice.Chang@Sun.COM 
193712186SJanice.Chang@Sun.COM _done:
193812186SJanice.Chang@Sun.COM 	zfs_close(zhp);
193912186SJanice.Chang@Sun.COM 	return (err);
194012186SJanice.Chang@Sun.COM }
194112186SJanice.Chang@Sun.COM 
194212186SJanice.Chang@Sun.COM /*
194312186SJanice.Chang@Sun.COM  * ndmpd_zfs_snapshot_prop_get()
194412186SJanice.Chang@Sun.COM  *
194512186SJanice.Chang@Sun.COM  * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot
194612186SJanice.Chang@Sun.COM  */
194712186SJanice.Chang@Sun.COM 
194812186SJanice.Chang@Sun.COM static int
194912186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr)
195012186SJanice.Chang@Sun.COM {
195112186SJanice.Chang@Sun.COM 	nvlist_t *userprop;
195212186SJanice.Chang@Sun.COM 	nvlist_t *propval;
195312186SJanice.Chang@Sun.COM 	char *strval;
195412186SJanice.Chang@Sun.COM 	int err;
195512186SJanice.Chang@Sun.COM 
195612186SJanice.Chang@Sun.COM 	propstr[0] = '\0';
195712186SJanice.Chang@Sun.COM 
195812186SJanice.Chang@Sun.COM 	userprop = zfs_get_user_props(zhp);
195912186SJanice.Chang@Sun.COM 
196012186SJanice.Chang@Sun.COM 	if (userprop == NULL)
196112186SJanice.Chang@Sun.COM 		return (0);
196212186SJanice.Chang@Sun.COM 
196312186SJanice.Chang@Sun.COM 	err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval);
196412186SJanice.Chang@Sun.COM 
196512186SJanice.Chang@Sun.COM 	if (err != 0) {
196612186SJanice.Chang@Sun.COM 		if (err == ENOENT)
196712186SJanice.Chang@Sun.COM 			return (0);
196812186SJanice.Chang@Sun.COM 
196912186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err);
197012186SJanice.Chang@Sun.COM 
197112186SJanice.Chang@Sun.COM 		return (-1);
197212186SJanice.Chang@Sun.COM 	}
197312186SJanice.Chang@Sun.COM 
197412186SJanice.Chang@Sun.COM 	err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
197512186SJanice.Chang@Sun.COM 
197612186SJanice.Chang@Sun.COM 	if (err != 0) {
197712186SJanice.Chang@Sun.COM 		if (err == ENOENT)
197812186SJanice.Chang@Sun.COM 			return (0);
197912186SJanice.Chang@Sun.COM 
198012186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err);
198112186SJanice.Chang@Sun.COM 
198212186SJanice.Chang@Sun.COM 		return (-1);
198312186SJanice.Chang@Sun.COM 	}
198412186SJanice.Chang@Sun.COM 
198512186SJanice.Chang@Sun.COM 	(void) strlcpy(propstr, strval, ZFS_MAXPROPLEN);
198612186SJanice.Chang@Sun.COM 
198712186SJanice.Chang@Sun.COM 	return (0);
198812186SJanice.Chang@Sun.COM }
198912186SJanice.Chang@Sun.COM 
199012186SJanice.Chang@Sun.COM /*
199112186SJanice.Chang@Sun.COM  * ndmpd_zfs_snapshot_prop_add()
199212186SJanice.Chang@Sun.COM  *
199312186SJanice.Chang@Sun.COM  * Update snapshot's NDMPD_ZFS_PROP_INCR property with
199412186SJanice.Chang@Sun.COM  * the current LEVEL, DMPNAME, and ZFSMODE values
199512186SJanice.Chang@Sun.COM  * (add property if it doesn't exist)
199612186SJanice.Chang@Sun.COM  */
199712186SJanice.Chang@Sun.COM 
199812186SJanice.Chang@Sun.COM static int
199912186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args)
200012186SJanice.Chang@Sun.COM {
200112186SJanice.Chang@Sun.COM 	char fullname[ZFS_MAXNAMELEN];
200212186SJanice.Chang@Sun.COM 	char propstr[ZFS_MAXPROPLEN];
200312186SJanice.Chang@Sun.COM 	zfs_handle_t *zhp;
200412186SJanice.Chang@Sun.COM 	boolean_t set;
200512186SJanice.Chang@Sun.COM 	int err;
200612186SJanice.Chang@Sun.COM 
200712186SJanice.Chang@Sun.COM 	(void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s",
200812186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_dataset,
200912186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_snapname);
201012186SJanice.Chang@Sun.COM 
201112186SJanice.Chang@Sun.COM 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
201212186SJanice.Chang@Sun.COM 
201312186SJanice.Chang@Sun.COM 	if (!zhp) {
201412186SJanice.Chang@Sun.COM 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)");
201512186SJanice.Chang@Sun.COM 		return (-1);
201612186SJanice.Chang@Sun.COM 	}
201712186SJanice.Chang@Sun.COM 
201812186SJanice.Chang@Sun.COM 	bzero(propstr, ZFS_MAXPROPLEN);
201912186SJanice.Chang@Sun.COM 
202012186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) {
202112186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "error getting property");
202212186SJanice.Chang@Sun.COM 		zfs_close(zhp);
202312186SJanice.Chang@Sun.COM 		return (-1);
202412186SJanice.Chang@Sun.COM 	}
202512186SJanice.Chang@Sun.COM 
202612186SJanice.Chang@Sun.COM 	if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) {
202712186SJanice.Chang@Sun.COM 		zfs_close(zhp);
202812186SJanice.Chang@Sun.COM 		return (-1);
202912186SJanice.Chang@Sun.COM 	}
203012186SJanice.Chang@Sun.COM 
203112186SJanice.Chang@Sun.COM 	if (set) {
203212186SJanice.Chang@Sun.COM 		err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr);
203312186SJanice.Chang@Sun.COM 		if (err) {
203412186SJanice.Chang@Sun.COM 			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
203512186SJanice.Chang@Sun.COM 			    err);
203612186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_ERR, "error setting property %s",
203712186SJanice.Chang@Sun.COM 			    propstr);
203812186SJanice.Chang@Sun.COM 			zfs_close(zhp);
203912186SJanice.Chang@Sun.COM 			return (-1);
204012186SJanice.Chang@Sun.COM 		}
204112186SJanice.Chang@Sun.COM 	}
204212186SJanice.Chang@Sun.COM 
204312186SJanice.Chang@Sun.COM 	zfs_close(zhp);
204412186SJanice.Chang@Sun.COM 
204512186SJanice.Chang@Sun.COM 	(void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN);
204612186SJanice.Chang@Sun.COM 
204712186SJanice.Chang@Sun.COM 	return (0);
204812186SJanice.Chang@Sun.COM }
204912186SJanice.Chang@Sun.COM 
205012186SJanice.Chang@Sun.COM static int
205112186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
205212186SJanice.Chang@Sun.COM     char *propstr, boolean_t *set)
205312186SJanice.Chang@Sun.COM {
205412186SJanice.Chang@Sun.COM 	char subprop[ZFS_MAXPROPLEN];
205512186SJanice.Chang@Sun.COM 
205612186SJanice.Chang@Sun.COM 	*set = B_TRUE;
205712186SJanice.Chang@Sun.COM 
205812186SJanice.Chang@Sun.COM 	(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
205912186SJanice.Chang@Sun.COM 	    subprop, ZFS_MAXPROPLEN, B_FALSE);
206012186SJanice.Chang@Sun.COM 
206112186SJanice.Chang@Sun.COM 	if (propstr[0] == '\0') {
206212186SJanice.Chang@Sun.COM 		(void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s",
206312186SJanice.Chang@Sun.COM 		    NDMPD_ZFS_PROP_MAJOR_VERSION,
206412186SJanice.Chang@Sun.COM 		    NDMPD_ZFS_PROP_MINOR_VERSION,
206512186SJanice.Chang@Sun.COM 		    (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u',
206612186SJanice.Chang@Sun.COM 		    subprop);
206712186SJanice.Chang@Sun.COM 		return (0);
206812186SJanice.Chang@Sun.COM 	}
206912186SJanice.Chang@Sun.COM 
207012186SJanice.Chang@Sun.COM 	if (strstr((const char *)propstr, (const char *)subprop)) {
207112186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists",
207212186SJanice.Chang@Sun.COM 		    subprop);
207312186SJanice.Chang@Sun.COM 		*set = B_FALSE;
207412186SJanice.Chang@Sun.COM 		return (0);
207512186SJanice.Chang@Sun.COM 	}
207612186SJanice.Chang@Sun.COM 
207712186SJanice.Chang@Sun.COM 	if ((strlen(propstr) + strlen(subprop) + 2) >= ZFS_MAXPROPLEN) {
207812186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "snapshot %s: user property "
207912186SJanice.Chang@Sun.COM 		    "%s would overflow; cannot complete operation",
208012186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_snapname,
208112186SJanice.Chang@Sun.COM 		    NDMPD_ZFS_PROP_INCR);
208212186SJanice.Chang@Sun.COM 		return (-1);
208312186SJanice.Chang@Sun.COM 	}
208412186SJanice.Chang@Sun.COM 
208512186SJanice.Chang@Sun.COM 	(void) strlcat(propstr, "/", ZFS_MAXPROPLEN);
208612186SJanice.Chang@Sun.COM 	(void) strlcat(propstr, subprop, ZFS_MAXPROPLEN);
208712186SJanice.Chang@Sun.COM 
208812186SJanice.Chang@Sun.COM 	return (0);
208912186SJanice.Chang@Sun.COM }
209012186SJanice.Chang@Sun.COM 
209112186SJanice.Chang@Sun.COM static int
209212186SJanice.Chang@Sun.COM ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args,
209312186SJanice.Chang@Sun.COM     char *subprop, int len, boolean_t prev_level)
209412186SJanice.Chang@Sun.COM {
209512186SJanice.Chang@Sun.COM 	return (snprintf(subprop, len, "%d.%s.%c",
209612186SJanice.Chang@Sun.COM 	    prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level,
209712186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_dmp_name,
209812186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_zfs_mode));
209912186SJanice.Chang@Sun.COM }
210012186SJanice.Chang@Sun.COM 
210112186SJanice.Chang@Sun.COM /*
210212186SJanice.Chang@Sun.COM  * ndmpd_zfs_snapshot_prop_remove()
210312186SJanice.Chang@Sun.COM  *
210412186SJanice.Chang@Sun.COM  * Remove specified substring from the snapshot's
210512186SJanice.Chang@Sun.COM  * NDMPD_ZFS_PROP_INCR property
210612186SJanice.Chang@Sun.COM  */
210712186SJanice.Chang@Sun.COM 
210812186SJanice.Chang@Sun.COM static int
210912186SJanice.Chang@Sun.COM ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args,
211012186SJanice.Chang@Sun.COM     ndmpd_zfs_snapfind_t *snapdata_p)
211112186SJanice.Chang@Sun.COM {
211212186SJanice.Chang@Sun.COM 	char findprop_plus_slash[ZFS_MAXPROPLEN];
211312186SJanice.Chang@Sun.COM 	char fullname[ZFS_MAXNAMELEN];
211412186SJanice.Chang@Sun.COM 	char newprop[ZFS_MAXPROPLEN];
211512186SJanice.Chang@Sun.COM 	char tmpstr[ZFS_MAXPROPLEN];
211612186SJanice.Chang@Sun.COM 	zfs_handle_t *zhp;
211712186SJanice.Chang@Sun.COM 	char *ptr;
211812186SJanice.Chang@Sun.COM 	int err;
211912186SJanice.Chang@Sun.COM 
212012186SJanice.Chang@Sun.COM 	(void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s",
212112186SJanice.Chang@Sun.COM 	    ndmpd_zfs_args->nz_dataset,
212212186SJanice.Chang@Sun.COM 	    snapdata_p->nzs_snapname);
212312186SJanice.Chang@Sun.COM 
212412186SJanice.Chang@Sun.COM 	zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
212512186SJanice.Chang@Sun.COM 
212612186SJanice.Chang@Sun.COM 	if (!zhp) {
212712186SJanice.Chang@Sun.COM 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
212812186SJanice.Chang@Sun.COM 		return (-1);
212912186SJanice.Chang@Sun.COM 	}
213012186SJanice.Chang@Sun.COM 
213112186SJanice.Chang@Sun.COM 	bzero(newprop, ZFS_MAXPROPLEN);
213212186SJanice.Chang@Sun.COM 
213312186SJanice.Chang@Sun.COM 	/*
213412186SJanice.Chang@Sun.COM 	 * If the substring to be removed is the only {L, D, Z}
213512186SJanice.Chang@Sun.COM 	 * in the property, remove the entire property
213612186SJanice.Chang@Sun.COM 	 */
213712186SJanice.Chang@Sun.COM 
213812186SJanice.Chang@Sun.COM 	tmpstr[0] = '\0';
213912186SJanice.Chang@Sun.COM 
214012186SJanice.Chang@Sun.COM 	(void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr);
214112186SJanice.Chang@Sun.COM 
214212186SJanice.Chang@Sun.COM 	if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) {
214312186SJanice.Chang@Sun.COM 
214412186SJanice.Chang@Sun.COM 		err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
214512186SJanice.Chang@Sun.COM 
214612186SJanice.Chang@Sun.COM 		zfs_close(zhp);
214712186SJanice.Chang@Sun.COM 
214812186SJanice.Chang@Sun.COM 		if (err) {
214912186SJanice.Chang@Sun.COM 			NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
215012186SJanice.Chang@Sun.COM 			    err);
215112186SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_ERR, "error setting property %s", newprop);
215212186SJanice.Chang@Sun.COM 			return (-1);
215312186SJanice.Chang@Sun.COM 		}
215412186SJanice.Chang@Sun.COM 
215512186SJanice.Chang@Sun.COM 		return (0);
215612186SJanice.Chang@Sun.COM 	}
215712186SJanice.Chang@Sun.COM 
215812186SJanice.Chang@Sun.COM 	(void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
215912186SJanice.Chang@Sun.COM 	    snapdata_p->nzs_findprop);
216012186SJanice.Chang@Sun.COM 
216112186SJanice.Chang@Sun.COM 	ptr = strstr((const char *)snapdata_p->nzs_snapprop,
216212186SJanice.Chang@Sun.COM 	    (const char *)findprop_plus_slash);
216312186SJanice.Chang@Sun.COM 
216412186SJanice.Chang@Sun.COM 	if (ptr == NULL) {
216512186SJanice.Chang@Sun.COM 		/*
216612186SJanice.Chang@Sun.COM 		 * This shouldn't happen.  Just return success.
216712186SJanice.Chang@Sun.COM 		 */
216812186SJanice.Chang@Sun.COM 		zfs_close(zhp);
216912186SJanice.Chang@Sun.COM 
217012186SJanice.Chang@Sun.COM 		return (0);
217112186SJanice.Chang@Sun.COM 	}
217212186SJanice.Chang@Sun.COM 
217312186SJanice.Chang@Sun.COM 	/*
217412186SJanice.Chang@Sun.COM 	 * Remove "nzs_findprop" substring from property
217512186SJanice.Chang@Sun.COM 	 *
217612186SJanice.Chang@Sun.COM 	 * Example property:
217712186SJanice.Chang@Sun.COM 	 *	0.0.u/1.bob.p/0.jane.d
217812186SJanice.Chang@Sun.COM 	 *
217912186SJanice.Chang@Sun.COM 	 * Note that there will always be a prefix to the
218012186SJanice.Chang@Sun.COM 	 * strstr() result.  Hence the below code works for
218112186SJanice.Chang@Sun.COM 	 * all cases.
218212186SJanice.Chang@Sun.COM 	 */
218312186SJanice.Chang@Sun.COM 
218412186SJanice.Chang@Sun.COM 	ptr--;
218512186SJanice.Chang@Sun.COM 	(void) strncpy(newprop, snapdata_p->nzs_snapprop,
218612186SJanice.Chang@Sun.COM 	    (char *)ptr - snapdata_p->nzs_snapprop);
218712186SJanice.Chang@Sun.COM 	ptr += strlen(snapdata_p->nzs_findprop) + 1;
218812186SJanice.Chang@Sun.COM 	(void) strlcat(newprop, ptr, ZFS_MAXPROPLEN);
218912186SJanice.Chang@Sun.COM 
219012186SJanice.Chang@Sun.COM 	err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
219112186SJanice.Chang@Sun.COM 
219212186SJanice.Chang@Sun.COM 	zfs_close(zhp);
219312186SJanice.Chang@Sun.COM 
219412186SJanice.Chang@Sun.COM 	if (err) {
219512186SJanice.Chang@Sun.COM 		NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err);
219612186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "error modifying property %s", newprop);
219712186SJanice.Chang@Sun.COM 		return (-1);
219812186SJanice.Chang@Sun.COM 	}
219912186SJanice.Chang@Sun.COM 
220012186SJanice.Chang@Sun.COM 	return (0);
220112186SJanice.Chang@Sun.COM }
220212186SJanice.Chang@Sun.COM 
220312186SJanice.Chang@Sun.COM static boolean_t
220412186SJanice.Chang@Sun.COM ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor)
220512186SJanice.Chang@Sun.COM {
220612186SJanice.Chang@Sun.COM 	(void) sscanf(propstr, "%u.%u.%*c%*s", major, minor);
220712186SJanice.Chang@Sun.COM 
220812186SJanice.Chang@Sun.COM 	if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) {
220912186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)",
221012186SJanice.Chang@Sun.COM 		    *major, NDMPD_ZFS_PROP_MAJOR_VERSION);
221112186SJanice.Chang@Sun.COM 		return (B_FALSE);
221212186SJanice.Chang@Sun.COM 	}
221312186SJanice.Chang@Sun.COM 
221412186SJanice.Chang@Sun.COM 	if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) {
221512186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)",
221612186SJanice.Chang@Sun.COM 		    *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
221712186SJanice.Chang@Sun.COM 	}
221812186SJanice.Chang@Sun.COM 
221912186SJanice.Chang@Sun.COM 	NDMP_LOG(LOG_DEBUG, "passed version check: "
222012186SJanice.Chang@Sun.COM 	    "supported prop major (%u <= %u); (snapprop minor: %u [%u])",
222112186SJanice.Chang@Sun.COM 	    *major, NDMPD_ZFS_PROP_MAJOR_VERSION,
222212186SJanice.Chang@Sun.COM 	    *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
222312186SJanice.Chang@Sun.COM 
222412186SJanice.Chang@Sun.COM 	return (B_TRUE);
222512186SJanice.Chang@Sun.COM }
222612186SJanice.Chang@Sun.COM 
222712186SJanice.Chang@Sun.COM static int
222812186SJanice.Chang@Sun.COM ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
222912186SJanice.Chang@Sun.COM     char *snapname, int namelen)
223012186SJanice.Chang@Sun.COM {
223112186SJanice.Chang@Sun.COM 	char subprop[ZFS_MAXPROPLEN];
223212186SJanice.Chang@Sun.COM 	struct timeval tp;
223312186SJanice.Chang@Sun.COM 	int err = 0;
223412186SJanice.Chang@Sun.COM 
223512186SJanice.Chang@Sun.COM 	(void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
223612186SJanice.Chang@Sun.COM 	    subprop, ZFS_MAXPROPLEN, B_FALSE);
223712186SJanice.Chang@Sun.COM 
223812186SJanice.Chang@Sun.COM 	(void) gettimeofday(&tp, NULL);
223912186SJanice.Chang@Sun.COM 
224012186SJanice.Chang@Sun.COM 	err = snprintf(snapname, namelen,
224112186SJanice.Chang@Sun.COM 	    "ndmp.%s.%ld.%ld",
224212186SJanice.Chang@Sun.COM 	    subprop,
224312186SJanice.Chang@Sun.COM 	    tp.tv_sec,
224412186SJanice.Chang@Sun.COM 	    tp.tv_usec);
224512186SJanice.Chang@Sun.COM 
224612186SJanice.Chang@Sun.COM 	if (err > namelen) {
224712186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d",
224812186SJanice.Chang@Sun.COM 		    snapname, namelen);
224912186SJanice.Chang@Sun.COM 		return (-1);
225012186SJanice.Chang@Sun.COM 	}
225112186SJanice.Chang@Sun.COM 
225212186SJanice.Chang@Sun.COM 	return (0);
225312186SJanice.Chang@Sun.COM }
225412186SJanice.Chang@Sun.COM 
225512186SJanice.Chang@Sun.COM static void
225612186SJanice.Chang@Sun.COM ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args)
225712186SJanice.Chang@Sun.COM {
225812186SJanice.Chang@Sun.COM 	switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) {
225912186SJanice.Chang@Sun.COM 	case EZFS_EXISTS:
226012186SJanice.Chang@Sun.COM 	case EZFS_BUSY:
226112186SJanice.Chang@Sun.COM 	case EZFS_NOENT:
226212186SJanice.Chang@Sun.COM 	case EZFS_INVALIDNAME:
226312186SJanice.Chang@Sun.COM 	case EZFS_MOUNTFAILED:
226412186SJanice.Chang@Sun.COM 	case EZFS_UMOUNTFAILED:
226512186SJanice.Chang@Sun.COM 	case EZFS_NAMETOOLONG:
226612186SJanice.Chang@Sun.COM 	case EZFS_BADRESTORE:
226712186SJanice.Chang@Sun.COM 
226812186SJanice.Chang@Sun.COM 		/* use existing error text */
226912186SJanice.Chang@Sun.COM 
227012186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
227112186SJanice.Chang@Sun.COM 		    "%s: %s: %s\n",
227212186SJanice.Chang@Sun.COM 		    ndmpd_zfs_args->nz_dataset,
227312186SJanice.Chang@Sun.COM 		    libzfs_error_action(ndmpd_zfs_args->nz_zlibh),
227412186SJanice.Chang@Sun.COM 		    libzfs_error_description(ndmpd_zfs_args->nz_zlibh));
227512186SJanice.Chang@Sun.COM 
227612186SJanice.Chang@Sun.COM 		break;
227712186SJanice.Chang@Sun.COM 
227812186SJanice.Chang@Sun.COM 	case EZFS_NOMEM:
227912186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
228012186SJanice.Chang@Sun.COM 		    "Unable to obtain memory for operation\n");
228112186SJanice.Chang@Sun.COM 		break;
228212186SJanice.Chang@Sun.COM 
228312186SJanice.Chang@Sun.COM 	case EZFS_PROPSPACE:
228412186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
228512186SJanice.Chang@Sun.COM 		    "A bad ZFS quota or reservation was encountered.\n");
228612186SJanice.Chang@Sun.COM 		break;
228712186SJanice.Chang@Sun.COM 
228812186SJanice.Chang@Sun.COM 	case EZFS_BADSTREAM:
228912186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
229012186SJanice.Chang@Sun.COM 		    "The backup stream is invalid.\n");
229112186SJanice.Chang@Sun.COM 		break;
229212186SJanice.Chang@Sun.COM 
229312186SJanice.Chang@Sun.COM 	case EZFS_ZONED:
229412186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
229512186SJanice.Chang@Sun.COM 		    "An error related to the local zone occurred.\n");
229612186SJanice.Chang@Sun.COM 		break;
229712186SJanice.Chang@Sun.COM 
229812186SJanice.Chang@Sun.COM 	case EZFS_NOSPC:
229912186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
230012186SJanice.Chang@Sun.COM 		    "No more space is available\n");
230112186SJanice.Chang@Sun.COM 		break;
230212186SJanice.Chang@Sun.COM 
230312186SJanice.Chang@Sun.COM 	case EZFS_IO:
230412186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
230512186SJanice.Chang@Sun.COM 		    "An I/O error occurred.\n");
230612186SJanice.Chang@Sun.COM 		break;
230712186SJanice.Chang@Sun.COM 
230812186SJanice.Chang@Sun.COM 	default:
230912186SJanice.Chang@Sun.COM 		ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
231012186SJanice.Chang@Sun.COM 		    "An internal ndmpd error occurred.  "
231112186SJanice.Chang@Sun.COM 		    "Please contact support\n");
231212186SJanice.Chang@Sun.COM 		break;
231312186SJanice.Chang@Sun.COM 	}
231412186SJanice.Chang@Sun.COM }
231512186SJanice.Chang@Sun.COM 
231612186SJanice.Chang@Sun.COM void
231712186SJanice.Chang@Sun.COM ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type,
231812186SJanice.Chang@Sun.COM     char *format, ...)
231912186SJanice.Chang@Sun.COM {
232012186SJanice.Chang@Sun.COM 	static char buf[1024];
232112186SJanice.Chang@Sun.COM 	va_list ap;
232212186SJanice.Chang@Sun.COM 
232312186SJanice.Chang@Sun.COM 	va_start(ap, format);
232412186SJanice.Chang@Sun.COM 
232512186SJanice.Chang@Sun.COM 	/*LINTED variable format specifier */
232612186SJanice.Chang@Sun.COM 	(void) vsnprintf(buf, sizeof (buf), format, ap);
232712186SJanice.Chang@Sun.COM 	va_end(ap);
232812186SJanice.Chang@Sun.COM 
232912186SJanice.Chang@Sun.COM 	MOD_LOGV3(ndmpd_zfs_params, log_type, buf);
233012186SJanice.Chang@Sun.COM 
233112186SJanice.Chang@Sun.COM 	if ((log_type) == NDMP_LOG_ERROR) {
233212186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_ERR, buf);
233312186SJanice.Chang@Sun.COM 	} else {
233412186SJanice.Chang@Sun.COM 		NDMP_LOG(LOG_INFO, buf);
233512186SJanice.Chang@Sun.COM 	}
233612186SJanice.Chang@Sun.COM }
2337