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