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