summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/cmd/ndmpd/Makefile8
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd.h132
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c13
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c62
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_common.h6
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_config.c77
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_data.c355
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c6
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_main.c5
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c29
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c42
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c54
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_util.c11
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c2336
-rw-r--r--usr/src/cmd/ndmpd/tlm/tlm_lib.c64
-rw-r--r--usr/src/lib/libndmp/common/libndmp.h16
16 files changed, 2970 insertions, 246 deletions
diff --git a/usr/src/cmd/ndmpd/Makefile b/usr/src/cmd/ndmpd/Makefile
index 2abd24753a..710650aaf4 100644
--- a/usr/src/cmd/ndmpd/Makefile
+++ b/usr/src/cmd/ndmpd/Makefile
@@ -1,6 +1,5 @@
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
#
#
@@ -81,18 +80,19 @@ NDMP_OBJ = \
ndmpd_data.o \
ndmpd_door.o \
ndmpd_dtime.o \
- ndmpd_prop.o \
ndmpd_fhistory.o \
ndmpd_handler.o \
ndmpd_log.o \
ndmpd_main.o \
ndmpd_mark.o \
ndmpd_mover.o \
+ ndmpd_prop.o \
ndmpd_scsi.o \
ndmpd_tape.o \
ndmpd_tar.o \
ndmpd_tar3.o \
- ndmpd_util.o
+ ndmpd_util.o \
+ ndmpd_zfs.o
TLM_OBJ = \
tlm_backup_reader.o \
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd.h b/usr/src/cmd/ndmpd/ndmp/ndmpd.h
index 4ebb2455de..d63113ba20 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd.h
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd.h
@@ -1,6 +1,5 @@
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -114,15 +113,16 @@ typedef void *(*funct_t)(void *); /* function pointer */
#define ROOT_INODE 2
/*
- * NDMP backup image signature.
+ * NDMP backup image signature
*/
#define NDMPUTF8MAGIC "NDMPUTF8MAGIC"
/*
* Supported BU types
*/
-#define NDMP_DUMP_TYPE "dump"
#define NDMP_TAR_TYPE "tar"
+#define NDMP_DUMP_TYPE "dump"
+#define NDMP_ZFS_TYPE "zfs"
/* All 1's binary maximum mover window */
#define MAX_WINDOW_SIZE 0xffffffffffffffffULL
@@ -284,7 +284,6 @@ typedef struct mem_ndmp_name_v3 {
ndmp_error nm3_err;
} mem_ndmp_name_v3_t;
-
typedef struct ndmpd_file_handler {
int fh_fd;
ulong_t fh_mode;
@@ -427,6 +426,76 @@ typedef struct ndmpd_session_file_history_v3 {
ulong_t fh_dir_name_buf_index;
} ndmpd_session_file_history_v3_t;
+/*
+ * zfs-based backup (zfs send/recv)
+ */
+
+typedef enum {
+ NDMPD_ZFS_MAJOR_0,
+} ndmpd_zfs_major_t;
+
+typedef enum {
+ NDMPD_ZFS_MINOR_0,
+} ndmpd_zfs_minor_t;
+
+typedef enum {
+ NDMPD_ZFS_PROP_MAJOR_0,
+} ndmpd_zfs_prop_major_t;
+
+typedef enum {
+ NDMPD_ZFS_PROP_MINOR_0,
+} ndmpd_zfs_prop_minor_t;
+
+#define NDMPD_ZFS_MAJOR_VERSION NDMPD_ZFS_MAJOR_0
+#define NDMPD_ZFS_MINOR_VERSION NDMPD_ZFS_MINOR_0
+#define NDMPD_ZFS_PROP_MAJOR_VERSION NDMPD_ZFS_PROP_MAJOR_0
+#define NDMPD_ZFS_PROP_MINOR_VERSION NDMPD_ZFS_PROP_MINOR_0
+
+#pragma pack(1)
+typedef struct {
+ char nzh_magic[14]; /* NDMPUTF8MAGIC\0 */
+ uint32_t nzh_major; /* major version */
+ uint32_t nzh_minor; /* minor version */
+ uint32_t nzh_hdrlen; /* length of hdr in bytes including magic */
+ /* future extensions */
+} ndmpd_zfs_header_t;
+#pragma pack()
+
+#define PIPE_TAPE 0
+#define PIPE_ZFS 1
+
+#define NDMPD_ZFS_DMP_NAME_MAX 32
+
+typedef struct ndmpd_zfs_args {
+ zfs_type_t nz_type; /* type of ZFS dataset */
+ char nz_dataset[ZFS_MAXNAMELEN]; /* dataset name */
+ char nz_snapname[ZFS_MAXNAMELEN]; /* snapname (following '@') */
+ char nz_fromsnap[ZFS_MAXNAMELEN]; /* snap of L-1 bkup */
+ char nz_snapprop[ZFS_MAXPROPLEN]; /* contents of snap incr prop */
+ boolean_t nz_ndmpd_snap; /* ndmpd-generated snap? */
+
+ pthread_t nz_sendrecv_thread; /* thread for send/recv */
+ pthread_t nz_tape_thread; /* thread for tape r/w */
+ int32_t nz_pipe_fd[2]; /* pipe for above 2 threads */
+ int32_t nz_bufsize; /* tape r/w buf size */
+ int64_t nz_window_len; /* DMA window length */
+
+ int nz_level; /* val of LEVEL env var */
+ char nz_zfs_mode; /* val of ZFS_MODE env var */
+ boolean_t nz_zfs_force; /* val of ZFS_FORCE env var */
+ boolean_t nz_update; /* val of UPDATE env var */
+ char nz_dmp_name[NDMPD_ZFS_DMP_NAME_MAX]; /* val of DMP_NAME env var */
+
+ ndmpd_module_params_t nz_params;
+ ndmp_lbr_params_t *nz_nlp;
+ libzfs_handle_t *nz_zlibh; /* session-specific lzfs hdl */
+ ndmp_context_t nz_nctx; /* used by plugin */
+
+ ndmpd_zfs_header_t nz_tape_header; /* tape hdr for "zfs" backup */
+} ndmpd_zfs_args_t;
+
+#define ndmpd_zfs_params (&(ndmpd_zfs_args)->nz_params)
+
typedef struct ndmpd_session {
ndmp_connection_t *ns_connection; /* NDMP connection to client */
boolean_t ns_eof; /* connection EOF flag */
@@ -439,6 +508,8 @@ typedef struct ndmpd_session {
ndmpd_file_handler_t *ns_file_handler_list; /* for I/O multiplexing */
int ns_nref;
ndmp_lbr_params_t *ns_ndmp_lbr_params;
+ struct ndmpd_zfs_args ns_ndmpd_zfs_args;
+ ndmpd_backup_type_t ns_butype;
mutex_t ns_lock;
/*
@@ -911,7 +982,6 @@ extern ndmp_error ndmp_restore_get_params_v3(ndmpd_session_t *,
ndmpd_module_params_t *);
extern ndmp_error ndmp_backup_get_params_v3(ndmpd_session_t *,
ndmpd_module_params_t *);
-extern char *get_bk_path_v3(ndmpd_module_params_t *);
/*
* door init and fini function from ndmpd_door_serv.c
@@ -938,11 +1008,11 @@ extern void ndmpd_abort_marking_v2(ndmpd_session_t *);
extern int ndmpd_mark_inodes_v3(ndmpd_session_t *, ndmp_lbr_params_t *);
extern ndmp_lbr_params_t *ndmp_get_nlp(void *);
-module_start_func_t ndmpd_tar_backup_starter;
-module_abort_func_t ndmpd_tar_backup_abort;
+module_start_func_t ndmpd_tar_backup_starter;
+module_abort_func_t ndmpd_tar_backup_abort;
-module_start_func_t ndmpd_tar_restore_starter;
-module_abort_func_t ndmpd_tar_restore_abort;
+module_start_func_t ndmpd_tar_restore_starter;
+module_abort_func_t ndmpd_tar_restore_abort;
module_start_func_t ndmpd_tar_backup_starter_v3;
module_abort_func_t ndmpd_tar_backup_abort_v3;
@@ -969,8 +1039,8 @@ extern int tcp_get_peer(int, unsigned int *, int *);
extern char *gethostaddr(void);
extern int tlm_init(void);
-extern int chkpnt_backup_successful(char *, char *);
-extern int chkpnt_backup_prepare(char *, char *);
+extern int chkpnt_backup_successful(char *, char *, boolean_t, int *);
+extern int chkpnt_backup_prepare(char *, char *, boolean_t);
extern boolean_t fs_is_chkpntvol(char *);
extern boolean_t fs_is_chkpnt_enabled(char *);
@@ -1005,4 +1075,42 @@ extern struct sasd_drive *sasd_drive(int);
extern void *ndmp_malloc(size_t size);
extern ndmp_plugin_t *ndmp_pl;
+
+#define NDMP_APILOG(s, t, m, ...) \
+{ \
+ if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV4) \
+ (void) ndmpd_api_log_v4(s, t, m, __VA_ARGS__); \
+ else if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV3) \
+ (void) ndmpd_api_log_v3(s, t, m, __VA_ARGS__); \
+ else \
+ (void) ndmpd_api_log_v2(s, __VA_ARGS__); \
+}
+
+/*
+ * Backup path utility functions
+ */
+extern char *get_backup_path_v3(ndmpd_module_params_t *);
+extern char *get_backup_path_v2(ndmpd_module_params_t *);
+
+/*
+ * Functions for zfs-based backup
+ */
+
+module_start_func_t ndmpd_zfs_backup_starter;
+module_start_func_t ndmpd_zfs_restore_starter;
+module_abort_func_t ndmpd_zfs_abort;
+
+int ndmpd_zfs_init(ndmpd_session_t *);
+void ndmpd_zfs_fini(ndmpd_zfs_args_t *);
+
+boolean_t ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *);
+boolean_t ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *);
+
+int ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *);
+int ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *);
+int ndmpd_zfs_post_backup(ndmpd_zfs_args_t *);
+int ndmpd_zfs_post_restore(ndmpd_zfs_args_t *);
+
+void ndmpd_zfs_dma_log(ndmpd_zfs_args_t *, ndmp_log_type, char *, ...);
+
#endif /* _NDMPD_H */
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c
index bc3cd8d3cc..d47bc38d25 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -111,7 +110,7 @@ ndmp_has_backup_chkpnt(char *volname, char *jobname)
}
chkp.chp_found = 0;
- (void) snprintf(chname, ZFS_MAXNAMELEN, "@bk-%s", jobname);
+ (void) snprintf(chname, ZFS_MAXNAMELEN, "@%s", jobname);
chkp.chp_name = chname;
(void) zfs_iter_snapshots(zhp, ndmp_has_backup, &chkp);
@@ -255,8 +254,10 @@ ndmp_start_check_point(char *vol_name, char *jname)
* removed before using it.
*/
if (ndmp_has_backup_chkpnt(vol, jname))
- (void) chkpnt_backup_successful(vol, jname);
- if ((erc = chkpnt_backup_prepare(vol, jname)) < 0)
+ (void) chkpnt_backup_successful(vol, jname, B_FALSE,
+ NULL);
+ if ((erc = chkpnt_backup_prepare(vol, jname, B_FALSE))
+ < 0)
(void) ndmp_remove_chk_pnt_vol(vol);
}
@@ -289,7 +290,7 @@ ndmp_release_check_point(char *vol_name, char *jname)
return (0);
if (ndmp_remove_chk_pnt_vol(vol) == 0)
- erc = chkpnt_backup_successful(vol, jname);
+ erc = chkpnt_backup_successful(vol, jname, B_FALSE, NULL);
return (erc);
}
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c
index 31b54bfa2c..13e4de9a16 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -1653,3 +1652,62 @@ ndmp_malloc(size_t size)
return (data);
}
+
+/*
+ * get_backup_path_v3
+ *
+ * Get the backup path from the NDMP environment variables.
+ *
+ * Parameters:
+ * params (input) - pointer to the parameters structure.
+ *
+ * Returns:
+ * The backup path: if anything is specified
+ * NULL: Otherwise
+ */
+char *
+get_backup_path_v3(ndmpd_module_params_t *params)
+{
+ char *bkpath;
+
+ bkpath = MOD_GETENV(params, "PREFIX");
+ if (!bkpath)
+ bkpath = MOD_GETENV(params, "FILESYSTEM");
+
+
+ if (!bkpath) {
+ MOD_LOGV3(params, NDMP_LOG_ERROR,
+ "Backup path not defined.\n");
+ } else {
+ NDMP_LOG(LOG_DEBUG, "bkpath: \"%s\"", bkpath);
+ }
+
+ return (bkpath);
+}
+
+/*
+ * get_backup_path
+ *
+ * Find the backup path from the environment variables (v2)
+ */
+char *
+get_backup_path_v2(ndmpd_module_params_t *params)
+{
+ char *bkpath;
+
+ bkpath = MOD_GETENV(params, "PREFIX");
+ if (bkpath == NULL)
+ bkpath = MOD_GETENV(params, "FILESYSTEM");
+
+ if (bkpath == NULL) {
+ MOD_LOG(params, "Error: restore path not specified.\n");
+ return (NULL);
+ }
+
+ if (*bkpath != '/') {
+ MOD_LOG(params, "Error: relative backup path not allowed.\n");
+ return (NULL);
+ }
+
+ return (bkpath);
+}
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_common.h b/usr/src/cmd/ndmpd/ndmp/ndmpd_common.h
index 0b2a75593b..5617da10e8 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_common.h
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_common.h
@@ -1,6 +1,5 @@
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -64,6 +63,7 @@
#define INT_MAXCMD 12
extern mutex_t log_lock;
+extern mutex_t ndmpd_zfs_fd_lock;
/* Connection data structure. */
typedef struct msg_info {
@@ -277,6 +277,6 @@ extern int ndmp_log_msg_id;
/*
* Module function prototypes.
*/
-typedef int module_start_func_t(ndmpd_module_params_t *);
+typedef int module_start_func_t(void *);
typedef int module_abort_func_t(void *);
#endif /* _NDMP_COMMON_H */
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c
index 751d798f28..d794fe2fa3 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -429,15 +428,21 @@ void
ndmpd_config_get_butype_info_v3(ndmp_connection_t *connection, void *body)
{
ndmp_config_get_butype_info_reply_v3 reply;
- ndmp_butype_info info[2];
+ ndmp_butype_info info[3];
ndmp_pval envs[8];
ulong_t attrs;
ndmp_pval *envp = envs;
+ ndmp_pval zfs_envs[9];
+ ulong_t zfs_attrs;
+ ndmp_pval *zfs_envp = zfs_envs;
+
(void) memset((void*)&reply, 0, sizeof (reply));
/*
- * Supported environment variables and their default values.
+ * Supported environment variables and their default values
+ * for dump and tar.
+ *
* The environment variables for dump and tar format are the
* same, because we use the same backup engine for both.
*/
@@ -473,6 +478,31 @@ ndmpd_config_get_butype_info_v3(ndmp_connection_t *connection, void *body)
info[1].default_env.default_env_val = envs;
info[1].attrs = attrs;
+ /*
+ * Supported environment variables and their default values
+ * for type "zfs."
+ */
+
+ NDMP_SETENV(zfs_envp, "PREFIX", "");
+ NDMP_SETENV(zfs_envp, "FILESYSTEM", "");
+ NDMP_SETENV(zfs_envp, "TYPE", "zfs");
+ NDMP_SETENV(zfs_envp, "HIST", "n");
+ NDMP_SETENV(zfs_envp, "LEVEL", "0");
+ NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive");
+ NDMP_SETENV(zfs_envp, "ZFS_FORCE", "FALSE");
+ NDMP_SETENV(zfs_envp, "UPDATE", "TRUE");
+ NDMP_SETENV(zfs_envp, "DMP_NAME", "level");
+
+ zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 |
+ NDMP_BUTYPE_RECOVER_UTF8 |
+ NDMP_BUTYPE_BACKUP_INCREMENTAL;
+
+ /* zfs backup type */
+ info[2].butype_name = "zfs";
+ info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval);
+ info[2].default_env.default_env_val = zfs_envs;
+ info[2].attrs = zfs_attrs;
+
reply.error = NDMP_NO_ERR;
reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
reply.butype_info.butype_info_val = info;
@@ -899,15 +929,23 @@ void
ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body)
{
ndmp_config_get_butype_info_reply_v4 reply;
- ndmp_butype_info info[2];
+ ndmp_butype_info info[3];
+
ndmp_pval envs[12];
ulong_t attrs;
ndmp_pval *envp = envs;
+ ndmp_pval zfs_envs[11];
+ ulong_t zfs_attrs;
+ ndmp_pval *zfs_envp = zfs_envs;
+
+
(void) memset((void*)&reply, 0, sizeof (reply));
/*
- * Supported environment variables and their default values.
+ * Supported environment variables and their default values
+ * for dump and tar.
+ *
* The environment variables for dump and tar format are the
* same, because we use the same backup engine for both.
*/
@@ -950,6 +988,33 @@ ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body)
info[1].default_env.default_env_val = envs;
info[1].attrs = attrs;
+ /*
+ * Supported environment variables and their default values
+ * for type "zfs."
+ */
+
+ NDMP_SETENV(zfs_envp, "USER", "");
+ NDMP_SETENV(zfs_envp, "CMD", "");
+ NDMP_SETENV(zfs_envp, "FILESYSTEM", "");
+ NDMP_SETENV(zfs_envp, "PATHNAME_SEPARATOR", "/");
+ NDMP_SETENV(zfs_envp, "TYPE", "zfs");
+ NDMP_SETENV(zfs_envp, "HIST", "n");
+ NDMP_SETENV(zfs_envp, "LEVEL", "0");
+ NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive");
+ NDMP_SETENV(zfs_envp, "ZFS_FORCE", "n");
+ NDMP_SETENV(zfs_envp, "UPDATE", "y");
+ NDMP_SETENV(zfs_envp, "DMP_NAME", "level");
+
+ zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 |
+ NDMP_BUTYPE_RECOVER_UTF8 |
+ NDMP_BUTYPE_BACKUP_INCREMENTAL;
+
+ /* zfs backup type */
+ info[2].butype_name = "zfs";
+ info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval);
+ info[2].default_env.default_env_val = zfs_envs;
+ info[2].attrs = zfs_attrs;
+
reply.error = NDMP_NO_ERR;
reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
reply.butype_info.butype_info_val = info;
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c
index 9b471e469a..24f28f1dcc 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -61,23 +60,18 @@ static ndmp_error data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr,
static int discard_data_v3(ndmpd_session_t *session, ulong_t length);
static void nlp_release_job_stat(ndmpd_session_t *session);
static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
-static ndmp_error start_backup_v3(ndmpd_session_t *session, char *bu_type,
- ndmp_pval *env_val, ulong_t env_len);
-static ndmp_error start_backup(ndmpd_session_t *session, char *bu_type,
- ndmp_pval *env_val, ulong_t env_len);
-static ndmp_error start_recover(ndmpd_session_t *session, char *bu_type,
- ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
- ulong_t nlist_len);
-static ndmp_error start_recover_v3(ndmpd_session_t *session, char *bu_type,
- ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val,
- ulong_t nlist_len);
-static ndmp_error start_backup(ndmpd_session_t *session, char *bu_type,
- ndmp_pval *env_val, ulong_t env_len);
-static ndmp_error start_recover(ndmpd_session_t *session, char *bu_type,
- ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
- ulong_t nlist_len);
-static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
-static void nlp_release_job_stat(ndmpd_session_t *session);
+
+static ndmp_error ndmpd_tar_start_backup_v2(ndmpd_session_t *, char *,
+ ndmp_pval *, ulong_t);
+static ndmp_error ndmpd_tar_start_recover_v2(ndmpd_session_t *, char *,
+ ndmp_pval *, ulong_t, ndmp_name *, ulong_t);
+static ndmp_error ndmpd_tar_start_backup_v3(ndmpd_session_t *, char *,
+ ndmp_pval *, ulong_t);
+static ndmp_error ndmpd_tar_start_recover_v3(ndmpd_session_t *,
+ ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t);
+
+static ndmp_error ndmpd_zfs_start_op(ndmpd_session_t *,
+ ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t, enum ndmp_data_operation);
/*
@@ -153,8 +147,8 @@ ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body)
reply.error = NDMP_NO_ERR;
session->ns_data.dd_mover = request->mover;
- err = start_backup(session, request->bu_type, request->env.env_val,
- request->env.env_len);
+ err = ndmpd_tar_start_backup_v2(session, request->bu_type,
+ request->env.env_val, request->env.env_len);
/*
* start_backup sends the reply if the backup is successfully started.
@@ -169,7 +163,6 @@ ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body)
}
}
-
/*
* ndmpd_data_start_recover_v2
*
@@ -193,9 +186,10 @@ ndmpd_data_start_recover_v2(ndmp_connection_t *connection, void *body)
request = (ndmp_data_start_recover_request_v2 *) body;
session->ns_data.dd_mover = request->mover;
- err = start_recover(session, request->bu_type, request->env.env_val,
- request->env.env_len, request->nlist.nlist_val,
- request->nlist.nlist_len);
+ err = ndmpd_tar_start_recover_v2(session, request->bu_type,
+ request->env.env_val, request->env.env_len,
+ request->nlist.nlist_val, request->nlist.nlist_len);
+
/*
* start_recover sends the reply if the recover is successfully started.
* Otherwise, send the reply containing the error here.
@@ -208,7 +202,6 @@ ndmpd_data_start_recover_v2(ndmp_connection_t *connection, void *body)
}
}
-
/*
* ndmpd_data_get_env_v2
*
@@ -401,29 +394,78 @@ ndmpd_data_start_backup_v3(ndmp_connection_t *connection, void *body)
ndmp_data_start_backup_request_v3 *request;
ndmp_data_start_backup_reply_v3 reply;
ndmpd_session_t *session = ndmp_get_client_data(connection);
- ndmp_error err;
request = (ndmp_data_start_backup_request_v3 *)body;
(void) memset((void*)&reply, 0, sizeof (reply));
- err = start_backup_v3(session, request->bu_type, request->env.env_val,
- request->env.env_len);
+ if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
+ NDMP_LOG(LOG_ERR,
+ "Can't start new backup in current state.");
+ NDMP_LOG(LOG_ERR,
+ "Connection to the mover is not established.");
+ reply.error = NDMP_ILLEGAL_STATE_ERR;
+ goto _error;
+ }
+
+ if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
+ if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
+ NDMP_LOG(LOG_ERR, "Write protected device.");
+ reply.error = NDMP_WRITE_PROTECT_ERR;
+ goto _error;
+ }
+ }
+
+ if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
+ session->ns_butype = NDMP_BUTYPE_TAR;
+ } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
+ session->ns_butype = NDMP_BUTYPE_DUMP;
+ } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
+ session->ns_butype = NDMP_BUTYPE_ZFS;
+ } else {
+ char msg_invalid[32];
+ char msg_types[32];
+
+ (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
+ request->bu_type);
+ (void) snprintf(msg_types, 32,
+ "Supported backup types are tar, dump, and zfs.");
+
+ NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
+ msg_invalid);
+ NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
+ msg_types);
+ NDMP_LOG(LOG_ERR, msg_invalid);
+ NDMP_LOG(LOG_ERR, msg_types);
+
+ reply.error = NDMP_ILLEGAL_ARGS_ERR;
+ goto _error;
+ }
+
+ if (session->ns_butype == NDMP_BUTYPE_ZFS) {
+ reply.error = ndmpd_zfs_start_op(session, request->env.env_val,
+ request->env.env_len, NULL, 0, NDMP_DATA_OP_BACKUP);
+ } else {
+ reply.error = ndmpd_tar_start_backup_v3(session,
+ request->bu_type, request->env.env_val,
+ request->env.env_len);
+ }
/*
- * start_backup_v3 sends the reply if the backup is
+ * *_start_backup* sends the reply if the backup is
* successfully started. Otherwise, send the reply
* containing the error here.
*/
- if (err != NDMP_NO_ERR) {
- reply.error = err;
+
+_error:
+
+ if (reply.error != NDMP_NO_ERR) {
ndmp_send_reply(connection, &reply,
"sending data_start_backup_v3 reply");
ndmpd_data_cleanup(session);
}
}
-
/*
* ndmpd_data_start_recover_v3
*
@@ -442,23 +484,62 @@ ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body)
ndmp_data_start_recover_request_v3 *request;
ndmp_data_start_recover_reply_v3 reply;
ndmpd_session_t *session = ndmp_get_client_data(connection);
- ndmp_error err;
request = (ndmp_data_start_recover_request_v3 *)body;
(void) memset((void*)&reply, 0, sizeof (reply));
- err = start_recover_v3(session, request->bu_type, request->env.env_val,
- request->env.env_len, request->nlist.nlist_val,
- request->nlist.nlist_len);
+ if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
+ NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
+ reply.error = NDMP_ILLEGAL_STATE_ERR;
+ goto _error;
+ }
+
+ if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
+ session->ns_butype = NDMP_BUTYPE_TAR;
+ } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
+ session->ns_butype = NDMP_BUTYPE_DUMP;
+ } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
+ session->ns_butype = NDMP_BUTYPE_ZFS;
+ } else {
+ char msg_invalid[32];
+ char msg_types[32];
+
+ (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
+ request->bu_type);
+ (void) snprintf(msg_types, 32,
+ "Supported backup types are tar, dump, and zfs.");
+
+ NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
+ msg_invalid);
+ NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
+ msg_types);
+ NDMP_LOG(LOG_ERR, msg_invalid);
+ NDMP_LOG(LOG_ERR, msg_types);
+
+ reply.error = NDMP_ILLEGAL_ARGS_ERR;
+ goto _error;
+ }
+
+ if (session->ns_butype == NDMP_BUTYPE_ZFS) {
+ reply.error = ndmpd_zfs_start_op(session, request->env.env_val,
+ request->env.env_len, request->nlist.nlist_val,
+ request->nlist.nlist_len, NDMP_DATA_OP_RECOVER);
+ } else {
+ reply.error = ndmpd_tar_start_recover_v3(session,
+ request->env.env_val, request->env.env_len,
+ request->nlist.nlist_val, request->nlist.nlist_len);
+ }
/*
- * start_recover_v3 sends the reply if the recover is
+ * *_start_recover* sends the reply if the recover is
* successfully started. Otherwise, send the reply
* containing the error here.
*/
- if (err != NDMP_NO_ERR) {
- reply.error = err;
+
+_error:
+
+ if (reply.error != NDMP_NO_ERR) {
ndmp_send_reply(connection, &reply,
"sending data_start_recover_v3 reply");
ndmpd_data_error(session, NDMP_DATA_HALT_INTERNAL_ERROR);
@@ -466,7 +547,6 @@ ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body)
}
}
-
/*
* ndmpd_data_abort_v3
*
@@ -1281,23 +1361,23 @@ data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr, ushort_t port)
/*
- * start_backup_v3
+ * ndmpd_tar_start_backup_v3
*
* Start the backup work
*
* Parameters:
- * session (input) - session pointer.
- * bu_type (input) - backup type.
- * env_val (input) - environment variable array.
- * env_len (input) - length of env_val.
+ * session (input) - session pointer.
+ * bu_type (input) - backup type.
+ * env_val (input) - environment variable array.
+ * env_len (input) - length of env_val.
*
* Returns:
* NDMP_NO_ERR - backup successfully started.
* otherwise - error code of backup start error.
*/
static ndmp_error
-start_backup_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
- ulong_t env_len)
+ndmpd_tar_start_backup_v3(ndmpd_session_t *session, char *bu_type,
+ ndmp_pval *env_val, ulong_t env_len)
{
int err;
ndmp_lbr_params_t *nlp;
@@ -1306,28 +1386,6 @@ start_backup_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
(void) memset((void*)&reply, 0, sizeof (reply));
- if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
- NDMP_LOG(LOG_ERR,
- "Can't start new backup in current state.");
- NDMP_LOG(LOG_ERR,
- "Connection to the mover is not established.");
- return (NDMP_ILLEGAL_STATE_ERR);
- }
-
- if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
- if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
- NDMP_LOG(LOG_ERR, "Write protected device.");
- return (NDMP_WRITE_PROTECT_ERR);
- }
- }
-
- if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
- strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
- NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
- NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
- return (NDMP_ILLEGAL_ARGS_ERR);
- }
-
err = ndmpd_save_env(session, env_val, env_len);
if (err != NDMP_NO_ERR)
return (err);
@@ -1414,7 +1472,7 @@ start_backup_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
/*
* perform the backup
*
- * Cannot wait for the thread to exit as we are replying the
+ * Cannot wait for the thread to exit as we are replying to the
* client request here.
*/
err = pthread_create(NULL, NULL,
@@ -1428,25 +1486,27 @@ start_backup_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
return (NDMP_NO_ERR);
}
-
/*
- * start_recover_v3
+ * ndmpd_tar_start_recover_v3
*
* Start the restore work
*
* Parameters:
- * session (input) - session pointer.
+ * session (input) - session pointer.
* bu_type (input) - backup type.
* env_val (input) - environment variable array.
* env_len (input) - length of env_val.
+ * nlist_val (input) - list of files.
+ * nlist_len (input) - length of nlist_val.
*
* Returns:
* NDMP_NO_ERR - recover successfully started.
* otherwise - error code of recover start error.
*/
static ndmp_error
-start_recover_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
- ulong_t env_len, ndmp_name_v3 *nlist_val, ulong_t nlist_len)
+ndmpd_tar_start_recover_v3(ndmpd_session_t *session,
+ ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val,
+ ulong_t nlist_len)
{
ndmp_data_start_recover_reply_v3 reply;
ndmpd_module_params_t *params;
@@ -1455,17 +1515,6 @@ start_recover_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
(void) memset((void*)&reply, 0, sizeof (reply));
- if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
- NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
- return (NDMP_ILLEGAL_STATE_ERR);
- }
- if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
- strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
- NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
- NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
- return (NDMP_ILLEGAL_ARGS_ERR);
- }
-
nlp = ndmp_get_nlp(session);
NDMP_FREE(nlp->nlp_params);
params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
@@ -1566,6 +1615,115 @@ start_recover_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
return (NDMP_NO_ERR);
}
+static ndmp_error
+ndmpd_zfs_start_op(ndmpd_session_t *session, ndmp_pval *env_val,
+ ulong_t env_len, ndmp_name_v3 *nlist_val, ulong_t nlist_len,
+ enum ndmp_data_operation op)
+{
+ ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
+ ndmp_data_start_backup_reply_v3 backup_reply;
+ ndmp_data_start_recover_reply_v3 recover_reply;
+ pthread_t tid;
+ void *reply;
+ char str[8];
+ int err;
+
+ if (ndmpd_zfs_init(session) != 0)
+ return (NDMP_UNDEFINED_ERR);
+
+ err = ndmpd_save_env(session, env_val, env_len);
+ if (err != NDMP_NO_ERR) {
+ ndmpd_zfs_fini(ndmpd_zfs_args);
+ return (err);
+ }
+
+ switch (op) {
+ case NDMP_DATA_OP_BACKUP:
+ if (!ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args)) {
+ ndmpd_zfs_fini(ndmpd_zfs_args);
+ return (NDMP_ILLEGAL_ARGS_ERR);
+ }
+
+ if (ndmpd_zfs_pre_backup(ndmpd_zfs_args)) {
+ NDMP_LOG(LOG_ERR, "pre_backup error");
+ return (NDMP_ILLEGAL_ARGS_ERR);
+ }
+
+ session->ns_data.dd_module.dm_start_func =
+ ndmpd_zfs_backup_starter;
+ (void) strlcpy(str, "backup", 8);
+ break;
+ case NDMP_DATA_OP_RECOVER:
+ err = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
+ if (err != NDMP_NO_ERR) {
+ ndmpd_zfs_fini(ndmpd_zfs_args);
+ return (NDMP_NO_MEM_ERR);
+ }
+
+ if (!ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args)) {
+ ndmpd_zfs_fini(ndmpd_zfs_args);
+ return (NDMP_ILLEGAL_ARGS_ERR);
+ }
+
+ if (ndmpd_zfs_pre_restore(ndmpd_zfs_args)) {
+ NDMP_LOG(LOG_ERR, "pre_restore error");
+ (void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
+ return (NDMP_ILLEGAL_ARGS_ERR);
+ }
+ session->ns_data.dd_module.dm_start_func =
+ ndmpd_zfs_restore_starter;
+ (void) strlcpy(str, "recover", 8);
+ break;
+ }
+
+ ndmpd_zfs_params->mp_operation = op;
+ session->ns_data.dd_operation = op;
+ session->ns_data.dd_module.dm_abort_func = ndmpd_zfs_abort;
+ session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
+ session->ns_data.dd_abort = FALSE;
+
+ if (op == NDMP_DATA_OP_BACKUP) {
+ (void) memset((void*)&backup_reply, 0, sizeof (backup_reply));
+ backup_reply.error = NDMP_NO_ERR;
+ reply = &backup_reply;
+ } else {
+ (void) memset((void*)&recover_reply, 0, sizeof (recover_reply));
+ recover_reply.error = NDMP_NO_ERR;
+ reply = &recover_reply;
+ }
+
+ if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
+ reply) < 0) {
+ NDMP_LOG(LOG_DEBUG, "Sending data_start_%s_v3 reply", str);
+ if (op == NDMP_DATA_OP_RECOVER)
+ ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
+ ndmpd_zfs_fini(ndmpd_zfs_args);
+ return (NDMP_NO_ERR);
+ }
+
+ err = pthread_create(&tid, NULL,
+ (funct_t)session->ns_data.dd_module.dm_start_func, ndmpd_zfs_args);
+
+ if (err) {
+ NDMP_LOG(LOG_ERR, "Can't start %s session (errno %d)",
+ str, err);
+ ndmpd_zfs_fini(ndmpd_zfs_args);
+ MOD_DONE(ndmpd_zfs_params, -1);
+ return (NDMP_NO_ERR);
+ }
+
+ (void) pthread_detach(tid);
+
+ if (op == NDMP_DATA_OP_BACKUP)
+ NS_INC(nbk);
+ else
+ NS_INC(nrs);
+
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_NORMAL,
+ "'zfs' %s starting\n", str);
+
+ return (NDMP_NO_ERR);
+}
/*
* discard_data_v3
@@ -1886,7 +2044,7 @@ ndmp_data_get_mover_mode(ndmpd_session_t *session)
NDMP_ADDR_TCP)) ? "remote" : "local");
break;
default:
- rv = "Uknonwn";
+ rv = "Unknown";
NDMP_LOG(LOG_ERR, "Invalid protocol version %d.",
session->ns_protocol_version);
}
@@ -1897,7 +2055,7 @@ ndmp_data_get_mover_mode(ndmpd_session_t *session)
/* *** static functions ******************************************** */
/*
- * start_backup
+ * ndmpd_tar_start_backup_v2
*
* Request handling code common to version 1 and
* version 2 data_start_backup request handlers.
@@ -1913,8 +2071,8 @@ ndmp_data_get_mover_mode(ndmpd_session_t *session)
* otherwise - error code of backup start error.
*/
static ndmp_error
-start_backup(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
- ulong_t env_len)
+ndmpd_tar_start_backup_v2(ndmpd_session_t *session, char *bu_type,
+ ndmp_pval *env_val, ulong_t env_len)
{
ndmp_data_start_backup_reply reply;
ndmpd_module_params_t *params;
@@ -2043,9 +2201,8 @@ start_backup(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
return (NDMP_NO_ERR);
}
-
/*
- * start_recover
+ * ndmpd_tar_start_recover_v2
*
* The main recover/restore function
*
@@ -2054,16 +2211,17 @@ start_backup(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
* bu_type (input) - backup type.
* env_val (input) - environment variable array.
* env_len (input) - length of env_val.
- * nlist_val (input) - list of files
- * nlist_len (input) - length of nlist_val
+ * nlist_val (input) - list of files.
+ * nlist_len (input) - length of nlist_val.
*
* Returns:
* NDMP_NO_ERR - recover successfully started.
* otherwise - error code of backup start error.
*/
static ndmp_error
-start_recover(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
- ulong_t env_len, ndmp_name *nlist_val, ulong_t nlist_len)
+ndmpd_tar_start_recover_v2(ndmpd_session_t *session, char *bu_type,
+ ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
+ ulong_t nlist_len)
{
ndmp_data_start_recover_reply_v2 reply;
ndmpd_module_params_t *params;
@@ -2170,7 +2328,7 @@ start_recover(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
/*
* perform the restore
*
- * Cannot wait for the thread to exit as we are replying the
+ * Cannot wait for the thread to exit as we are replying to the
* client request here.
*/
(void) pthread_create(NULL, NULL,
@@ -2180,7 +2338,6 @@ start_recover(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
return (NDMP_NO_ERR);
}
-
/*
* ndmpd_data_get_info
*
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c
index c316444dcf..4315457621 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -769,7 +768,8 @@ ndmpd_fhpath_v3_cb(lbr_fhlog_call_backs_t *cbp, char *path, struct stat64 *stp,
if (!params || !params->mp_file_history_path_func) {
err = -1;
} else {
- char *p = ndmp_get_relative_path(get_bk_path_v3(params),
+ char *p =
+ ndmp_get_relative_path(get_backup_path_v3(params),
path);
if ((err = ndmpd_api_file_history_file_v3(cbp->
fh_cookie, p, stp, off)) < 0)
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c
index d4d332873a..b87eb49ff8 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -283,6 +282,7 @@ main(int argc, char *argv[])
openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON);
(void) mutex_init(&log_lock, 0, NULL);
+ (void) mutex_init(&ndmpd_zfs_fd_lock, 0, NULL);
if (mod_init() != 0) {
syslog(LOG_ERR, "Failed to load the plugin module.");
@@ -339,6 +339,7 @@ main(int argc, char *argv[])
ndmpd.s_sigval = 0;
}
+ (void) mutex_destroy(&ndmpd_zfs_fd_lock);
(void) mutex_destroy(&log_lock);
libzfs_fini(zlibh);
mod_fini();
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c
index 5ca0ea4174..7f3f4bb3a6 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -99,16 +98,6 @@ int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */
#define TAPE_READ_ERR -1
#define TAPE_NO_WRITER_ERR -2
-#define NDMP_APILOG(s, t, m, ...) \
-{ \
- if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV4) \
- (void) ndmpd_api_log_v4(s, t, m, __VA_ARGS__); \
- else if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV3) \
- (void) ndmpd_api_log_v3(s, t, m, __VA_ARGS__); \
- else \
- (void) ndmpd_api_log_v2(s, __VA_ARGS__); \
-}
-
/*
* ************************************************************************
* NDMP V2 HANDLERS
@@ -1608,7 +1597,7 @@ ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
return (-1);
}
/*
- * Wait for until the state is changed by
+ * Wait until the state is changed by
* an abort or continue request.
*/
nlp_ref_nw(session);
@@ -3351,6 +3340,10 @@ start_mover_for_backup(ndmpd_session_t *session)
* Returns:
* 0: not started
* non-zero: started
+ * Note: non-zero is also returned if the backup type is
+ * neither TAR nor DUMP. I.e. the is_writer_running()
+ * check does not apply in this case and things should
+ * appear successful.
*/
static boolean_t
is_writer_running(ndmpd_session_t *session)
@@ -3358,6 +3351,9 @@ is_writer_running(ndmpd_session_t *session)
boolean_t rv;
ndmp_lbr_params_t *nlp;
+ if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
+ return (1);
+
if (session == NULL)
rv = 0;
else if ((nlp = ndmp_get_nlp(session)) == NULL)
@@ -3380,6 +3376,10 @@ is_writer_running(ndmpd_session_t *session)
* Returns:
* 0: not started
* non-zero: started
+ * Note: non-zero is also returned if the backup type is
+ * neither TAR nor DUMP. I.e. the is_writer_running()
+ * check does not apply in this case and things should
+ * appear successful.
*/
static boolean_t
is_writer_running_v3(ndmpd_session_t *session)
@@ -3387,6 +3387,9 @@ is_writer_running_v3(ndmpd_session_t *session)
boolean_t rv;
ndmp_lbr_params_t *nlp;
+ if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
+ return (1);
+
if (session == NULL)
rv = 0;
else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c
index dd91065cac..ac71943834 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -36,6 +35,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
+/* Copyright (c) 2007, The Storage Networking Industry Association. */
/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
#include <sys/stat.h>
@@ -1432,34 +1432,6 @@ prefixdir(char *dir, char *suffix)
/*
- * get_backup_path
- *
- * Find the backup path from the environment variables
- */
-static char *
-get_backup_path(ndmpd_module_params_t *params)
-{
- char *bkpath;
-
- bkpath = MOD_GETENV(params, "PREFIX");
- if (bkpath == NULL)
- bkpath = MOD_GETENV(params, "FILESYSTEM");
-
- if (bkpath == NULL) {
- MOD_LOG(params, "Error: restore path not specified.\n");
- return (NULL);
- }
-
- if (*bkpath != '/') {
- MOD_LOG(params, "Error: relative backup path not allowed.\n");
- return (NULL);
- }
-
- return (bkpath);
-}
-
-
-/*
* get_nfiles
*
* Get the count of files to be restored
@@ -1664,7 +1636,7 @@ ndmp_backup_extract_params(ndmpd_session_t *session,
MOD_LOG(params, "Error: Internal error: nlp == NULL.\n");
return (NDMP_ILLEGAL_ARGS_ERR);
}
- if ((nlp->nlp_backup_path = get_backup_path(params)) == NULL)
+ if ((nlp->nlp_backup_path = get_backup_path_v2(params)) == NULL)
return (NDMP_FILE_NOT_FOUND_ERR);
if ((rv = check_backup_dir_validity(params,
@@ -1834,7 +1806,7 @@ ndmp_restore_extract_params(ndmpd_session_t *session,
}
/* Extract directory from where the backup was made. */
- if ((bkpath = get_backup_path(params)) == NULL)
+ if ((bkpath = get_backup_path_v2(params)) == NULL)
return (NDMP_ILLEGAL_ARGS_ERR);
nlp->nlp_restore_bk_path = bkpath;
@@ -1892,8 +1864,9 @@ ndmp_restore_extract_params(ndmpd_session_t *session,
* and release the snapshot at the end.
*/
int
-ndmpd_tar_backup_starter(ndmpd_module_params_t *mod_params)
+ndmpd_tar_backup_starter(void *arg)
{
+ ndmpd_module_params_t *mod_params = arg;
int err;
ndmpd_session_t *session;
ndmp_lbr_params_t *nlp;
@@ -1998,8 +1971,9 @@ ndmpd_tar_backup_abort(void *module_cookie)
*/
int
-ndmpd_tar_restore_starter(ndmpd_module_params_t *mod_params)
+ndmpd_tar_restore_starter(void *arg)
{
+ ndmpd_module_params_t *mod_params = arg;
int err;
ndmpd_session_t *session;
ndmp_lbr_params_t *nlp;
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c
index b29b5a332b..19b3e0ef2d 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -36,6 +35,8 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
+/* Copyright (c) 2007, The Storage Networking Industry Association. */
+/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
@@ -625,39 +626,6 @@ voliswr(char *path)
/*
- * get_bk_path_v3
- *
- * Get the backup path from the NDMP environment variables.
- *
- * Parameters:
- * params (input) - pointer to the parameters structure.
- *
- * Returns:
- * The backup path: if anything is specified
- * NULL: Otherwise
- */
-char *
-get_bk_path_v3(ndmpd_module_params_t *params)
-{
- char *bkpath;
-
- bkpath = MOD_GETENV(params, "PREFIX");
- if (!bkpath)
- bkpath = MOD_GETENV(params, "FILESYSTEM");
-
-
- if (!bkpath) {
- MOD_LOGV3(params, NDMP_LOG_ERROR,
- "Backup path not defined.\n");
- } else {
- NDMP_LOG(LOG_DEBUG, "bkpath: \"%s\"", bkpath);
- }
-
- return (bkpath);
-}
-
-
-/*
* is_valid_backup_dir_v3
*
* Checks the validity of the backup path. Backup path should
@@ -2454,6 +2422,7 @@ tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
nctx.nc_cmds = cmds;
nctx.nc_params = params;
+ nctx.nc_ddata = (void *) session;
if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx,
nlp->nlp_backup_path)) != 0) {
NDMP_LOG(LOG_ERR, "Pre-backup plug-in: %m");
@@ -3231,8 +3200,10 @@ ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
/* Plug-in module */
if (ndmp_pl != NULL &&
ndmp_pl->np_pre_restore != NULL) {
+ (void) memset(&nctx, 0, sizeof (ndmp_context_t));
nctx.nc_cmds = cmds;
nctx.nc_params = params;
+ nctx.nc_ddata = (void *) session;
ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
dar_index - 1);
@@ -3487,7 +3458,6 @@ get_absolute_path(const char *bkpath)
return (rv);
}
-
/*
* Expands the format string and logs the resulting message to the
* remote DMA
@@ -3591,8 +3561,10 @@ ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
/* Plug-in module */
if (ndmp_pl != NULL &&
ndmp_pl->np_pre_restore != NULL) {
+ (void) memset(&nctx, 0, sizeof (ndmp_context_t));
nctx.nc_cmds = cmds;
nctx.nc_params = params;
+ nctx.nc_ddata = (void *) session;
if ((err = ndmp_plugin_pre_restore(&nctx, params,
nlp->nlp_nfiles))
!= 0) {
@@ -3703,7 +3675,7 @@ ndmp_backup_get_params_v3(ndmpd_session_t *session,
"Internal error: NULL nlp.\n");
rv = NDMP_ILLEGAL_ARGS_ERR;
} else {
- if (!(nlp->nlp_backup_path = get_bk_path_v3(params)))
+ if (!(nlp->nlp_backup_path = get_backup_path_v3(params)))
rv = NDMP_FILE_NOT_FOUND_ERR;
else if (!is_valid_backup_dir_v3(params, nlp->nlp_backup_path))
rv = NDMP_ILLEGAL_ARGS_ERR;
@@ -3766,8 +3738,9 @@ ndmp_backup_get_params_v3(ndmpd_session_t *session,
* != 0: otherwise
*/
int
-ndmpd_tar_backup_starter_v3(ndmpd_module_params_t *params)
+ndmpd_tar_backup_starter_v3(void *arg)
{
+ ndmpd_module_params_t *params = arg;
int err;
ndmpd_session_t *session;
ndmp_lbr_params_t *nlp;
@@ -3888,7 +3861,7 @@ ndmp_restore_get_params_v3(ndmpd_session_t *session,
if (!(nlp = ndmp_get_nlp(session))) {
NDMP_LOG(LOG_DEBUG, "nlp is NULL");
rv = NDMP_ILLEGAL_ARGS_ERR;
- } else if (!(nlp->nlp_backup_path = get_bk_path_v3(params)))
+ } else if (!(nlp->nlp_backup_path = get_backup_path_v3(params)))
rv = NDMP_ILLEGAL_ARGS_ERR;
else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
@@ -3943,8 +3916,9 @@ ndmp_restore_get_params_v3(ndmpd_session_t *session,
* != NDMP_NO_ERR: otherwise
*/
int
-ndmpd_tar_restore_starter_v3(ndmpd_module_params_t *params)
+ndmpd_tar_restore_starter_v3(void *arg)
{
+ ndmpd_module_params_t *params = arg;
int err;
ndmpd_session_t *session;
ndmp_lbr_params_t *nlp;
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c
index 80a08e55a8..2769147231 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -2742,3 +2741,11 @@ ndmp_context_get_specific(ndmp_context_t *nctx)
{
return (nctx->nc_pldata);
}
+
+ndmpd_backup_type_t
+ndmp_get_backup_type(ndmp_context_t *ctx)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)ctx->nc_ddata;
+
+ return (session->ns_butype);
+}
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c
new file mode 100644
index 0000000000..6a57828a24
--- /dev/null
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c
@@ -0,0 +1,2336 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * BSD 3 Clause License
+ *
+ * Copyright (c) 2007, The Storage Networking Industry Association.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of The Storage Networking Industry Association (SNIA)
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* Copyright (c) 2007, The Storage Networking Industry Association. */
+/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/lwp.h>
+#include <sys/fs/zfs.h>
+#include <sys/mtio.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <libzfs.h>
+#include <stdio.h>
+#include "ndmpd_common.h"
+#include "ndmpd.h"
+
+typedef struct {
+ char nzs_findprop[ZFS_MAXPROPLEN]; /* prop substring to find */
+ char nzs_snapname[ZFS_MAXNAMELEN]; /* snap's name */
+ char nzs_snapprop[ZFS_MAXPROPLEN]; /* snap's prop value */
+ char nzs_snapskip[ZFS_MAXPROPLEN]; /* snap to skip */
+ uint32_t nzs_prop_major; /* property major version */
+ uint32_t nzs_prop_minor; /* property minor version */
+} ndmpd_zfs_snapfind_t;
+
+mutex_t ndmpd_zfs_fd_lock;
+
+static int ndmpd_zfs_open_fds(ndmpd_zfs_args_t *);
+static void ndmpd_zfs_close_fds(ndmpd_zfs_args_t *);
+
+static void ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *, int);
+
+static int ndmpd_zfs_header_write(ndmpd_session_t *);
+static int ndmpd_zfs_header_read(ndmpd_zfs_args_t *);
+
+static int ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *);
+
+static int ndmpd_zfs_restore(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *);
+
+static int ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *, int **, int **);
+
+static int ndmpd_zfs_is_spanning(ndmpd_zfs_args_t *);
+
+static boolean_t ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *, char *, int);
+static int ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *);
+
+static boolean_t ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *);
+
+static int ndmpd_zfs_getenv(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *);
+static boolean_t ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *, char *);
+static boolean_t ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *);
+
+static int ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *, int);
+static int ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *,
+ boolean_t, ndmpd_zfs_snapfind_t *);
+static boolean_t ndmpd_zfs_snapshot_ndmpd_generated(char *);
+static int ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *, ndmpd_zfs_snapfind_t *);
+
+static int ndmpd_zfs_snapshot_prop_find(zfs_handle_t *, void *);
+static int ndmpd_zfs_snapshot_prop_get(zfs_handle_t *, char *);
+static int ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *);
+static int ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *, char *,
+ boolean_t *);
+static int ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *, char *, int,
+ boolean_t);
+static int ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *,
+ ndmpd_zfs_snapfind_t *);
+static boolean_t ndmpd_zfs_prop_version_check(char *, uint32_t *, uint32_t *);
+
+static int ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *, char *, int);
+
+static void ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *);
+
+static int ndmpd_zfs_backup(ndmpd_zfs_args_t *);
+
+#define snapshot_create chkpnt_backup_prepare
+#define snapshot_destroy chkpnt_backup_successful
+
+/*
+ * Syntax for com.sun.ndmp:incr property value:
+ * #.#.n|u/$LEVEL.$DMP_NAME.$ZFS_MODE(/ ...)
+ *
+ * where
+ * #.# is the version number
+ * 'n' means ndmp-generated; 'u' means user-supplied
+ * $LEVEL: backup (incremental) level [0-9]
+ * $DMP_NAME: set name [default: "level"]
+ * $ZFS_MODE: d | r | p [for dataset, recursive, or package]
+ *
+ * Examples:
+ *
+ * 0.0.n/0.bob.p
+ * 0.0.u/1.bob.p/0.jane.d
+ */
+
+#define NDMPD_ZFS_PROP_INCR "com.sun.ndmp:incr"
+
+/*
+ * NDMPD_ZFS_LOG_ZERR
+ *
+ * As coded, there should be no races in the retrieval of the ZFS errno
+ * from the ndmpd_zfs_args->nz_zlibh. I.e., for a given ndmpd_zfs backup
+ * or restore, there should only ever be one ZFS library call taking place
+ * at any one moment in time.
+ */
+
+#define NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, ...) { \
+ NDMP_LOG(LOG_ERR, __VA_ARGS__); \
+ NDMP_LOG(LOG_ERR, "%s--%s", \
+ libzfs_error_action((ndmpd_zfs_args)->nz_zlibh), \
+ libzfs_error_description((ndmpd_zfs_args)->nz_zlibh)); \
+ ndmpd_zfs_zerr_dma_log((ndmpd_zfs_args)); \
+}
+
+int
+ndmpd_zfs_init(ndmpd_session_t *session)
+{
+ ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
+ int version = session->ns_protocol_version;
+
+ bzero(ndmpd_zfs_args, sizeof (*ndmpd_zfs_args));
+
+ if ((version < NDMPV3) || (version > NDMPV4)) {
+ NDMP_LOG(LOG_ERR, "Unknown or unsupported version %d", version);
+ return (-1);
+ }
+
+ if ((ndmpd_zfs_args->nz_zlibh = libzfs_init()) == NULL) {
+ NDMP_LOG(LOG_ERR, "libzfs init error [%d]", errno);
+ return (-1);
+ }
+
+ if (ndmpd_zfs_open_fds(ndmpd_zfs_args) < 0) {
+ NDMP_LOG(LOG_ERR, "open_fds() failure(): %d\n", errno);
+ return (-1);
+ }
+
+ ndmpd_zfs_args->nz_bufsize = ndmp_buffer_get_size(session);
+ ndmpd_zfs_args->nz_window_len = session->ns_mover.md_window_length;
+
+ ndmpd_zfs_args->nz_nlp = ndmp_get_nlp(session);
+
+ assert(ndmpd_zfs_args->nz_nlp != NULL);
+
+ ndmpd_zfs_args->nz_nlp->nlp_bytes_total = 0;
+
+ session->ns_data.dd_module.dm_module_cookie = ndmpd_zfs_args;
+ session->ns_data.dd_data_size = 0;
+ session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
+ session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
+
+ session->ns_data.dd_bytes_left_to_read = 0;
+ session->ns_data.dd_position = 0;
+ session->ns_data.dd_discard_length = 0;
+ session->ns_data.dd_read_offset = 0;
+ session->ns_data.dd_read_length = 0;
+
+ ndmpd_zfs_params->mp_get_env_func = ndmpd_api_get_env;
+ ndmpd_zfs_params->mp_add_env_func = ndmpd_api_add_env;
+ ndmpd_zfs_params->mp_set_env_func = ndmpd_api_set_env;
+ ndmpd_zfs_params->mp_dispatch_func = ndmpd_api_dispatch;
+ ndmpd_zfs_params->mp_daemon_cookie = (void *)session;
+ ndmpd_zfs_params->mp_protocol_version = session->ns_protocol_version;
+ ndmpd_zfs_params->mp_stats = &session->ns_data.dd_module.dm_stats;
+ ndmpd_zfs_params->mp_add_file_handler_func =
+ ndmpd_api_add_file_handler;
+ ndmpd_zfs_params->mp_remove_file_handler_func =
+ ndmpd_api_remove_file_handler;
+ ndmpd_zfs_params->mp_seek_func = 0;
+
+ switch (version) {
+ case NDMPV3:
+ ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
+ ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
+ ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
+ ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
+ ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v3;
+ ndmpd_zfs_params->mp_file_recovered_func =
+ ndmpd_api_file_recovered_v3;
+ break;
+ case NDMPV4:
+ ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
+ ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
+ ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
+ ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
+ ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v4;
+ ndmpd_zfs_params->mp_file_recovered_func =
+ ndmpd_api_file_recovered_v4;
+ break;
+ default:
+ /* error already returned above for this case */
+ break;
+ }
+
+ return (0);
+}
+
+void
+ndmpd_zfs_fini(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ libzfs_fini(ndmpd_zfs_args->nz_zlibh);
+
+ ndmpd_zfs_close_fds(ndmpd_zfs_args);
+}
+
+static int
+ndmpd_zfs_open_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ int err;
+
+ err = pipe(ndmpd_zfs_args->nz_pipe_fd);
+ if (err)
+ NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n", strerror(errno));
+
+ return (err);
+}
+
+/*
+ * ndmpd_zfs_close_fds()
+ *
+ * In the abort case, use dup2() to redirect the end of the pipe that is
+ * being written to (to a new pipe). Close the ends of the new pipe to cause
+ * EPIPE to be returned to the writing thread. This will cause the writer
+ * and reader to terminate without having any of the writer's data erroneously
+ * go to any reopened descriptor.
+ */
+
+static void
+ndmpd_zfs_close_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ int pipe_end;
+ int fds[2];
+
+ if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE) {
+ ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
+ ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
+ return;
+ }
+
+ (void) mutex_lock(&ndmpd_zfs_fd_lock);
+
+ if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) {
+ pipe_end = PIPE_ZFS;
+ } else {
+ pipe_end = PIPE_TAPE;
+ }
+
+ if (ndmpd_zfs_args->nz_pipe_fd[pipe_end] != -1) {
+ if (pipe(fds) != 0) {
+ (void) mutex_unlock(&ndmpd_zfs_fd_lock);
+ NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n",
+ strerror(errno));
+ return;
+ }
+
+ (void) dup2(fds[0], ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
+ (void) close(fds[0]);
+ (void) close(fds[1]);
+
+ ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
+ }
+
+ (void) mutex_unlock(&ndmpd_zfs_fd_lock);
+}
+
+static void
+ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *ndmpd_zfs_args, int pipe_end)
+{
+ (void) mutex_lock(&ndmpd_zfs_fd_lock);
+ (void) close(ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
+ ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
+ (void) mutex_unlock(&ndmpd_zfs_fd_lock);
+}
+
+static int
+ndmpd_zfs_header_write(ndmpd_session_t *session)
+{
+ ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
+ int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
+ ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
+ char *buf;
+
+ buf = ndmp_malloc(bufsize);
+ if (buf == NULL) {
+ NDMP_LOG(LOG_DEBUG, "buf NULL");
+ return (-1);
+ }
+
+ (void) strlcpy(tape_header->nzh_magic, NDMPUTF8MAGIC,
+ sizeof (NDMPUTF8MAGIC));
+ tape_header->nzh_major = LE_32(NDMPD_ZFS_MAJOR_VERSION);
+ tape_header->nzh_minor = LE_32(NDMPD_ZFS_MINOR_VERSION);
+ tape_header->nzh_hdrlen = LE_32(bufsize);
+
+ bzero(buf, bufsize);
+ (void) memcpy(buf, tape_header, sizeof (ndmpd_zfs_header_t));
+
+ NDMP_LOG(LOG_DEBUG, "header (major, minor, length): %u %u %u",
+ NDMPD_ZFS_MAJOR_VERSION,
+ NDMPD_ZFS_MINOR_VERSION,
+ bufsize);
+
+ if (MOD_WRITE(ndmpd_zfs_params, buf, bufsize) != 0) {
+ free(buf);
+ NDMP_LOG(LOG_ERR, "MOD_WRITE error");
+ return (-1);
+ }
+
+ free(buf);
+
+ session->ns_data.dd_module.dm_stats.ms_bytes_processed = bufsize;
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_header_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
+ ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
+ uint32_t hdrlen;
+ int32_t header_left;
+ int err;
+ char *buf;
+
+ buf = ndmp_malloc(bufsize);
+ if (buf == NULL) {
+ NDMP_LOG(LOG_DEBUG, "buf NULL");
+ return (-1);
+ }
+
+ bzero(buf, bufsize);
+
+ /*
+ * Read nz_bufsize worth of bytes first (the size of a mover record).
+ */
+
+ err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
+
+ if (err != 0) {
+ NDMP_LOG(LOG_ERR, "MOD_READ error: %d", err);
+ free(buf);
+ return (-1);
+ }
+
+ (void) memcpy(tape_header, buf, sizeof (ndmpd_zfs_header_t));
+
+
+ if (strcmp(tape_header->nzh_magic, NDMPUTF8MAGIC) != 0) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "bad magic string\n");
+ goto _err;
+ }
+
+ if (tape_header->nzh_major > LE_32(NDMPD_ZFS_MAJOR_VERSION)) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "major number larger than supported: (%d %d)\n",
+ LE_32(tape_header->nzh_major), NDMPD_ZFS_MAJOR_VERSION);
+ goto _err;
+ }
+
+ /*
+ * Major version 0 (regardless of minor version):
+ * Header must be a multiple of the mover record size.
+ */
+
+ hdrlen = LE_32(tape_header->nzh_hdrlen);
+ if (hdrlen > bufsize) {
+ header_left = hdrlen - bufsize;
+ while (header_left > 0) {
+ err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
+ if (err == -1) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args,
+ NDMP_LOG_ERROR, "bad header\n");
+ goto _err;
+ }
+ header_left -= bufsize;
+ }
+ }
+
+ NDMP_LOG(LOG_DEBUG, "tape header: %s; %u %u; %u ",
+ tape_header->nzh_magic,
+ LE_32(tape_header->nzh_major),
+ LE_32(tape_header->nzh_minor),
+ LE_32(tape_header->nzh_hdrlen));
+
+ ndmpd_zfs_args->nz_nlp->nlp_bytes_total = hdrlen;
+
+ free(buf);
+ return (0);
+
+_err:
+
+ NDMP_LOG(LOG_ERR, "tape header: %s; %u %u; %u ",
+ tape_header->nzh_magic,
+ LE_32(tape_header->nzh_major),
+ LE_32(tape_header->nzh_minor),
+ LE_32(tape_header->nzh_hdrlen));
+
+ free(buf);
+ return (-1);
+}
+
+int
+ndmpd_zfs_backup_starter(void *arg)
+{
+ ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ int cleanup_err = 0;
+ int err = 0;
+
+ ndmp_session_ref(session);
+
+ if (ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args) != 0) {
+ err = -1;
+ goto _done;
+ }
+
+ err = ndmpd_zfs_backup(ndmpd_zfs_args);
+
+ cleanup_err = ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args, err);
+
+ NDMP_LOG(LOG_DEBUG,
+ "data bytes_total(including header):%llu",
+ session->ns_data.dd_module.dm_stats.ms_bytes_processed);
+
+ err |= cleanup_err;
+
+_done:
+ NS_DEC(nbk);
+ MOD_DONE(ndmpd_zfs_params, err ? err : cleanup_err);
+ ndmp_session_unref(session);
+ ndmpd_zfs_fini(ndmpd_zfs_args);
+
+ return (err);
+}
+
+static int
+ndmpd_zfs_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ int *read_err = NULL;
+ int *write_err = NULL;
+ int result = 0;
+ int err;
+
+ if (session->ns_eof)
+ return (-1);
+
+ if (!session->ns_data.dd_abort) {
+ if (ndmpd_zfs_header_write(session)) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "ndmpd_zfs header write error\n");
+ return (-1);
+ }
+
+ err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
+ &read_err, &write_err);
+
+ if (err || read_err || write_err || session->ns_eof)
+ result = EPIPE;
+ }
+
+ if (session->ns_data.dd_abort) {
+ ndmpd_audit_backup(session->ns_connection,
+ ndmpd_zfs_args->nz_dataset,
+ session->ns_data.dd_data_addr.addr_type,
+ ndmpd_zfs_args->nz_dataset, EINTR);
+ NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
+ ndmpd_zfs_args->nz_dataset);
+
+ (void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
+ err = -1;
+ } else {
+ ndmpd_audit_backup(session->ns_connection,
+ ndmpd_zfs_args->nz_dataset,
+ session->ns_data.dd_data_addr.addr_type,
+ ndmpd_zfs_args->nz_dataset, result);
+
+ err = ndmpd_zfs_post_backup(ndmpd_zfs_args);
+ if (err || result)
+ err = -1;
+
+ if (err == 0) {
+ NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished.",
+ ndmpd_zfs_args->nz_dataset);
+ } else {
+ NDMP_LOG(LOG_DEBUG, "An error occurred while backing up"
+ " \"%s\"", ndmpd_zfs_args->nz_dataset);
+ }
+ }
+
+ return (err);
+}
+
+/*
+ * ndmpd_zfs_backup_send_read()
+ *
+ * This routine executes zfs_send() to create the backup data stream.
+ * The value of ZFS_MODE determines the type of zfs_send():
+ * dataset ('d'): Only the dataset specified (i.e., top level) is backed up
+ * recursive ('r'): The dataset and its child file systems are backed up
+ * package ('p'): Same as 'r', except all intermediate snapshots are also
+ * backed up
+ *
+ * Volumes do not have descednants, so 'd' and 'r' produce equivalent results.
+ */
+
+static int
+ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ sendflags_t flags = { 0 };
+ char *fromsnap = NULL;
+ zfs_handle_t *zhp;
+ int err;
+
+ zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
+ ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
+
+ if (!zhp) {
+ if (!session->ns_data.dd_abort)
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
+ return (-1);
+ }
+
+ switch (ndmpd_zfs_args->nz_zfs_mode) {
+ case ('d'):
+ flags.props = B_TRUE;
+ break;
+ case ('r'):
+ flags.replicate = B_TRUE;
+ break;
+ case ('p'):
+ flags.doall = B_TRUE;
+ flags.replicate = B_TRUE;
+ break;
+ default:
+ NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c",
+ ndmpd_zfs_args->nz_zfs_mode);
+ zfs_close(zhp);
+ return (-1);
+ }
+
+ if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
+ if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') {
+ NDMP_LOG(LOG_ERR, "no fromsnap");
+ zfs_close(zhp);
+ return (-1);
+ }
+ fromsnap = ndmpd_zfs_args->nz_fromsnap;
+ }
+
+ err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, flags,
+ ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL);
+
+ if (err && !session->ns_data.dd_abort)
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err);
+
+ zfs_close(zhp);
+
+ return (err);
+}
+
+/*
+ * ndmpd_zfs_backup_tape_write()
+ *
+ * The data begins on a mover record boundary (because
+ * the header is the size of a mover record--i.e.
+ * ndmpd_zfs_args->nz_bufsize).
+ */
+
+static int
+ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ int bufsize = ndmpd_zfs_args->nz_bufsize;
+ u_longlong_t *bytes_totalp;
+ int count;
+ char *buf;
+
+ buf = ndmp_malloc(bufsize);
+ if (buf == NULL) {
+ NDMP_LOG(LOG_DEBUG, "buf NULL");
+ return (-1);
+ }
+
+ bytes_totalp =
+ &(session->ns_data.dd_module.dm_stats.ms_bytes_processed);
+
+ for (;;) {
+ bzero(buf, bufsize);
+
+ count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
+ bufsize);
+
+ if (count == 0) /* EOF */ {
+ NDMP_LOG(LOG_DEBUG,
+ "zfs_send stream size: %llu bytes (sans header)",
+ *bytes_totalp - bufsize);
+ free(buf);
+ return (0);
+ }
+
+ if (count == -1) {
+ NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)",
+ errno);
+ free(buf);
+ return (-1);
+ }
+
+ if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) {
+ (void) ndmpd_zfs_abort((void *) ndmpd_zfs_args);
+ NDMP_LOG(LOG_ERR, "MOD_WRITE error");
+ free(buf);
+ return (-1);
+ }
+
+ *bytes_totalp += count;
+ }
+ /* NOTREACHED */
+}
+
+int
+ndmpd_zfs_restore_starter(void *arg)
+{
+ ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ int err;
+
+ ndmp_session_ref(session);
+
+ err = ndmpd_zfs_restore(ndmpd_zfs_args);
+
+ MOD_DONE(ndmpd_zfs_params, err);
+
+ NS_DEC(nrs);
+
+ ndmp_session_unref(session);
+
+ ndmpd_zfs_fini(ndmpd_zfs_args);
+
+ return (err);
+}
+
+static int
+ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ int *read_err = NULL;
+ int *write_err = NULL;
+ int result = 0;
+ int err;
+
+ if (!session->ns_data.dd_abort) {
+ if (ndmpd_zfs_header_read(ndmpd_zfs_args)) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "ndmpd_zfs header read error\n");
+ return (-1);
+ }
+
+ err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
+ &write_err, &read_err);
+
+ if (err || read_err || write_err || session->ns_eof)
+ result = EIO;
+ }
+
+ if (session->ns_data.dd_abort) {
+ NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
+ ndmpd_zfs_args->nz_dataset);
+ ndmpd_audit_restore(session->ns_connection,
+ ndmpd_zfs_args->nz_dataset,
+ session->ns_data.dd_data_addr.addr_type,
+ ndmpd_zfs_args->nz_dataset, EINTR);
+ (void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
+ err = -1;
+ } else {
+ ndmpd_audit_restore(session->ns_connection,
+ ndmpd_zfs_args->nz_dataset,
+ session->ns_data.dd_data_addr.addr_type,
+ ndmpd_zfs_args->nz_dataset, result);
+ err = ndmpd_zfs_post_restore(ndmpd_zfs_args);
+ if (err || result)
+ err = -1;
+
+ if (err == 0) {
+ NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished",
+ ndmpd_zfs_args->nz_dataset);
+ } else {
+ NDMP_LOG(LOG_DEBUG, "An error occurred while restoring"
+ " to \"%s\"", ndmpd_zfs_args->nz_dataset);
+ }
+ }
+
+ return (err);
+}
+
+static int
+ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ int bufsize = ndmpd_zfs_args->nz_bufsize;
+ u_longlong_t *bytes_totalp;
+ char *buf;
+ int count;
+ int err;
+
+ buf = ndmp_malloc(bufsize);
+ if (buf == NULL) {
+ NDMP_LOG(LOG_DEBUG, "buf NULL");
+ return (-1);
+ }
+
+ bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total;
+
+ for (;;) {
+ err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
+
+ if (err == -1) {
+ NDMP_LOG(LOG_DEBUG, "end of data (%llu) bytes",
+ *bytes_totalp);
+ (void) write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE],
+ buf, bufsize);
+ break;
+ }
+
+ count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
+ bufsize);
+
+ if (count == -1) {
+ free(buf);
+
+ if ((errno == EPIPE) && !session->ns_data.dd_abort) {
+ NDMP_LOG(LOG_DEBUG, "EPIPE; count == -1; "
+ "[%llu bytes] returning success",
+ *bytes_totalp);
+ return (0);
+ }
+
+ if (session->ns_data.dd_abort)
+ NDMP_LOG(LOG_DEBUG, "abort set");
+
+ NDMP_LOG(LOG_DEBUG, "pipe write error:"
+ "errno: %d", errno);
+
+ return (-1);
+ }
+
+ *bytes_totalp += count;
+
+ /*
+ * A short write to the pipe indicates the
+ * other peer is terminated so we should exit
+ */
+
+ if (count != bufsize) {
+ NDMP_LOG(LOG_DEBUG, "count != bufsize:"
+ "count: %d; bufsize: %d",
+ count, bufsize);
+ free(buf);
+ return (0);
+ }
+
+ /* Checks for local mover */
+ if (*bytes_totalp == ndmpd_zfs_args->nz_window_len) {
+ NDMP_LOG(LOG_DEBUG, "Reached EOW at %lld",
+ *bytes_totalp);
+ if (ndmpd_zfs_is_spanning(ndmpd_zfs_args) == 0) {
+ NDMP_LOG(LOG_DEBUG, "Exit");
+ break;
+ }
+ NDMP_LOG(LOG_DEBUG, "Continue through spanning");
+ }
+ }
+
+ free(buf);
+ return (0);
+}
+
+/*
+ * ndmpd_zfs_restore_recv_write()
+ *
+ * This routine executes zfs_receive() to restore the backup.
+ */
+
+static int
+ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ recvflags_t flags;
+ int err;
+
+ bzero(&flags, sizeof (recvflags_t));
+
+ flags.nomount = B_TRUE;
+
+ if (ndmpd_zfs_args->nz_zfs_force)
+ flags.force = B_TRUE;
+
+ err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
+ flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL);
+
+ if (err && !session->ns_data.dd_abort)
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err);
+
+ return (err);
+}
+
+/*
+ * ndmpd_zfs_is_spanning()
+ *
+ * Check to see if the tape is at spanning point
+ */
+
+static int
+ndmpd_zfs_is_spanning(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ int count = session->ns_mover.md_record_size;
+ char *buf;
+
+ if ((buf = ndmp_malloc(count)) == NULL)
+ return (0);
+
+ if (read(session->ns_tape.td_fd, buf, count) == 0) {
+ free(buf);
+ return (1);
+ }
+
+ (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSR, 1);
+ free(buf);
+ return (0);
+}
+
+/*
+ * ndmpd_zfs_reader_writer()
+ *
+ * Two separate threads are used for actual backup or restore.
+ */
+
+static int
+ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args,
+ int **sendrecv_errp, int **tape_errp)
+{
+ funct_t sendrecv_func;
+ funct_t tape_func;
+ int sendrecv_err;
+ int tape_err;
+
+ switch (ndmpd_zfs_params->mp_operation) {
+ case NDMP_DATA_OP_BACKUP:
+ sendrecv_func = (funct_t)ndmpd_zfs_backup_send_read;
+ tape_func = (funct_t)ndmpd_zfs_backup_tape_write;
+ break;
+ case NDMP_DATA_OP_RECOVER:
+ sendrecv_func = (funct_t)ndmpd_zfs_restore_recv_write;
+ tape_func = (funct_t)ndmpd_zfs_restore_tape_read;
+ break;
+ }
+
+ sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread,
+ NULL, sendrecv_func, ndmpd_zfs_args);
+
+ if (sendrecv_err == 0) {
+ tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread,
+ NULL, tape_func, ndmpd_zfs_args);
+
+ if (tape_err) {
+ /*
+ * The close of the tape side of the pipe will cause
+ * nz_sendrecv_thread to error in the zfs_send/recv()
+ * call and to return. Hence we do not need
+ * to explicitly cancel the sendrecv_thread here
+ * (the pthread_join() below is sufficient).
+ */
+
+ (void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]);
+ NDMP_LOG(LOG_ERR, "Could not start tape thread; "
+ "aborting z-op");
+ }
+
+ (void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread,
+ (void **) sendrecv_errp);
+ }
+
+ if ((tape_err == 0) &&
+ (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER))
+ ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
+
+ ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
+
+ if ((sendrecv_err == 0) && (tape_err == 0)) {
+ (void) pthread_join(ndmpd_zfs_args->nz_tape_thread,
+ (void **) tape_errp);
+ }
+
+ if ((tape_err == 0) &&
+ (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP))
+ ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
+
+ return (sendrecv_err ? sendrecv_err : tape_err);
+}
+
+int
+ndmpd_zfs_abort(void *arg)
+{
+ ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
+ char str[8];
+
+ if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)
+ (void) strlcpy(str, "backup", 8);
+ else
+ (void) strlcpy(str, "recover", 8);
+
+ NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation",
+ str);
+
+ ndmpd_zfs_close_fds(ndmpd_zfs_args);
+
+ return (0);
+}
+
+/*
+ * ndmpd_zfs_pre_backup()
+ *
+ * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL.
+ * This ensures that ndmp_include_zfs() will fail, which is
+ * a requirement for "zfs"-type backup.
+ */
+
+int
+ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
+ int err;
+
+ if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL)
+ return (0);
+
+ (void) memset(nctxp, 0, sizeof (ndmp_context_t));
+ nctxp->nc_plversion = ndmp_pl->np_plversion;
+ nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
+ nctxp->nc_ddata = (void *) session;
+
+ err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp,
+ ndmpd_zfs_args->nz_dataset);
+
+ if (err != 0) {
+ NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m");
+ (void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
+ }
+
+ return (err);
+}
+
+int
+ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
+ int err = 0;
+
+ if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL)
+ return (0);
+
+ err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err);
+
+ if (err == -1)
+ NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
+
+ return (err);
+}
+
+int
+ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
+ char bkpath[ZFS_MAXNAMELEN];
+ int err;
+
+ if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL)
+ return (0);
+
+ err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath, ZFS_MAXNAMELEN);
+
+ if (err != 0) {
+ NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err);
+ return (-1);
+ }
+
+ err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args);
+
+ if (err != 0) {
+ NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err);
+ return (-1);
+ }
+
+ (void) memset(nctxp, 0, sizeof (ndmp_context_t));
+ nctxp->nc_ddata = (void *) session;
+
+ err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath,
+ ndmpd_zfs_args->nz_dataset);
+
+ if (err != 0) {
+ NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
+ int err = 0;
+
+ if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL)
+ return (0);
+
+ err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err);
+
+ if (err == -1)
+ NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
+
+ return (err);
+}
+
+boolean_t
+ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_zfs_snapfind_t snapdata;
+
+ if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0)
+ return (B_FALSE);
+
+ if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args))
+ return (B_FALSE);
+
+ if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
+ (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
+ snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE);
+
+ snapdata.nzs_snapname[0] = '\0';
+ snapdata.nzs_snapprop[0] = '\0';
+
+ if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata))
+ return (B_FALSE);
+
+ if (snapdata.nzs_snapname[0] == '\0') { /* not found */
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Snapshot for level %d does not exist\n",
+ ndmpd_zfs_args->nz_level-1);
+ return (B_FALSE);
+ }
+
+ (void) strlcpy(ndmpd_zfs_args->nz_fromsnap,
+ snapdata.nzs_snapname, ZFS_MAXNAMELEN);
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * ndmpd_zfs_backup_pathvalid()
+ *
+ * Make sure the path is of an existing dataset
+ */
+
+static boolean_t
+ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ char zpath[ZFS_MAXNAMELEN];
+ char propstr[ZFS_MAXPROPLEN];
+ zfs_handle_t *zhp;
+ zfs_type_t ztype = 0;
+ int err;
+
+ if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, ZFS_MAXNAMELEN)
+ != 0)
+ return (B_FALSE);
+
+ if (ndmpd_zfs_args->nz_snapname[0] != '\0') {
+ zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath,
+ ZFS_TYPE_SNAPSHOT);
+
+ if (!zhp) {
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args,
+ "zfs_open (snap)");
+ ndmpd_zfs_args->nz_snapname[0] = '\0';
+ ndmpd_zfs_args->nz_dataset[0] = '\0';
+ return (B_FALSE);
+ }
+
+ err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
+
+ zfs_close(zhp);
+
+ if (err) {
+ NDMP_LOG(LOG_DEBUG,
+ "ndmpd_zfs_snapshot_prop_get failed");
+ return (-1);
+ }
+
+ if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "cannot use an ndmpd-generated snapshot\n");
+ return (B_FALSE);
+ }
+ }
+
+ zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
+ ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET);
+
+ if (zhp) {
+ ztype = zfs_get_type(zhp);
+ zfs_close(zhp);
+ }
+
+ if ((ztype == ZFS_TYPE_VOLUME) ||
+ (ztype == ZFS_TYPE_FILESYSTEM)) {
+ ndmpd_zfs_args->nz_type = ztype;
+ return (B_TRUE);
+ }
+
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Invalid file system or volume.\n");
+
+ return (B_FALSE);
+}
+
+/*
+ * ndmpd_zfs_backup_getpath()
+ *
+ * Retrieve the backup path from the environment, which should
+ * be of the form "/dataset[@snap]". The leading slash is required
+ * by certain DMA's but can otherwise be ignored.
+ *
+ * (Note: "dataset" can consist of more than one component,
+ * e.g. "pool", "pool/volume", "pool/fs/fs2".)
+ *
+ * The dataset name and the snapshot name (if any) will be
+ * stored in ndmpd_zfs_args.
+ */
+
+static int
+ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath,
+ int zlen)
+{
+ char *env_path;
+ char *at;
+
+ env_path = get_backup_path_v3(ndmpd_zfs_params);
+ if (env_path == NULL)
+ return (-1);
+
+ if (env_path[0] != '/') {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Invalid path: %s (leading slash required)\n", env_path);
+ return (-1);
+ }
+
+ (void) strlcpy(zpath, &env_path[1], zlen);
+ (void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1],
+ ZFS_MAXNAMELEN);
+
+ at = strchr(ndmpd_zfs_args->nz_dataset, '@');
+ if (at) {
+ *at = '\0';
+ (void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at,
+ ZFS_MAXNAMELEN);
+ } else {
+ ndmpd_zfs_args->nz_snapname[0] = '\0';
+ }
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ return (ndmpd_zfs_getenv(ndmpd_zfs_args));
+}
+
+boolean_t
+ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0)
+ return (B_FALSE);
+
+ if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+static boolean_t
+ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ zfs_handle_t *zhp;
+ char *at;
+
+ if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0)
+ return (B_FALSE);
+
+ at = strchr(ndmpd_zfs_args->nz_dataset, '@');
+
+ if (at) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
+ "%s ignored in restore path\n", at);
+ *at = '\0';
+ }
+
+ ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
+
+ zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
+ ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
+
+ if (zhp) {
+ zfs_close(zhp);
+
+ if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Restore dataset exists.\n"
+ "A nonexistent dataset must be specified "
+ "for 'zfs' non-incremental restore.\n");
+ return (B_FALSE);
+ }
+ }
+
+ NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset);
+
+ return (B_TRUE);
+}
+
+/*
+ * ndmpd_zfs_restore_getpath()
+ *
+ * Be sure to not include the leading slash, which is required for
+ * compatibility with backup applications (NBU) but which is not part
+ * of the ZFS syntax. (Note that this done explicitly in all paths
+ * below except those calling ndmpd_zfs_backup_getpath(), because it is
+ * already stripped in that function.)
+ *
+ * In addition, the DMA might add a trailing slash to the path.
+ * Strip all such slashes.
+ */
+
+static int
+ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ int version = ndmpd_zfs_params->mp_protocol_version;
+ char zpath[ZFS_MAXNAMELEN];
+ mem_ndmp_name_v3_t *namep_v3;
+ char *dataset = ndmpd_zfs_args->nz_dataset;
+ char *nm;
+ char *p;
+ int len;
+ int err;
+
+ dataset = ndmpd_zfs_args->nz_dataset;
+
+ namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0);
+
+ if (namep_v3 == NULL) {
+ NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]");
+ return (-1);
+ }
+
+ if (namep_v3->nm3_dpath) {
+ if (namep_v3->nm3_dpath[0] != '/') {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Invalid path: %s (leading slash required)\n",
+ namep_v3->nm3_dpath);
+ return (-1);
+ }
+
+ (void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]),
+ ZFS_MAXNAMELEN);
+
+ if (namep_v3->nm3_newnm) {
+ (void) strlcat(dataset, "/", ZFS_MAXNAMELEN);
+ (void) strlcat(dataset, namep_v3->nm3_newnm,
+ ZFS_MAXNAMELEN);
+
+ } else {
+ if (version == NDMPV3) {
+ /*
+ * The following does not apply for V4.
+ *
+ * Find the last component of nm3_opath.
+ * nm3_opath has no trailing '/'.
+ */
+ p = strrchr(namep_v3->nm3_opath, '/');
+ nm = p? p : namep_v3->nm3_opath;
+ (void) strlcat(dataset, "/", ZFS_MAXNAMELEN);
+ (void) strlcat(dataset, nm, ZFS_MAXNAMELEN);
+ }
+ }
+ } else {
+ err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
+ ZFS_MAXNAMELEN);
+ if (err)
+ return (err);
+ }
+
+ len = strlen(dataset);
+ while (dataset[len-1] == '/') {
+ dataset[len-1] = '\0';
+ len--;
+ }
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ return (ndmpd_zfs_getenv(ndmpd_zfs_args));
+}
+
+static int
+ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+
+ if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0)
+ return (-1);
+
+ if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0)
+ return (-1);
+
+ if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0)
+ return (-1);
+
+ if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0)
+ return (-1);
+
+ if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ char *envp;
+
+ envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE");
+
+ if (envp == NULL) {
+ NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, "
+ "defaulting to recursive");
+ ndmpd_zfs_args->nz_zfs_mode = 'r';
+ return (0);
+ }
+
+ if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) {
+ ndmpd_zfs_args->nz_zfs_mode = 'd';
+ } else if ((strcmp(envp, "recursive") == 0) ||
+ (strcmp(envp, "r") == 0)) {
+ ndmpd_zfs_args->nz_zfs_mode = 'r';
+ } else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) {
+ ndmpd_zfs_args->nz_zfs_mode = 'p';
+ } else {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Invalid ZFS_MODE value \"%s\".\n", envp);
+ return (-1);
+ }
+
+ NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"",
+ ndmpd_zfs_args->nz_zfs_mode);
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ char *envp_force;
+
+ envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE");
+
+ if (envp_force == NULL) {
+ NDMP_LOG(LOG_DEBUG,
+ "env(ZFS_FORCE) not specified, defaulting to FALSE");
+ ndmpd_zfs_args->nz_zfs_force = B_FALSE;
+ return (0);
+ }
+
+ /*
+ * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
+ */
+
+ if (strchr("tTyY", *envp_force))
+ ndmpd_zfs_args->nz_zfs_force = B_TRUE;
+
+ NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force);
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ char *envp;
+
+ envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL");
+
+ if (envp == NULL) {
+ NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, "
+ "defaulting to 0");
+ ndmpd_zfs_args->nz_level = 0;
+ return (0);
+ }
+
+ if (envp[1] != '\0') {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Invalid backup level \"%s\".\n", envp);
+ return (-1);
+ }
+
+ if (!isdigit(*envp)) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Invalid backup level \"%s\".\n", envp);
+ return (-1);
+ }
+
+ ndmpd_zfs_args->nz_level = atoi(envp);
+
+ NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"",
+ ndmpd_zfs_args->nz_level);
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ char *envp_update;
+
+ envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE");
+
+ if (envp_update == NULL) {
+ NDMP_LOG(LOG_DEBUG,
+ "env(UPDATE) not specified, defaulting to TRUE");
+ ndmpd_zfs_args->nz_update = B_TRUE;
+ return (0);
+ }
+
+ /*
+ * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
+ */
+
+ if (strchr("tTyY", *envp_update))
+ ndmpd_zfs_args->nz_update = B_TRUE;
+
+ NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update);
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ char *envp;
+
+ envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME");
+
+ if (envp == NULL) {
+ NDMP_LOG(LOG_DEBUG,
+ "env(DMP_NAME) not specified, defaulting to 'level'");
+ (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level",
+ NDMPD_ZFS_DMP_NAME_MAX);
+ return (0);
+ }
+
+ if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp))
+ return (-1);
+
+ (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp,
+ NDMPD_ZFS_DMP_NAME_MAX);
+
+ NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp);
+
+ return (0);
+}
+
+/*
+ * ndmpd_zfs_dmp_name_valid()
+ *
+ * This function verifies that the dmp_name is valid.
+ *
+ * The dmp_name is restricted to alphanumeric characters plus
+ * the underscore and hyphen, and must be 31 characters or less.
+ * This is due to its use in the NDMPD_ZFS_PROP_INCR property
+ * and in the ZFS snapshot name (if an ndmpd-generated snapshot
+ * is required).
+ */
+
+static boolean_t
+ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name)
+{
+ char *c;
+
+ if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "DMP_NAME %s is longer than %d\n",
+ dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1);
+ return (B_FALSE);
+ }
+
+ for (c = dmp_name; *c != '\0'; c++) {
+ if (!isalpha(*c) && !isdigit(*c) &&
+ (*c != '_') && (*c != '-')) {
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "DMP_NAME %s contains illegal character %c\n",
+ dmp_name, *c);
+ return (B_FALSE);
+ }
+ }
+
+ NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name);
+ return (B_TRUE);
+}
+
+/*
+ * ndmpd_zfs_is_incremental()
+ *
+ * This can only be called after ndmpd_zfs_getenv_level()
+ * has been called.
+ */
+
+static boolean_t
+ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ return (ndmpd_zfs_args->nz_level != 0);
+}
+
+/*
+ * ndmpd_zfs_snapshot_prepare()
+ *
+ * If no snapshot was supplied by the user, create a snapshot
+ * for use by ndmpd.
+ */
+
+static int
+ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ boolean_t recursive = B_FALSE;
+ int zfs_err = 0;
+
+ if (session->ns_data.dd_abort) {
+ NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
+ ndmpd_zfs_args->nz_dataset);
+ return (-1);
+ }
+
+ if (ndmpd_zfs_args->nz_snapname[0] == '\0') {
+ ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE;
+
+ if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) {
+ ndmpd_zfs_args->nz_snapname[0] = '\0';
+
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Error creating snapshot for %s\n",
+ ndmpd_zfs_args->nz_dataset);
+
+ return (-1);
+ }
+ }
+
+ if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) {
+ NDMP_LOG(LOG_DEBUG,
+ "ndmpd_zfs_snapshot_prop_add error\n");
+
+ if (ndmpd_zfs_args->nz_ndmpd_snap) {
+
+ if (ndmpd_zfs_args->nz_zfs_mode != 'd')
+ recursive = B_TRUE;
+
+ (void) snapshot_destroy(ndmpd_zfs_args->nz_dataset,
+ ndmpd_zfs_args->nz_snapname, recursive, &zfs_err);
+ }
+
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * ndmpd_zfs_snapshot_cleanup()
+ *
+ * If UPDATE = y, find the old snapshot (if any) corresponding to
+ * {LEVEL, DMPNAME, ZFS_MODE}. If it was ndmpd-generated,
+ * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR
+ * property to remove {L, D, Z}.
+ *
+ * If UPDATE = n, if an ndmpd-generated snapshot was used for backup,
+ * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR
+ * property to remove {L, D, Z}.
+ */
+
+static int
+ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err)
+{
+ ndmpd_session_t *session = (ndmpd_session_t *)
+ (ndmpd_zfs_params->mp_daemon_cookie);
+ ndmpd_zfs_snapfind_t snapdata;
+ boolean_t ndmpd_generated = B_FALSE;
+
+ bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t));
+
+ (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
+ snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE);
+
+ if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) {
+ /*
+ * Find the existing snapshot, if any, to "unuse."
+ * Indicate that the current snapshot used for backup
+ * should be skipped in the search. (The search is
+ * sorted by creation time but this cannot be relied
+ * upon for user-supplied snapshots.)
+ */
+
+ (void) snprintf(snapdata.nzs_snapskip, ZFS_MAXNAMELEN, "%s",
+ ndmpd_zfs_args->nz_snapname);
+
+ if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) {
+ NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n");
+ goto _remove_tmp_snap;
+ }
+
+ if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */
+ ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated
+ (snapdata.nzs_snapprop);
+
+ if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
+ ndmpd_generated, &snapdata) != 0) {
+ NDMP_LOG(LOG_DEBUG,
+ "ndmpd_zfs_snapshot_unuse error\n");
+ goto _remove_tmp_snap;
+ }
+ }
+
+ if (session->ns_data.dd_abort)
+ goto _remove_tmp_snap;
+
+ return (0);
+ }
+
+_remove_tmp_snap:
+
+ (void) snprintf(snapdata.nzs_snapname, ZFS_MAXNAMELEN, "%s",
+ ndmpd_zfs_args->nz_snapname);
+
+ (void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop,
+ ZFS_MAXPROPLEN);
+
+ snapdata.nzs_snapskip[0] = '\0';
+
+ if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
+ ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) {
+ NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n");
+ return (-1);
+ }
+
+ if (!ndmpd_zfs_args->nz_update)
+ return (0);
+
+ return (-1);
+}
+
+static int
+ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ boolean_t recursive = B_FALSE;
+
+ if (ndmpd_zfs_snapname_create(ndmpd_zfs_args,
+ ndmpd_zfs_args->nz_snapname, ZFS_MAXNAMELEN -1) < 0) {
+ NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s",
+ errno, ndmpd_zfs_args->nz_dataset);
+ return (-1);
+ }
+
+ if (ndmpd_zfs_args->nz_zfs_mode != 'd')
+ recursive = B_TRUE;
+
+ if (snapshot_create(ndmpd_zfs_args->nz_dataset,
+ ndmpd_zfs_args->nz_snapname, recursive) != 0) {
+ NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s",
+ ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
+ return (-1);
+ }
+
+ NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s",
+ ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
+
+ return (0);
+}
+
+/*
+ * ndmpd_zfs_snapshot_unuse()
+ *
+ * Given a pre-existing snapshot of the given {L, D, Z}:
+ * If snapshot is ndmpd-generated, remove snapshot.
+ * If not ndmpd-generated, or if the ndmpd-generated snapshot
+ * cannot be destroyed, remove the {L, D, Z} substring from the
+ * snapshot's NDMPD_ZFS_PROP_INCR property.
+ *
+ * In the event of a failure, it may be that two snapshots will
+ * have the {L, D, Z} property set on them. This is not desirable,
+ * so return an error and log the failure.
+ */
+
+static int
+ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args,
+ boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p)
+{
+ boolean_t recursive = B_FALSE;
+ int zfs_err = 0;
+ int err = 0;
+
+ if (ndmpd_generated) {
+ if (ndmpd_zfs_args->nz_zfs_mode != 'd')
+ recursive = B_TRUE;
+
+ err = snapshot_destroy(ndmpd_zfs_args->nz_dataset,
+ snapdata_p->nzs_snapname, recursive, &zfs_err);
+
+ if (err) {
+ NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;"
+ " err: %d; zfs_err: %d",
+ ndmpd_zfs_args->nz_dataset,
+ snapdata_p->nzs_snapname, err, zfs_err);
+ return (-1);
+ }
+ }
+
+ if (!ndmpd_generated || zfs_err) {
+ if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p))
+ return (-1);
+ }
+
+ return (0);
+}
+
+static boolean_t
+ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop)
+{
+ char origin;
+
+ (void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin);
+
+ return (origin == 'n');
+}
+
+/*
+ * ndmpd_zfs_snapshot_find()
+ *
+ * Find a snapshot with a particular value for
+ * the NDMPD_ZFS_PROP_INCR property.
+ */
+
+static int
+ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args,
+ ndmpd_zfs_snapfind_t *snapdata)
+{
+ zfs_handle_t *zhp;
+ int err;
+
+ zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
+ ndmpd_zfs_args->nz_type);
+
+ if (!zhp) {
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
+ return (-1);
+ }
+
+ err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find,
+ snapdata);
+
+ zfs_close(zhp);
+
+ if (err) {
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d",
+ err);
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Error iterating snapshots\n");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * ndmpd_zfs_snapshot_prop_find()
+ *
+ * Find a snapshot with a particular value for
+ * NDMPD_ZFS_PROP_INCR. Fill in data for the first one
+ * found (sorted by creation time). However, skip the
+ * the snapshot indicated in nzs_snapskip, if any.
+ */
+
+static int
+ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg)
+{
+ ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg;
+ char propstr[ZFS_MAXPROPLEN];
+ char findprop_plus_slash[ZFS_MAXPROPLEN];
+ char *justsnap;
+ int err = 0;
+
+ if (snapdata_p->nzs_snapname[0] != '\0') {
+ NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s",
+ (char *)zfs_get_name(zhp));
+ goto _done;
+ }
+
+ err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
+
+ if (err) {
+ NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed");
+ goto _done;
+ }
+
+ if (propstr[0] == '\0') {
+ NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set",
+ (char *)zfs_get_name(zhp));
+ goto _done;
+ }
+
+ (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
+ snapdata_p->nzs_findprop);
+
+ if (!strstr((const char *)propstr,
+ (const char *)findprop_plus_slash)) {
+ NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)",
+ (char *)zfs_get_name(zhp), propstr,
+ snapdata_p->nzs_findprop);
+ goto _done;
+ }
+
+ if (!ndmpd_zfs_prop_version_check(propstr,
+ &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) {
+ NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)",
+ (char *)zfs_get_name(zhp), propstr,
+ snapdata_p->nzs_findprop);
+ NDMP_LOG(LOG_DEBUG, "did not pass version check");
+ goto _done;
+ }
+
+ justsnap = strchr(zfs_get_name(zhp), '@') + 1;
+
+ if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) {
+ (void) strlcpy(snapdata_p->nzs_snapname, justsnap,
+ ZFS_MAXNAMELEN);
+
+ (void) strlcpy(snapdata_p->nzs_snapprop, propstr,
+ ZFS_MAXPROPLEN);
+
+ NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n",
+ snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop);
+ }
+
+_done:
+ zfs_close(zhp);
+ return (err);
+}
+
+/*
+ * ndmpd_zfs_snapshot_prop_get()
+ *
+ * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot
+ */
+
+static int
+ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr)
+{
+ nvlist_t *userprop;
+ nvlist_t *propval;
+ char *strval;
+ int err;
+
+ propstr[0] = '\0';
+
+ userprop = zfs_get_user_props(zhp);
+
+ if (userprop == NULL)
+ return (0);
+
+ err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval);
+
+ if (err != 0) {
+ if (err == ENOENT)
+ return (0);
+
+ NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err);
+
+ return (-1);
+ }
+
+ err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
+
+ if (err != 0) {
+ if (err == ENOENT)
+ return (0);
+
+ NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err);
+
+ return (-1);
+ }
+
+ (void) strlcpy(propstr, strval, ZFS_MAXPROPLEN);
+
+ return (0);
+}
+
+/*
+ * ndmpd_zfs_snapshot_prop_add()
+ *
+ * Update snapshot's NDMPD_ZFS_PROP_INCR property with
+ * the current LEVEL, DMPNAME, and ZFSMODE values
+ * (add property if it doesn't exist)
+ */
+
+static int
+ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ char fullname[ZFS_MAXNAMELEN];
+ char propstr[ZFS_MAXPROPLEN];
+ zfs_handle_t *zhp;
+ boolean_t set;
+ int err;
+
+ (void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s",
+ ndmpd_zfs_args->nz_dataset,
+ ndmpd_zfs_args->nz_snapname);
+
+ zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
+
+ if (!zhp) {
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)");
+ return (-1);
+ }
+
+ bzero(propstr, ZFS_MAXPROPLEN);
+
+ if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) {
+ NDMP_LOG(LOG_DEBUG, "error getting property");
+ zfs_close(zhp);
+ return (-1);
+ }
+
+ if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) {
+ zfs_close(zhp);
+ return (-1);
+ }
+
+ if (set) {
+ err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr);
+ if (err) {
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
+ err);
+ NDMP_LOG(LOG_ERR, "error setting property %s",
+ propstr);
+ zfs_close(zhp);
+ return (-1);
+ }
+ }
+
+ zfs_close(zhp);
+
+ (void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN);
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
+ char *propstr, boolean_t *set)
+{
+ char subprop[ZFS_MAXPROPLEN];
+
+ *set = B_TRUE;
+
+ (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
+ subprop, ZFS_MAXPROPLEN, B_FALSE);
+
+ if (propstr[0] == '\0') {
+ (void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s",
+ NDMPD_ZFS_PROP_MAJOR_VERSION,
+ NDMPD_ZFS_PROP_MINOR_VERSION,
+ (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u',
+ subprop);
+ return (0);
+ }
+
+ if (strstr((const char *)propstr, (const char *)subprop)) {
+ NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists",
+ subprop);
+ *set = B_FALSE;
+ return (0);
+ }
+
+ if ((strlen(propstr) + strlen(subprop) + 2) >= ZFS_MAXPROPLEN) {
+ NDMP_LOG(LOG_ERR, "snapshot %s: user property "
+ "%s would overflow; cannot complete operation",
+ ndmpd_zfs_args->nz_snapname,
+ NDMPD_ZFS_PROP_INCR);
+ return (-1);
+ }
+
+ (void) strlcat(propstr, "/", ZFS_MAXPROPLEN);
+ (void) strlcat(propstr, subprop, ZFS_MAXPROPLEN);
+
+ return (0);
+}
+
+static int
+ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args,
+ char *subprop, int len, boolean_t prev_level)
+{
+ return (snprintf(subprop, len, "%d.%s.%c",
+ prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level,
+ ndmpd_zfs_args->nz_dmp_name,
+ ndmpd_zfs_args->nz_zfs_mode));
+}
+
+/*
+ * ndmpd_zfs_snapshot_prop_remove()
+ *
+ * Remove specified substring from the snapshot's
+ * NDMPD_ZFS_PROP_INCR property
+ */
+
+static int
+ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args,
+ ndmpd_zfs_snapfind_t *snapdata_p)
+{
+ char findprop_plus_slash[ZFS_MAXPROPLEN];
+ char fullname[ZFS_MAXNAMELEN];
+ char newprop[ZFS_MAXPROPLEN];
+ char tmpstr[ZFS_MAXPROPLEN];
+ zfs_handle_t *zhp;
+ char *ptr;
+ int err;
+
+ (void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s",
+ ndmpd_zfs_args->nz_dataset,
+ snapdata_p->nzs_snapname);
+
+ zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
+
+ if (!zhp) {
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
+ return (-1);
+ }
+
+ bzero(newprop, ZFS_MAXPROPLEN);
+
+ /*
+ * If the substring to be removed is the only {L, D, Z}
+ * in the property, remove the entire property
+ */
+
+ tmpstr[0] = '\0';
+
+ (void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr);
+
+ if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) {
+
+ err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
+
+ zfs_close(zhp);
+
+ if (err) {
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
+ err);
+ NDMP_LOG(LOG_ERR, "error setting property %s", newprop);
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
+ snapdata_p->nzs_findprop);
+
+ ptr = strstr((const char *)snapdata_p->nzs_snapprop,
+ (const char *)findprop_plus_slash);
+
+ if (ptr == NULL) {
+ /*
+ * This shouldn't happen. Just return success.
+ */
+ zfs_close(zhp);
+
+ return (0);
+ }
+
+ /*
+ * Remove "nzs_findprop" substring from property
+ *
+ * Example property:
+ * 0.0.u/1.bob.p/0.jane.d
+ *
+ * Note that there will always be a prefix to the
+ * strstr() result. Hence the below code works for
+ * all cases.
+ */
+
+ ptr--;
+ (void) strncpy(newprop, snapdata_p->nzs_snapprop,
+ (char *)ptr - snapdata_p->nzs_snapprop);
+ ptr += strlen(snapdata_p->nzs_findprop) + 1;
+ (void) strlcat(newprop, ptr, ZFS_MAXPROPLEN);
+
+ err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
+
+ zfs_close(zhp);
+
+ if (err) {
+ NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err);
+ NDMP_LOG(LOG_ERR, "error modifying property %s", newprop);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static boolean_t
+ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor)
+{
+ (void) sscanf(propstr, "%u.%u.%*c%*s", major, minor);
+
+ if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) {
+ NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)",
+ *major, NDMPD_ZFS_PROP_MAJOR_VERSION);
+ return (B_FALSE);
+ }
+
+ if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) {
+ NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)",
+ *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
+ }
+
+ NDMP_LOG(LOG_DEBUG, "passed version check: "
+ "supported prop major (%u <= %u); (snapprop minor: %u [%u])",
+ *major, NDMPD_ZFS_PROP_MAJOR_VERSION,
+ *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
+
+ return (B_TRUE);
+}
+
+static int
+ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
+ char *snapname, int namelen)
+{
+ char subprop[ZFS_MAXPROPLEN];
+ struct timeval tp;
+ int err = 0;
+
+ (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
+ subprop, ZFS_MAXPROPLEN, B_FALSE);
+
+ (void) gettimeofday(&tp, NULL);
+
+ err = snprintf(snapname, namelen,
+ "ndmp.%s.%ld.%ld",
+ subprop,
+ tp.tv_sec,
+ tp.tv_usec);
+
+ if (err > namelen) {
+ NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d",
+ snapname, namelen);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args)
+{
+ switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) {
+ case EZFS_EXISTS:
+ case EZFS_BUSY:
+ case EZFS_NOENT:
+ case EZFS_INVALIDNAME:
+ case EZFS_MOUNTFAILED:
+ case EZFS_UMOUNTFAILED:
+ case EZFS_NAMETOOLONG:
+ case EZFS_BADRESTORE:
+
+ /* use existing error text */
+
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "%s: %s: %s\n",
+ ndmpd_zfs_args->nz_dataset,
+ libzfs_error_action(ndmpd_zfs_args->nz_zlibh),
+ libzfs_error_description(ndmpd_zfs_args->nz_zlibh));
+
+ break;
+
+ case EZFS_NOMEM:
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "Unable to obtain memory for operation\n");
+ break;
+
+ case EZFS_PROPSPACE:
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "A bad ZFS quota or reservation was encountered.\n");
+ break;
+
+ case EZFS_BADSTREAM:
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "The backup stream is invalid.\n");
+ break;
+
+ case EZFS_ZONED:
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "An error related to the local zone occurred.\n");
+ break;
+
+ case EZFS_NOSPC:
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "No more space is available\n");
+ break;
+
+ case EZFS_IO:
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "An I/O error occurred.\n");
+ break;
+
+ default:
+ ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
+ "An internal ndmpd error occurred. "
+ "Please contact support\n");
+ break;
+ }
+}
+
+void
+ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type,
+ char *format, ...)
+{
+ static char buf[1024];
+ va_list ap;
+
+ va_start(ap, format);
+
+ /*LINTED variable format specifier */
+ (void) vsnprintf(buf, sizeof (buf), format, ap);
+ va_end(ap);
+
+ MOD_LOGV3(ndmpd_zfs_params, log_type, buf);
+
+ if ((log_type) == NDMP_LOG_ERROR) {
+ NDMP_LOG(LOG_ERR, buf);
+ } else {
+ NDMP_LOG(LOG_INFO, buf);
+ }
+}
diff --git a/usr/src/cmd/ndmpd/tlm/tlm_lib.c b/usr/src/cmd/ndmpd/tlm/tlm_lib.c
index 2734ebc187..b4704dfa61 100644
--- a/usr/src/cmd/ndmpd/tlm/tlm_lib.c
+++ b/usr/src/cmd/ndmpd/tlm/tlm_lib.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -663,7 +662,7 @@ tlm_get_chkpnt_time(char *path, int auto_checkpoint, time_t *tp, char *jname)
if (auto_checkpoint) {
NDMP_LOG(LOG_DEBUG, "volname [%s]", volname);
- (void) snprintf(chk_name, PATH_MAX, "bk-%s", jname);
+ (void) snprintf(chk_name, PATH_MAX, "%s", jname);
return (chkpnt_creationtime_bypattern(volname, chk_name, tp));
}
cp_nm = strchr(volname, '@');
@@ -710,13 +709,13 @@ tlm_log_list(char *title, char **lpp)
* Insert the backup snapshot name into the path.
*
* Input:
- * name: Origional path name.
+ * name: Original path name.
*
* Output:
- * name: Origional name modified to include a snapshot.
+ * name: Original name modified to include a snapshot.
*
* Returns:
- * Origional name modified to include a snapshot.
+ * Original name modified to include a snapshot.
*/
char *
tlm_build_snapshot_name(char *name, char *sname, char *jname)
@@ -747,7 +746,7 @@ tlm_build_snapshot_name(char *name, char *sname, char *jname)
(void) mutex_unlock(&zlib_mtx);
rest = name + strlen(mountpoint);
- (void) snprintf(sname, TLM_MAX_PATH_NAME, "%s/%s/bk-%s%s", mountpoint,
+ (void) snprintf(sname, TLM_MAX_PATH_NAME, "%s/%s/%s%s", mountpoint,
TLM_SNAPSHOT_DIR, jname, rest);
return (sname);
@@ -1174,7 +1173,7 @@ tlm_ioctl(int fd, int cmd, void *data)
* Create a snapshot on the volume
*/
int
-chkpnt_backup_prepare(char *volname, char *jname)
+chkpnt_backup_prepare(char *volname, char *jname, boolean_t recursive)
{
char chk_name[PATH_MAX];
char *p;
@@ -1190,17 +1189,18 @@ chkpnt_backup_prepare(char *volname, char *jname)
while (*p == '/')
p++;
- (void) snprintf(chk_name, PATH_MAX, "%s@bk-%s", p, jname);
+ (void) snprintf(chk_name, PATH_MAX, "%s@%s", p, jname);
(void) mutex_lock(&zlib_mtx);
- if ((rv = zfs_snapshot(zlibh, chk_name, 0, NULL)) == -1) {
+ if ((rv = zfs_snapshot(zlibh, chk_name, recursive, NULL))
+ == -1) {
if (errno == EEXIST) {
(void) mutex_unlock(&zlib_mtx);
return (0);
}
NDMP_LOG(LOG_DEBUG,
- "chkpnt_backup_prepare: %s failed (err=%d)",
- chk_name, errno);
+ "chkpnt_backup_prepare: %s failed (err=%d): %s",
+ chk_name, errno, libzfs_error_description(zlibh));
(void) mutex_unlock(&zlib_mtx);
return (rv);
}
@@ -1212,12 +1212,18 @@ chkpnt_backup_prepare(char *volname, char *jname)
* Remove the 'backup' snapshot if backup was successful
*/
int
-chkpnt_backup_successful(char *volname, char *jname)
+chkpnt_backup_successful(char *volname, char *jname, boolean_t recursive,
+ int *zfs_err)
{
char chk_name[PATH_MAX];
zfs_handle_t *zhp;
+ zfs_type_t ztype;
+ int err;
char *p;
+ if (zfs_err)
+ *zfs_err = 0;
+
if (!volname || !*volname)
return (-1);
@@ -1228,16 +1234,40 @@ chkpnt_backup_successful(char *volname, char *jname)
while (*p == '/')
p++;
- (void) snprintf(chk_name, PATH_MAX, "%s@bk-%s", p, jname);
+ if (recursive) {
+ ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
+ } else {
+ (void) snprintf(chk_name, PATH_MAX, "%s@%s", p, jname);
+ p = chk_name;
+ ztype = ZFS_TYPE_SNAPSHOT;
+ }
(void) mutex_lock(&zlib_mtx);
- if ((zhp = zfs_open(zlibh, chk_name, ZFS_TYPE_SNAPSHOT)) == NULL) {
+ if ((zhp = zfs_open(zlibh, p, ztype)) == NULL) {
NDMP_LOG(LOG_DEBUG, "chkpnt_backup_successful: open %s failed",
- chk_name);
+ p);
(void) mutex_unlock(&zlib_mtx);
return (-1);
}
- (void) zfs_destroy(zhp, B_FALSE);
+
+ if (recursive) {
+ err = zfs_destroy_snaps(zhp, jname, B_FALSE);
+ } else {
+ err = zfs_destroy(zhp, B_FALSE);
+ }
+
+ if (err) {
+ NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s",
+ p,
+ recursive,
+ libzfs_errno(zlibh),
+ libzfs_error_action(zlibh),
+ libzfs_error_description(zlibh));
+
+ if (zfs_err)
+ *zfs_err = err;
+ }
+
zfs_close(zhp);
(void) mutex_unlock(&zlib_mtx);
diff --git a/usr/src/lib/libndmp/common/libndmp.h b/usr/src/lib/libndmp/common/libndmp.h
index 0d535bb46c..2a85462809 100644
--- a/usr/src/lib/libndmp/common/libndmp.h
+++ b/usr/src/lib/libndmp/common/libndmp.h
@@ -1,6 +1,5 @@
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -36,6 +35,8 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
+/* Copyright (c) 2007, The Storage Networking Industry Association. */
+/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
#ifndef _LIBNDMP_H
#define _LIBNDMP_H
@@ -64,9 +65,10 @@ extern int ndmp_errno;
typedef struct ndmp_context {
char *nc_plname;
uint_t nc_plversion;
- void *nc_pldata;
+ void *nc_pldata; /* data private to the plugin */
void *nc_cmds;
void *nc_params;
+ void *nc_ddata; /* data private to the daemon */
} ndmp_context_t;
typedef struct ndmp_plugin {
@@ -92,6 +94,14 @@ typedef enum ndmp_log_dma_type {
NDMP_LOGD_WARNING = 3
} ndmp_log_dma_type_t;
+typedef enum {
+ NDMP_BUTYPE_TAR = 0,
+ NDMP_BUTYPE_DUMP,
+ NDMP_BUTYPE_ZFS
+} ndmpd_backup_type_t;
+
+extern ndmpd_backup_type_t ndmp_get_backup_type(ndmp_context_t *);
+
/* libndmp error codes */
#define ENDMP_BASE 2000
enum {