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