1 /*
   2  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
   4  */
   5 
   6 /*
   7  * BSD 3 Clause License
   8  *
   9  * Copyright (c) 2007, The Storage Networking Industry Association.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *      - Redistributions of source code must retain the above copyright
  15  *        notice, this list of conditions and the following disclaimer.
  16  *
  17  *      - Redistributions in binary form must reproduce the above copyright
  18  *        notice, this list of conditions and the following disclaimer in
  19  *        the documentation and/or other materials provided with the
  20  *        distribution.
  21  *
  22  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  23  *        nor the names of its contributors may be used to endorse or promote
  24  *        products derived from this software without specific prior written
  25  *        permission.
  26  *
  27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37  * POSSIBILITY OF SUCH DAMAGE.
  38  */
  39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  41 
  42 #include <sys/types.h>
  43 #include <sys/param.h>
  44 #include <sys/lwp.h>
  45 #include <sys/fs/zfs.h>
  46 #include <sys/mtio.h>
  47 #include <sys/time.h>
  48 #include <unistd.h>
  49 #include <errno.h>
  50 #include <stdlib.h>
  51 #include <string.h>
  52 #include <ctype.h>
  53 #include <libzfs.h>
  54 #include <stdio.h>
  55 #include "ndmpd_common.h"
  56 #include "ndmpd.h"
  57 
  58 typedef struct {
  59         char nzs_findprop[ZFS_MAXPROPLEN]; /* prop substring to find */
  60         char nzs_snapname[ZFS_MAX_DATASET_NAME_LEN]; /* snap's name */
  61         char nzs_snapprop[ZFS_MAXPROPLEN]; /* snap's prop value */
  62         char nzs_snapskip[ZFS_MAXPROPLEN]; /* snap to skip */
  63         uint32_t nzs_prop_major;           /* property major version */
  64         uint32_t nzs_prop_minor;           /* property minor version */
  65 } ndmpd_zfs_snapfind_t;
  66 
  67 mutex_t ndmpd_zfs_fd_lock;
  68 
  69 static int ndmpd_zfs_open_fds(ndmpd_zfs_args_t *);
  70 static void ndmpd_zfs_close_fds(ndmpd_zfs_args_t *);
  71 
  72 static void ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *, int);
  73 
  74 static int ndmpd_zfs_header_write(ndmpd_session_t *);
  75 static int ndmpd_zfs_header_read(ndmpd_zfs_args_t *);
  76 
  77 static int ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *);
  78 static int ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *);
  79 
  80 static int ndmpd_zfs_restore(ndmpd_zfs_args_t *);
  81 static int ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *);
  82 static int ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *);
  83 
  84 static int ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *, int **, int **);
  85 
  86 static int ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *, u_longlong_t);
  87 
  88 static boolean_t ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *);
  89 static int ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *, char *, int);
  90 static int ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *);
  91 
  92 static boolean_t ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *);
  93 static int ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *);
  94 static int ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *);
  95 
  96 static int ndmpd_zfs_getenv(ndmpd_zfs_args_t *);
  97 static int ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *);
  98 static int ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *);
  99 static int ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *);
 100 static int ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *);
 101 static int ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *);
 102 static int ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *);
 103 
 104 static boolean_t ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *, char *);
 105 static boolean_t ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *);
 106 static int ndmpd_zfs_send_fhist(ndmpd_zfs_args_t *);
 107 
 108 static int ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *);
 109 static int ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *, int);
 110 static int ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *);
 111 static int ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *,
 112     boolean_t, ndmpd_zfs_snapfind_t *);
 113 static boolean_t ndmpd_zfs_snapshot_ndmpd_generated(char *);
 114 static int ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *, ndmpd_zfs_snapfind_t *);
 115 
 116 static int ndmpd_zfs_snapshot_prop_find(zfs_handle_t *, void *);
 117 static int ndmpd_zfs_snapshot_prop_get(zfs_handle_t *, char *);
 118 static int ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *);
 119 static int ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *, char *,
 120     boolean_t *);
 121 static int ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *, char *, int,
 122     boolean_t);
 123 static int ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *,
 124     ndmpd_zfs_snapfind_t *);
 125 static boolean_t ndmpd_zfs_prop_version_check(char *, uint32_t *, uint32_t *);
 126 
 127 static int ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *, char *, int);
 128 
 129 static void ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *);
 130 
 131 static int ndmpd_zfs_backup(ndmpd_zfs_args_t *);
 132 
 133 /*
 134  * Syntax for com.sun.ndmp:incr property value:
 135  *      #.#.n|u/$LEVEL.$DMP_NAME.$ZFS_MODE(/ ...)
 136  *
 137  * where
 138  *      #.# is the version number
 139  *      'n' means ndmp-generated; 'u' means user-supplied
 140  *      $LEVEL: backup (incremental) level [0-9]
 141  *      $DMP_NAME: set name [default: "level"]
 142  *      $ZFS_MODE: d | r | p [for dataset, recursive, or package]
 143  *
 144  * Examples:
 145  *
 146  *      0.0.n/0.bob.p
 147  *      0.0.u/1.bob.p/0.jane.d
 148  *
 149  * Note: NDMPD_ZFS_SUBPROP_MAX is calculated based on ZFS_MAXPROPLEN
 150  */
 151 
 152 #define NDMPD_ZFS_PROP_INCR "com.sun.ndmp:incr"
 153 #define NDMPD_ZFS_SUBPROP_MAX   28
 154 
 155 /*
 156  * NDMPD_ZFS_LOG_ZERR
 157  *
 158  * As coded, there should be no races in the retrieval of the ZFS errno
 159  * from the ndmpd_zfs_args->nz_zlibh.  I.e., for a given ndmpd_zfs backup
 160  * or restore, there should only ever be one ZFS library call taking place
 161  * at any one moment in time.
 162  */
 163 
 164 #define NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, ...) {                       \
 165         NDMP_LOG(LOG_ERR, __VA_ARGS__);                                 \
 166         NDMP_LOG(LOG_ERR, "%s--%s",                                     \
 167             libzfs_error_action((ndmpd_zfs_args)->nz_zlibh),                 \
 168             libzfs_error_description((ndmpd_zfs_args)->nz_zlibh));           \
 169         ndmpd_zfs_zerr_dma_log((ndmpd_zfs_args));                       \
 170 }
 171 
 172 int
 173 ndmpd_zfs_init(ndmpd_session_t *session)
 174 {
 175         ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
 176         int version = session->ns_protocol_version;
 177 
 178         bzero(ndmpd_zfs_args, sizeof (*ndmpd_zfs_args));
 179 
 180         if ((version < NDMPV3) || (version > NDMPV4)) {
 181                 NDMP_LOG(LOG_ERR, "Unknown or unsupported version %d", version);
 182                 return (-1);
 183         }
 184 
 185         if ((ndmpd_zfs_args->nz_zlibh = libzfs_init()) == NULL) {
 186                 NDMP_LOG(LOG_ERR, "libzfs init error [%d]", errno);
 187                 return (-1);
 188         }
 189 
 190         if (ndmpd_zfs_open_fds(ndmpd_zfs_args) < 0) {
 191                 NDMP_LOG(LOG_ERR, "open_fds() failure(): %d\n", errno);
 192                 return (-1);
 193         }
 194 
 195         ndmpd_zfs_args->nz_bufsize = ndmp_buffer_get_size(session);
 196         ndmpd_zfs_args->nz_window_len = session->ns_mover.md_window_length;
 197 
 198         ndmpd_zfs_args->nz_nlp = ndmp_get_nlp(session);
 199 
 200         assert(ndmpd_zfs_args->nz_nlp != NULL);
 201 
 202         ndmpd_zfs_args->nz_nlp->nlp_bytes_total = 0;
 203 
 204         session->ns_data.dd_module.dm_module_cookie = ndmpd_zfs_args;
 205         session->ns_data.dd_data_size = 0;
 206         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
 207         session->ns_data.dd_module.dm_stats.ms_est_time_remaining  = 0;
 208 
 209         session->ns_data.dd_bytes_left_to_read = 0;
 210         session->ns_data.dd_position = 0;
 211         session->ns_data.dd_discard_length = 0;
 212         session->ns_data.dd_read_offset = 0;
 213         session->ns_data.dd_read_length = 0;
 214 
 215         ndmpd_zfs_params->mp_get_env_func = ndmpd_api_get_env;
 216         ndmpd_zfs_params->mp_add_env_func = ndmpd_api_add_env;
 217         ndmpd_zfs_params->mp_set_env_func = ndmpd_api_set_env;
 218         ndmpd_zfs_params->mp_dispatch_func = ndmpd_api_dispatch;
 219         ndmpd_zfs_params->mp_daemon_cookie = (void *)session;
 220         ndmpd_zfs_params->mp_protocol_version = session->ns_protocol_version;
 221         ndmpd_zfs_params->mp_stats = &session->ns_data.dd_module.dm_stats;
 222         ndmpd_zfs_params->mp_add_file_handler_func =
 223             ndmpd_api_add_file_handler;
 224         ndmpd_zfs_params->mp_remove_file_handler_func =
 225             ndmpd_api_remove_file_handler;
 226         ndmpd_zfs_params->mp_seek_func = 0;
 227 
 228         switch (version) {
 229         case NDMPV3:
 230                 ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
 231                 ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
 232                 ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
 233                 ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
 234                 ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v3;
 235                 ndmpd_zfs_params->mp_file_recovered_func =
 236                     ndmpd_api_file_recovered_v3;
 237                 break;
 238         case NDMPV4:
 239                 ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3;
 240                 ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3;
 241                 ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3;
 242                 ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3;
 243                 ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v4;
 244                 ndmpd_zfs_params->mp_file_recovered_func =
 245                     ndmpd_api_file_recovered_v4;
 246                 break;
 247         default:
 248                 /* error already returned above for this case */
 249                 break;
 250         }
 251 
 252         return (0);
 253 }
 254 
 255 void
 256 ndmpd_zfs_fini(ndmpd_zfs_args_t *ndmpd_zfs_args)
 257 {
 258         libzfs_fini(ndmpd_zfs_args->nz_zlibh);
 259 
 260         ndmpd_zfs_close_fds(ndmpd_zfs_args);
 261 }
 262 
 263 static int
 264 ndmpd_zfs_open_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
 265 {
 266         int err;
 267 
 268         err = pipe(ndmpd_zfs_args->nz_pipe_fd);
 269         if (err)
 270                 NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n", strerror(errno));
 271 
 272         return (err);
 273 }
 274 
 275 /*
 276  * ndmpd_zfs_close_fds()
 277  *
 278  * In the abort case, use dup2() to redirect the end of the pipe that is
 279  * being written to (to a new pipe).  Close the ends of the new pipe to cause
 280  * EPIPE to be returned to the writing thread.  This will cause the writer
 281  * and reader to terminate without having any of the writer's data erroneously
 282  * go to any reopened descriptor.
 283  */
 284 
 285 static void
 286 ndmpd_zfs_close_fds(ndmpd_zfs_args_t *ndmpd_zfs_args)
 287 {
 288         ndmpd_session_t *session = (ndmpd_session_t *)
 289             (ndmpd_zfs_params->mp_daemon_cookie);
 290         int pipe_end;
 291         int fds[2];
 292 
 293         if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE) {
 294                 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
 295                 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
 296                 return;
 297         }
 298 
 299         (void) mutex_lock(&ndmpd_zfs_fd_lock);
 300 
 301         if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) {
 302                 pipe_end = PIPE_ZFS;
 303         } else {
 304                 pipe_end = PIPE_TAPE;
 305         }
 306 
 307         if (ndmpd_zfs_args->nz_pipe_fd[pipe_end] != -1) {
 308                 if (pipe(fds) != 0) {
 309                         (void) mutex_unlock(&ndmpd_zfs_fd_lock);
 310                         NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n",
 311                             strerror(errno));
 312                         return;
 313                 }
 314 
 315                 (void) dup2(fds[0], ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
 316                 (void) close(fds[0]);
 317                 (void) close(fds[1]);
 318 
 319                 ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
 320         }
 321 
 322         (void) mutex_unlock(&ndmpd_zfs_fd_lock);
 323 }
 324 
 325 static void
 326 ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *ndmpd_zfs_args, int pipe_end)
 327 {
 328         (void) mutex_lock(&ndmpd_zfs_fd_lock);
 329         (void) close(ndmpd_zfs_args->nz_pipe_fd[pipe_end]);
 330         ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1;
 331         (void) mutex_unlock(&ndmpd_zfs_fd_lock);
 332 }
 333 
 334 static int
 335 ndmpd_zfs_header_write(ndmpd_session_t *session)
 336 {
 337         ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
 338         int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
 339         ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
 340         char *buf;
 341 
 342         buf = ndmp_malloc(bufsize);
 343         if (buf == NULL) {
 344                 NDMP_LOG(LOG_DEBUG, "buf NULL");
 345                 return (-1);
 346         }
 347 
 348         (void) strlcpy(tape_header->nzh_magic, NDMPUTF8MAGIC,
 349             sizeof (NDMPUTF8MAGIC));
 350         tape_header->nzh_major = LE_32(NDMPD_ZFS_MAJOR_VERSION);
 351         tape_header->nzh_minor = LE_32(NDMPD_ZFS_MINOR_VERSION);
 352         tape_header->nzh_hdrlen = LE_32(bufsize);
 353 
 354         bzero(buf, bufsize);
 355         (void) memcpy(buf, tape_header, sizeof (ndmpd_zfs_header_t));
 356 
 357         NDMP_LOG(LOG_DEBUG, "header (major, minor, length): %u %u %u",
 358             NDMPD_ZFS_MAJOR_VERSION,
 359             NDMPD_ZFS_MINOR_VERSION,
 360             bufsize);
 361 
 362         if (MOD_WRITE(ndmpd_zfs_params, buf, bufsize) != 0) {
 363                 free(buf);
 364                 NDMP_LOG(LOG_ERR, "MOD_WRITE error");
 365                 return (-1);
 366         }
 367 
 368         free(buf);
 369 
 370         session->ns_data.dd_module.dm_stats.ms_bytes_processed = bufsize;
 371 
 372         return (0);
 373 }
 374 
 375 static int
 376 ndmpd_zfs_header_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
 377 {
 378         int32_t bufsize = ndmpd_zfs_args->nz_bufsize;
 379         ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header;
 380         uint32_t hdrlen;
 381         int32_t header_left;
 382         int err;
 383         char *buf;
 384 
 385         buf = ndmp_malloc(bufsize);
 386         if (buf == NULL) {
 387                 NDMP_LOG(LOG_DEBUG, "buf NULL");
 388                 return (-1);
 389         }
 390 
 391         bzero(buf, bufsize);
 392 
 393         /*
 394          * Read nz_bufsize worth of bytes first (the size of a mover record).
 395          */
 396 
 397         err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
 398 
 399         if (err != 0) {
 400                 NDMP_LOG(LOG_ERR, "MOD_READ error: %d", err);
 401                 free(buf);
 402                 return (-1);
 403         }
 404 
 405         (void) memcpy(tape_header, buf, sizeof (ndmpd_zfs_header_t));
 406 
 407         if (strcmp(tape_header->nzh_magic, NDMPUTF8MAGIC) != 0) {
 408                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
 409                     "bad magic string\n");
 410                 goto _err;
 411         }
 412 
 413         if (tape_header->nzh_major > LE_32(NDMPD_ZFS_MAJOR_VERSION)) {
 414                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
 415                     "major number larger than supported: (%d %d)\n",
 416                     LE_32(tape_header->nzh_major), NDMPD_ZFS_MAJOR_VERSION);
 417                 goto _err;
 418         }
 419 
 420         /*
 421          * Major version 0 (regardless of minor version):
 422          * Header must be a multiple of the mover record size.
 423          */
 424 
 425         hdrlen = LE_32(tape_header->nzh_hdrlen);
 426         if (hdrlen > bufsize) {
 427                 header_left = hdrlen - bufsize;
 428                 while (header_left > 0) {
 429                         err = MOD_READ(ndmpd_zfs_params, buf, bufsize);
 430                         if (err == -1) {
 431                                 ndmpd_zfs_dma_log(ndmpd_zfs_args,
 432                                     NDMP_LOG_ERROR, "bad header\n");
 433                                 goto _err;
 434                         }
 435                         header_left -= bufsize;
 436                 }
 437         }
 438 
 439         NDMP_LOG(LOG_DEBUG, "tape header: %s; %u %u; %u ",
 440             tape_header->nzh_magic,
 441             LE_32(tape_header->nzh_major),
 442             LE_32(tape_header->nzh_minor),
 443             LE_32(tape_header->nzh_hdrlen));
 444 
 445         ndmpd_zfs_args->nz_nlp->nlp_bytes_total = hdrlen;
 446 
 447         free(buf);
 448         return (0);
 449 
 450 _err:
 451 
 452         NDMP_LOG(LOG_ERR, "tape header: %s; %u %u; %u ",
 453             tape_header->nzh_magic,
 454             LE_32(tape_header->nzh_major),
 455             LE_32(tape_header->nzh_minor),
 456             LE_32(tape_header->nzh_hdrlen));
 457 
 458         free(buf);
 459         return (-1);
 460 }
 461 
 462 int
 463 ndmpd_zfs_backup_starter(void *arg)
 464 {
 465         ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
 466         ndmpd_session_t *session = (ndmpd_session_t *)
 467             (ndmpd_zfs_params->mp_daemon_cookie);
 468         int cleanup_err = 0;
 469         int err = 0;
 470 
 471         ndmp_session_ref(session);
 472 
 473         if (ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args) != 0) {
 474                 err = -1;
 475                 goto _done;
 476         }
 477 
 478         err = ndmpd_zfs_backup(ndmpd_zfs_args);
 479 
 480         cleanup_err = ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args, err);
 481 
 482         NDMP_LOG(LOG_DEBUG,
 483             "data bytes_total(including header):%llu",
 484             session->ns_data.dd_module.dm_stats.ms_bytes_processed);
 485 
 486         if (err == 0)
 487                 err = ndmpd_zfs_send_fhist(ndmpd_zfs_args);
 488 
 489 _done:
 490         NS_DEC(nbk);
 491         MOD_DONE(ndmpd_zfs_params, err ? err : cleanup_err);
 492         ndmp_session_unref(session);
 493         ndmpd_zfs_fini(ndmpd_zfs_args);
 494 
 495         return (err);
 496 }
 497 
 498 static int
 499 ndmpd_zfs_send_fhist(ndmpd_zfs_args_t *ndmpd_zfs_args)
 500 {
 501         ndmpd_session_t *session = (ndmpd_session_t *)
 502             (ndmpd_zfs_params->mp_daemon_cookie);
 503         struct stat64 st;
 504         char *envp;
 505 
 506         envp = MOD_GETENV(ndmpd_zfs_params, "HIST");
 507         if (!envp)
 508                 return (0);
 509 
 510         if (!(strchr("YT", toupper(*envp)))) {
 511                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
 512                     "HIST is not set.  No file history will be "
 513                     "generated.\n");
 514                 return (0);
 515         }
 516 
 517         /* Build up a sample root dir stat */
 518         (void) memset(&st, 0, sizeof (struct stat64));
 519         st.st_mode = S_IFDIR | 0777;
 520         st.st_mtime = st.st_atime = st.st_ctime = time(NULL);
 521         st.st_uid = st.st_gid = 0;
 522         st.st_size = 1;
 523         st.st_nlink = 1;
 524 
 525         if (ndmpd_api_file_history_dir_v3(session, ".", ROOT_INODE,
 526             ROOT_INODE) != 0)
 527                 return (-1);
 528         if (ndmpd_api_file_history_dir_v3(session, "..", ROOT_INODE,
 529             ROOT_INODE) != 0)
 530                 return (-1);
 531         if (ndmpd_api_file_history_node_v3(session, ROOT_INODE, &st, 0) != 0)
 532                 return (-1);
 533 
 534         ndmpd_file_history_cleanup(session, TRUE);
 535         return (0);
 536 }
 537 
 538 static int
 539 ndmpd_zfs_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
 540 {
 541         ndmpd_session_t *session = (ndmpd_session_t *)
 542             (ndmpd_zfs_params->mp_daemon_cookie);
 543         int *read_err = NULL;
 544         int *write_err = NULL;
 545         int result = 0;
 546         int err;
 547 
 548         if (session->ns_eof)
 549                 return (-1);
 550 
 551         if (!session->ns_data.dd_abort) {
 552                 if (ndmpd_zfs_header_write(session)) {
 553                         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
 554                             "ndmpd_zfs header write error\n");
 555                         return (-1);
 556                 }
 557 
 558                 err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
 559                     &read_err, &write_err);
 560 
 561                 if (err || read_err || write_err || session->ns_eof)
 562                         result = EPIPE;
 563         }
 564 
 565         if (session->ns_data.dd_abort) {
 566                 ndmpd_audit_backup(session->ns_connection,
 567                     ndmpd_zfs_args->nz_dataset,
 568                     session->ns_data.dd_data_addr.addr_type,
 569                     ndmpd_zfs_args->nz_dataset, EINTR);
 570                 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
 571                     ndmpd_zfs_args->nz_dataset);
 572 
 573                 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
 574                 err = -1;
 575         } else {
 576                 ndmpd_audit_backup(session->ns_connection,
 577                     ndmpd_zfs_args->nz_dataset,
 578                     session->ns_data.dd_data_addr.addr_type,
 579                     ndmpd_zfs_args->nz_dataset, result);
 580 
 581                 err = ndmpd_zfs_post_backup(ndmpd_zfs_args);
 582                 if (err || result)
 583                         err = -1;
 584 
 585                 if (err == 0)  {
 586                         NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished.",
 587                             ndmpd_zfs_args->nz_dataset);
 588                 } else {
 589                         NDMP_LOG(LOG_DEBUG, "An error occurred while backing up"
 590                             " \"%s\"", ndmpd_zfs_args->nz_dataset);
 591                 }
 592         }
 593 
 594         return (err);
 595 }
 596 
 597 /*
 598  * ndmpd_zfs_backup_send_read()
 599  *
 600  * This routine executes zfs_send() to create the backup data stream.
 601  * The value of ZFS_MODE determines the type of zfs_send():
 602  *      dataset ('d'): Only the dataset specified (i.e., top level) is backed up
 603  *      recursive ('r'): The dataset and its child file systems are backed up
 604  *      package ('p'): Same as 'r', except all intermediate snapshots are also
 605  *                      backed up
 606  *
 607  * Volumes do not have descednants, so 'd' and 'r' produce equivalent results.
 608  */
 609 
 610 static int
 611 ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
 612 {
 613         ndmpd_session_t *session = (ndmpd_session_t *)
 614             (ndmpd_zfs_params->mp_daemon_cookie);
 615         sendflags_t flags = { 0 };
 616         char *fromsnap = NULL;
 617         zfs_handle_t *zhp;
 618         int err;
 619 
 620         zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
 621             ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
 622 
 623         if (!zhp) {
 624                 if (!session->ns_data.dd_abort)
 625                         NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
 626                 return (-1);
 627         }
 628 
 629         switch (ndmpd_zfs_args->nz_zfs_mode) {
 630         case ('d'):
 631                 flags.props = B_TRUE;
 632                 break;
 633         case ('r'):
 634                 flags.replicate = B_TRUE;
 635                 break;
 636         case ('p'):
 637                 flags.doall = B_TRUE;
 638                 flags.replicate = B_TRUE;
 639                 break;
 640         default:
 641                 NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c",
 642                     ndmpd_zfs_args->nz_zfs_mode);
 643                 zfs_close(zhp);
 644                 return (-1);
 645         }
 646 
 647         if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
 648                 if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') {
 649                         NDMP_LOG(LOG_ERR, "no fromsnap");
 650                         zfs_close(zhp);
 651                         return (-1);
 652                 }
 653                 fromsnap = ndmpd_zfs_args->nz_fromsnap;
 654         }
 655 
 656         err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, &flags,
 657             ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL);
 658 
 659         if (err && !session->ns_data.dd_abort)
 660                 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err);
 661 
 662         zfs_close(zhp);
 663 
 664         return (err);
 665 }
 666 
 667 /*
 668  * ndmpd_zfs_backup_tape_write()
 669  *
 670  * The data begins on a mover record boundary (because
 671  * the header is the size of a mover record--i.e.
 672  * ndmpd_zfs_args->nz_bufsize).
 673  */
 674 
 675 static int
 676 ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
 677 {
 678         ndmpd_session_t *session = (ndmpd_session_t *)
 679             (ndmpd_zfs_params->mp_daemon_cookie);
 680         int bufsize = ndmpd_zfs_args->nz_bufsize;
 681         u_longlong_t *bytes_totalp;
 682         int count;
 683         char *buf;
 684 
 685         buf = ndmp_malloc(bufsize);
 686         if (buf == NULL) {
 687                 NDMP_LOG(LOG_DEBUG, "buf NULL");
 688                 return (-1);
 689         }
 690 
 691         bytes_totalp =
 692             &(session->ns_data.dd_module.dm_stats.ms_bytes_processed);
 693 
 694         for (;;) {
 695                 bzero(buf, bufsize);
 696 
 697                 count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
 698                     bufsize);
 699 
 700                 if (count == 0) /* EOF */ {
 701                         NDMP_LOG(LOG_DEBUG,
 702                             "zfs_send stream size: %llu bytes; "
 703                             "full backup size (including header): %llu",
 704                             *bytes_totalp - bufsize, *bytes_totalp);
 705                         free(buf);
 706 
 707                         return (ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args,
 708                             *bytes_totalp));
 709                 }
 710 
 711                 if (count == -1) {
 712                         NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)",
 713                             errno);
 714                         free(buf);
 715                         return (-1);
 716                 }
 717                 NS_ADD(rdisk, count);
 718 
 719                 if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) {
 720                         (void) ndmpd_zfs_abort((void *) ndmpd_zfs_args);
 721                         NDMP_LOG(LOG_ERR, "MOD_WRITE error");
 722                         free(buf);
 723                         return (-1);
 724                 }
 725 
 726                 *bytes_totalp += count;
 727         }
 728         /* NOTREACHED */
 729 }
 730 
 731 static int
 732 ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args,
 733     u_longlong_t bytes_total)
 734 {
 735         char zfs_backup_size[32];
 736         int err;
 737 
 738         (void) snprintf(zfs_backup_size, sizeof (zfs_backup_size), "%llu",
 739             bytes_total);
 740 
 741         err = MOD_ADDENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE", zfs_backup_size);
 742 
 743         if (err) {
 744                 NDMP_LOG(LOG_ERR, "Failed to add ZFS_BACKUP_SIZE env");
 745                 return (-1);
 746         }
 747 
 748         NDMP_LOG(LOG_DEBUG, "Added ZFS_BACKUP_SIZE env: %s", zfs_backup_size);
 749 
 750         return (0);
 751 }
 752 
 753 int
 754 ndmpd_zfs_restore_starter(void *arg)
 755 {
 756         ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
 757         ndmpd_session_t *session = (ndmpd_session_t *)
 758             (ndmpd_zfs_params->mp_daemon_cookie);
 759         int err;
 760 
 761         ndmp_session_ref(session);
 762 
 763         err = ndmpd_zfs_restore(ndmpd_zfs_args);
 764 
 765         MOD_DONE(ndmpd_zfs_params, err);
 766 
 767         NS_DEC(nrs);
 768 
 769         ndmp_session_unref(session);
 770 
 771         ndmpd_zfs_fini(ndmpd_zfs_args);
 772 
 773         return (err);
 774 }
 775 
 776 static int
 777 ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
 778 {
 779         ndmpd_session_t *session = (ndmpd_session_t *)
 780             (ndmpd_zfs_params->mp_daemon_cookie);
 781         int *read_err = NULL;
 782         int *write_err = NULL;
 783         int result = 0;
 784         int err;
 785 
 786         if (!session->ns_data.dd_abort) {
 787                 if (ndmpd_zfs_header_read(ndmpd_zfs_args)) {
 788                         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
 789                             "ndmpd_zfs header read error\n");
 790                         return (-1);
 791                 }
 792 
 793                 err = ndmpd_zfs_reader_writer(ndmpd_zfs_args,
 794                     &write_err, &read_err);
 795 
 796                 if (err || read_err || write_err || session->ns_eof)
 797                         result = EIO;
 798         }
 799 
 800         if (session->ns_data.dd_abort) {
 801                 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
 802                     ndmpd_zfs_args->nz_dataset);
 803                 ndmpd_audit_restore(session->ns_connection,
 804                     ndmpd_zfs_args->nz_dataset,
 805                     session->ns_data.dd_data_addr.addr_type,
 806                     ndmpd_zfs_args->nz_dataset, EINTR);
 807                 (void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
 808                 err = -1;
 809         } else {
 810                 ndmpd_audit_restore(session->ns_connection,
 811                     ndmpd_zfs_args->nz_dataset,
 812                     session->ns_data.dd_data_addr.addr_type,
 813                     ndmpd_zfs_args->nz_dataset, result);
 814                 err = ndmpd_zfs_post_restore(ndmpd_zfs_args);
 815                 if (err || result)
 816                         err = -1;
 817 
 818                 if (err == 0) {
 819                         NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished",
 820                             ndmpd_zfs_args->nz_dataset);
 821                 } else {
 822                         NDMP_LOG(LOG_DEBUG, "An error occurred while restoring"
 823                             " to \"%s\"", ndmpd_zfs_args->nz_dataset);
 824                 }
 825         }
 826 
 827         return (err);
 828 }
 829 
 830 static int
 831 ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
 832 {
 833         ndmpd_session_t *session = (ndmpd_session_t *)
 834             (ndmpd_zfs_params->mp_daemon_cookie);
 835         int bufsize = ndmpd_zfs_args->nz_bufsize;
 836         u_longlong_t backup_size = ndmpd_zfs_args->nz_zfs_backup_size;
 837         u_longlong_t *bytes_totalp;
 838         u_longlong_t bytes;
 839         char *buf;
 840         int count;
 841         int err;
 842 
 843         buf = ndmp_malloc(bufsize);
 844         if (buf == NULL) {
 845                 NDMP_LOG(LOG_DEBUG, "buf NULL");
 846                 return (-1);
 847         }
 848 
 849         bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total;
 850 
 851         while (*bytes_totalp < backup_size) {
 852 
 853                 bytes = backup_size - *bytes_totalp;
 854 
 855                 if (bytes >= bufsize)
 856                         bytes = bufsize;
 857 
 858                 err = MOD_READ(ndmpd_zfs_params, buf, bytes);
 859 
 860                 if (err != 0) {
 861                         NDMP_LOG(LOG_ERR, "MOD_READ error: %d; returning -1",
 862                             err);
 863                         free(buf);
 864                         return (-1);
 865                 }
 866 
 867                 count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf,
 868                     bytes);
 869 
 870                 if (count != bytes) {
 871                         NDMP_LOG(LOG_ERR, "count (%d) != bytes (%d)",
 872                             count, bytes);
 873 
 874                         if (count == -1) {
 875                                 NDMP_LOG(LOG_ERR, "pipe write error: errno: %d",
 876                                     errno);
 877 
 878                                 if (session->ns_data.dd_abort)
 879                                         NDMP_LOG(LOG_DEBUG, "abort set");
 880                         }
 881 
 882                         free(buf);
 883                         return (-1);
 884                 }
 885 
 886                 NS_ADD(wdisk, count);
 887 
 888                 *bytes_totalp += count;
 889         }
 890 
 891         free(buf);
 892         return (0);
 893 }
 894 
 895 /*
 896  * ndmpd_zfs_restore_recv_write()
 897  *
 898  * This routine executes zfs_receive() to restore the backup.
 899  */
 900 
 901 static int
 902 ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
 903 {
 904         ndmpd_session_t *session = (ndmpd_session_t *)
 905             (ndmpd_zfs_params->mp_daemon_cookie);
 906         recvflags_t flags;
 907         int err;
 908 
 909         bzero(&flags, sizeof (recvflags_t));
 910 
 911         flags.nomount = B_TRUE;
 912 
 913         NDMP_LOG(LOG_DEBUG, "nz_zfs_force: %d\n", ndmpd_zfs_args->nz_zfs_force);
 914 
 915         if (ndmpd_zfs_args->nz_zfs_force)
 916                 flags.force = B_TRUE;
 917 
 918         err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
 919             NULL, &flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL);
 920 
 921         if (err && !session->ns_data.dd_abort)
 922                 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err);
 923 
 924         return (err);
 925 }
 926 
 927 /*
 928  * ndmpd_zfs_reader_writer()
 929  *
 930  * Two separate threads are used for actual backup or restore.
 931  */
 932 
 933 static int
 934 ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args,
 935     int **sendrecv_errp, int **tape_errp)
 936 {
 937         funct_t sendrecv_func;
 938         funct_t tape_func;
 939         int sendrecv_err;
 940         int tape_err;
 941 
 942         switch (ndmpd_zfs_params->mp_operation) {
 943         case NDMP_DATA_OP_BACKUP:
 944                 sendrecv_func = (funct_t)ndmpd_zfs_backup_send_read;
 945                 tape_func = (funct_t)ndmpd_zfs_backup_tape_write;
 946                 break;
 947         case NDMP_DATA_OP_RECOVER:
 948                 sendrecv_func = (funct_t)ndmpd_zfs_restore_recv_write;
 949                 tape_func = (funct_t)ndmpd_zfs_restore_tape_read;
 950                 break;
 951         }
 952 
 953         sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread,
 954             NULL, sendrecv_func, ndmpd_zfs_args);
 955 
 956         if (sendrecv_err == 0) {
 957                 tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread,
 958                     NULL, tape_func, ndmpd_zfs_args);
 959 
 960                 if (tape_err) {
 961                         /*
 962                          * The close of the tape side of the pipe will cause
 963                          * nz_sendrecv_thread to error in the zfs_send/recv()
 964                          * call and to return.  Hence we do not need
 965                          * to explicitly cancel the sendrecv_thread here
 966                          * (the pthread_join() below is sufficient).
 967                          */
 968 
 969                         (void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]);
 970                         NDMP_LOG(LOG_ERR, "Could not start tape thread; "
 971                             "aborting z-op");
 972                 }
 973 
 974                 (void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread,
 975                     (void **) sendrecv_errp);
 976         }
 977 
 978         if ((tape_err == 0) &&
 979             (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER))
 980                 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
 981 
 982         ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS);
 983 
 984         if ((sendrecv_err == 0) && (tape_err == 0)) {
 985                 (void) pthread_join(ndmpd_zfs_args->nz_tape_thread,
 986                     (void **) tape_errp);
 987         }
 988 
 989         if ((tape_err == 0) &&
 990             (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP))
 991                 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE);
 992 
 993         return (sendrecv_err ? sendrecv_err : tape_err);
 994 }
 995 
 996 int
 997 ndmpd_zfs_abort(void *arg)
 998 {
 999         ndmpd_zfs_args_t *ndmpd_zfs_args = arg;
1000         char str[8];
1001 
1002         if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)
1003                 (void) strlcpy(str, "backup", 8);
1004         else
1005                 (void) strlcpy(str, "recover", 8);
1006 
1007         NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation",
1008             str);
1009 
1010         ndmpd_zfs_close_fds(ndmpd_zfs_args);
1011 
1012         return (0);
1013 }
1014 
1015 /*
1016  * ndmpd_zfs_pre_backup()
1017  *
1018  * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL.
1019  * This ensures that ndmp_include_zfs() will fail, which is
1020  * a requirement for "zfs"-type backup.
1021  */
1022 
1023 int
1024 ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
1025 {
1026         ndmpd_session_t *session = (ndmpd_session_t *)
1027             (ndmpd_zfs_params->mp_daemon_cookie);
1028         ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1029         int err;
1030 
1031         if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL)
1032                 return (0);
1033 
1034         (void) memset(nctxp, 0, sizeof (ndmp_context_t));
1035         nctxp->nc_plversion = ndmp_pl->np_plversion;
1036         nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
1037         nctxp->nc_ddata = (void *) session;
1038         nctxp->nc_params = ndmpd_zfs_params;
1039 
1040         err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp,
1041             ndmpd_zfs_args->nz_dataset);
1042 
1043         if (err != 0) {
1044                 NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m");
1045                 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args);
1046         }
1047 
1048         return (err);
1049 }
1050 
1051 int
1052 ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args)
1053 {
1054         ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1055         int err = 0;
1056 
1057         if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL)
1058                 return (0);
1059 
1060         err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err);
1061 
1062         if (err == -1)
1063                 NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
1064 
1065         return (err);
1066 }
1067 
1068 int
1069 ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
1070 {
1071         ndmpd_session_t *session = (ndmpd_session_t *)
1072             (ndmpd_zfs_params->mp_daemon_cookie);
1073         ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1074         char bkpath[ZFS_MAX_DATASET_NAME_LEN];
1075         int err;
1076 
1077         if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL)
1078                 return (0);
1079 
1080         err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath,
1081             ZFS_MAX_DATASET_NAME_LEN);
1082 
1083         if (err != 0) {
1084                 NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err);
1085                 return (-1);
1086         }
1087 
1088         err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args);
1089 
1090         if (err != 0) {
1091                 NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err);
1092                 return (-1);
1093         }
1094 
1095         (void) memset(nctxp, 0, sizeof (ndmp_context_t));
1096         nctxp->nc_ddata = (void *) session;
1097         nctxp->nc_params = ndmpd_zfs_params;
1098 
1099         err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath,
1100             ndmpd_zfs_args->nz_dataset);
1101 
1102         if (err != 0) {
1103                 NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
1104                 return (-1);
1105         }
1106 
1107         return (0);
1108 }
1109 
1110 int
1111 ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args)
1112 {
1113         ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx;
1114         int err = 0;
1115 
1116         if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL)
1117                 return (0);
1118 
1119         err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err);
1120 
1121         if (err == -1)
1122                 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
1123 
1124         return (err);
1125 }
1126 
1127 boolean_t
1128 ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1129 {
1130         ndmpd_zfs_snapfind_t snapdata;
1131 
1132         if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0)
1133                 return (B_FALSE);
1134 
1135         if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args))
1136                 return (B_FALSE);
1137 
1138         if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
1139                 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
1140                     snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE);
1141 
1142                 snapdata.nzs_snapname[0] = '\0';
1143                 snapdata.nzs_snapprop[0] = '\0';
1144 
1145                 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata))
1146                         return (B_FALSE);
1147 
1148                 if (snapdata.nzs_snapname[0] == '\0') { /* not found */
1149                         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1150                             "Snapshot for level %d does not exist\n",
1151                             ndmpd_zfs_args->nz_level-1);
1152                         return (B_FALSE);
1153                 }
1154 
1155                 (void) strlcpy(ndmpd_zfs_args->nz_fromsnap,
1156                     snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN);
1157         }
1158 
1159         return (B_TRUE);
1160 }
1161 
1162 /*
1163  * ndmpd_zfs_backup_pathvalid()
1164  *
1165  * Make sure the path is of an existing dataset
1166  */
1167 
1168 static boolean_t
1169 ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1170 {
1171         char zpath[ZFS_MAX_DATASET_NAME_LEN];
1172         char propstr[ZFS_MAXPROPLEN];
1173         zfs_handle_t *zhp;
1174         zfs_type_t ztype = 0;
1175         int err;
1176 
1177         if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
1178             ZFS_MAX_DATASET_NAME_LEN) != 0)
1179                 return (B_FALSE);
1180 
1181         if (ndmpd_zfs_args->nz_snapname[0] != '\0') {
1182                 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath,
1183                     ZFS_TYPE_SNAPSHOT);
1184 
1185                 if (!zhp) {
1186                         NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args,
1187                             "zfs_open (snap)");
1188                         ndmpd_zfs_args->nz_snapname[0] = '\0';
1189                         ndmpd_zfs_args->nz_dataset[0] = '\0';
1190                         return (B_FALSE);
1191                 }
1192 
1193                 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
1194 
1195                 zfs_close(zhp);
1196 
1197                 if (err) {
1198                         NDMP_LOG(LOG_DEBUG,
1199                             "ndmpd_zfs_snapshot_prop_get failed");
1200                         return (-1);
1201                 }
1202 
1203                 if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) {
1204                         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1205                             "cannot use an ndmpd-generated snapshot\n");
1206                         return (B_FALSE);
1207                 }
1208         }
1209 
1210         zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
1211             ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET);
1212 
1213         if (zhp) {
1214                 ztype = zfs_get_type(zhp);
1215                 zfs_close(zhp);
1216         }
1217 
1218         if ((ztype == ZFS_TYPE_VOLUME) ||
1219             (ztype == ZFS_TYPE_FILESYSTEM)) {
1220                 ndmpd_zfs_args->nz_type = ztype;
1221                 return (B_TRUE);
1222         }
1223 
1224         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1225             "Invalid file system or volume.\n");
1226 
1227         return (B_FALSE);
1228 }
1229 
1230 /*
1231  * ndmpd_zfs_backup_getpath()
1232  *
1233  * Retrieve the backup path from the environment, which should
1234  * be of the form "/dataset[@snap]".  The leading slash is required
1235  * by certain DMA's but can otherwise be ignored.
1236  *
1237  * (Note: "dataset" can consist of more than one component,
1238  * e.g. "pool", "pool/volume", "pool/fs/fs2".)
1239  *
1240  * The dataset name and the snapshot name (if any) will be
1241  * stored in ndmpd_zfs_args.
1242  */
1243 
1244 static int
1245 ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath,
1246     int zlen)
1247 {
1248         char *env_path;
1249         char *at;
1250 
1251         env_path = get_backup_path_v3(ndmpd_zfs_params);
1252         if (env_path == NULL)
1253                 return (-1);
1254 
1255         if (env_path[0] != '/') {
1256                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1257                     "Invalid path: %s (leading slash required)\n", env_path);
1258                 return (-1);
1259         }
1260 
1261         (void) strlcpy(zpath, &env_path[1], zlen);
1262         (void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1],
1263             ZFS_MAX_DATASET_NAME_LEN);
1264 
1265         at = strchr(ndmpd_zfs_args->nz_dataset, '@');
1266         if (at) {
1267                 *at = '\0';
1268                 (void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at,
1269                     ZFS_MAX_DATASET_NAME_LEN);
1270         } else {
1271                 ndmpd_zfs_args->nz_snapname[0] = '\0';
1272         }
1273 
1274         (void) trim_whitespace(ndmpd_zfs_args->nz_dataset);
1275 
1276         return (0);
1277 }
1278 
1279 static int
1280 ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1281 {
1282         return (ndmpd_zfs_getenv(ndmpd_zfs_args));
1283 }
1284 
1285 boolean_t
1286 ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1287 {
1288         if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0)
1289                 return (B_FALSE);
1290 
1291         if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args))
1292                 return (B_FALSE);
1293 
1294         return (B_TRUE);
1295 }
1296 
1297 static boolean_t
1298 ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args)
1299 {
1300         zfs_handle_t *zhp;
1301         char *at;
1302 
1303         if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0)
1304                 return (B_FALSE);
1305 
1306         at = strchr(ndmpd_zfs_args->nz_dataset, '@');
1307 
1308         if (at) {
1309                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING,
1310                     "%s ignored in restore path\n", at);
1311                 *at = '\0';
1312         }
1313 
1314         ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
1315 
1316         zhp = zfs_open(ndmpd_zfs_args->nz_zlibh,
1317             ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type);
1318 
1319         if (zhp) {
1320                 zfs_close(zhp);
1321 
1322                 if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) {
1323                         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1324                             "Restore dataset exists.\n"
1325                             "A nonexistent dataset must be specified "
1326                             "for 'zfs' non-incremental restore.\n");
1327                         return (B_FALSE);
1328                 }
1329         }
1330 
1331         NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset);
1332 
1333         return (B_TRUE);
1334 }
1335 
1336 /*
1337  * ndmpd_zfs_restore_getpath()
1338  *
1339  * Be sure to not include the leading slash, which is required for
1340  * compatibility with backup applications (NBU) but which is not part
1341  * of the ZFS syntax.  (Note that this done explicitly in all paths
1342  * below except those calling ndmpd_zfs_backup_getpath(), because it is
1343  * already stripped in that function.)
1344  *
1345  * In addition, the DMA might add a trailing slash to the path.
1346  * Strip all such slashes.
1347  */
1348 
1349 static int
1350 ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args)
1351 {
1352         int version = ndmpd_zfs_params->mp_protocol_version;
1353         char zpath[ZFS_MAX_DATASET_NAME_LEN];
1354         mem_ndmp_name_v3_t *namep_v3;
1355         char *dataset = ndmpd_zfs_args->nz_dataset;
1356         char *nm;
1357         char *p;
1358         int len;
1359         int err;
1360 
1361         namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0);
1362 
1363         if (namep_v3 == NULL) {
1364                 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]");
1365                 return (-1);
1366         }
1367 
1368         if (namep_v3->nm3_dpath) {
1369                 if (namep_v3->nm3_dpath[0] != '/') {
1370                         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1371                             "Invalid path: %s (leading slash required)\n",
1372                             namep_v3->nm3_dpath);
1373                         return (-1);
1374                 }
1375 
1376                 (void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]),
1377                     ZFS_MAX_DATASET_NAME_LEN);
1378 
1379                 if (namep_v3->nm3_newnm) {
1380                         (void) strlcat(dataset, "/", ZFS_MAX_DATASET_NAME_LEN);
1381                         (void) strlcat(dataset, namep_v3->nm3_newnm,
1382                             ZFS_MAX_DATASET_NAME_LEN);
1383 
1384                 } else {
1385                         if (version == NDMPV3) {
1386                                 /*
1387                                  * The following does not apply for V4.
1388                                  *
1389                                  * Find the last component of nm3_opath.
1390                                  * nm3_opath has no trailing '/'.
1391                                  */
1392                                 p = strrchr(namep_v3->nm3_opath, '/');
1393                                 nm = p? p : namep_v3->nm3_opath;
1394                                 (void) strlcat(dataset, "/",
1395                                     ZFS_MAX_DATASET_NAME_LEN);
1396                                 (void) strlcat(dataset, nm,
1397                                     ZFS_MAX_DATASET_NAME_LEN);
1398                         }
1399                 }
1400         } else {
1401                 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath,
1402                     ZFS_MAX_DATASET_NAME_LEN);
1403                 if (err)
1404                         return (err);
1405         }
1406 
1407         len = strlen(dataset);
1408         while (dataset[len-1] == '/') {
1409                 dataset[len-1] = '\0';
1410                 len--;
1411         }
1412 
1413         return (0);
1414 }
1415 
1416 static int
1417 ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1418 {
1419         if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args) != 0)
1420                 return (-1);
1421 
1422         return (ndmpd_zfs_getenv(ndmpd_zfs_args));
1423 }
1424 
1425 static int
1426 ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args)
1427 {
1428 
1429         if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0)
1430                 return (-1);
1431 
1432         if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0)
1433                 return (-1);
1434 
1435         if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0)
1436                 return (-1);
1437 
1438         if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0)
1439                 return (-1);
1440 
1441         if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0)
1442                 return (-1);
1443 
1444         return (0);
1445 }
1446 
1447 static int
1448 ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args)
1449 {
1450         char *envp;
1451 
1452         envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE");
1453 
1454         if (envp == NULL) {
1455                 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, "
1456                     "defaulting to recursive");
1457                 ndmpd_zfs_args->nz_zfs_mode = 'r';
1458                 return (0);
1459         }
1460 
1461         if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) {
1462                 ndmpd_zfs_args->nz_zfs_mode = 'd';
1463         } else if ((strcmp(envp, "recursive") == 0) ||
1464             (strcmp(envp, "r") == 0)) {
1465                 ndmpd_zfs_args->nz_zfs_mode = 'r';
1466         } else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) {
1467                 ndmpd_zfs_args->nz_zfs_mode = 'p';
1468         } else {
1469                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1470                     "Invalid ZFS_MODE value \"%s\".\n", envp);
1471                 return (-1);
1472         }
1473 
1474         NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"",
1475             ndmpd_zfs_args->nz_zfs_mode);
1476 
1477         return (0);
1478 }
1479 
1480 /*
1481  * ndmpd_zfs_getenv_zfs_force()
1482  *
1483  * If SMF property zfs-force-override is set to "yes" or "no", this
1484  * value will override any value of NDMP environment variable ZFS_FORCE
1485  * as set by the DMA admin (or override the default of 'n', if ZFS_FORCE
1486  * is not set).  By default, zfs-force-override is "off", which means it
1487  * will not override ZFS_FORCE.
1488  */
1489 
1490 static int
1491 ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args)
1492 {
1493         char *envp_force;
1494         char *override;
1495 
1496         override = ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE);
1497 
1498         if (strcasecmp(override, "yes") == 0) {
1499                 ndmpd_zfs_args->nz_zfs_force = B_TRUE;
1500                 NDMP_LOG(LOG_NOTICE,
1501                     "SMF property zfs-force-override set to 'yes', "
1502                     "overriding ZFS_FORCE");
1503                 return (0);
1504         }
1505 
1506         if (strcasecmp(override, "no") == 0) {
1507                 ndmpd_zfs_args->nz_zfs_force = B_FALSE;
1508                 NDMP_LOG(LOG_NOTICE,
1509                     "SMF property zfs-force-override set to 'no', "
1510                     "overriding ZFS_FORCE");
1511                 return (0);
1512         }
1513 
1514         if (strcasecmp(override, "off") != 0) {
1515                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1516                     "SMF property zfs-force-override set to invalid value of "
1517                     "'%s'; treating it as 'off'.", override);
1518         }
1519 
1520         envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE");
1521 
1522         if (envp_force == NULL) {
1523                 NDMP_LOG(LOG_DEBUG,
1524                     "env(ZFS_FORCE) not specified, defaulting to FALSE");
1525                 ndmpd_zfs_args->nz_zfs_force = B_FALSE;
1526                 return (0);
1527         }
1528 
1529         /*
1530          * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1531          */
1532 
1533         if (strchr("tTyY", *envp_force))
1534                 ndmpd_zfs_args->nz_zfs_force = B_TRUE;
1535 
1536         NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force);
1537 
1538         return (0);
1539 }
1540 
1541 static int
1542 ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args)
1543 {
1544         char *envp;
1545 
1546         envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL");
1547 
1548         if (envp == NULL) {
1549                 NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, "
1550                     "defaulting to 0");
1551                 ndmpd_zfs_args->nz_level = 0;
1552                 return (0);
1553         }
1554 
1555         if (envp[1] != '\0') {
1556                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1557                     "Invalid backup level \"%s\".\n", envp);
1558                 return (-1);
1559         }
1560 
1561         if (!isdigit(*envp)) {
1562                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1563                     "Invalid backup level \"%s\".\n", envp);
1564                 return (-1);
1565         }
1566 
1567         ndmpd_zfs_args->nz_level = atoi(envp);
1568 
1569         NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"",
1570             ndmpd_zfs_args->nz_level);
1571 
1572         return (0);
1573 }
1574 
1575 static int
1576 ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args)
1577 {
1578         char *envp_update;
1579 
1580         envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE");
1581 
1582         if (envp_update == NULL) {
1583                 NDMP_LOG(LOG_DEBUG,
1584                     "env(UPDATE) not specified, defaulting to TRUE");
1585                 ndmpd_zfs_args->nz_update = B_TRUE;
1586                 return (0);
1587         }
1588 
1589         /*
1590          * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4).
1591          */
1592 
1593         if (strchr("tTyY", *envp_update))
1594                 ndmpd_zfs_args->nz_update = B_TRUE;
1595 
1596         NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update);
1597 
1598         return (0);
1599 }
1600 
1601 static int
1602 ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args)
1603 {
1604         char *envp;
1605 
1606         envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME");
1607 
1608         if (envp == NULL) {
1609                 NDMP_LOG(LOG_DEBUG,
1610                     "env(DMP_NAME) not specified, defaulting to 'level'");
1611                 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level",
1612                     NDMPD_ZFS_DMP_NAME_MAX);
1613                 return (0);
1614         }
1615 
1616         if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp))
1617                 return (-1);
1618 
1619         (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp,
1620             NDMPD_ZFS_DMP_NAME_MAX);
1621 
1622         NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp);
1623 
1624         return (0);
1625 }
1626 
1627 static int
1628 ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args)
1629 {
1630         char *zfs_backup_size;
1631 
1632         zfs_backup_size = MOD_GETENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE");
1633 
1634         if (zfs_backup_size == NULL) {
1635                 NDMP_LOG(LOG_ERR, "ZFS_BACKUP_SIZE env is NULL");
1636                 return (-1);
1637         }
1638 
1639         NDMP_LOG(LOG_DEBUG, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size);
1640 
1641         (void) sscanf(zfs_backup_size, "%llu",
1642             &ndmpd_zfs_args->nz_zfs_backup_size);
1643 
1644         return (0);
1645 }
1646 
1647 /*
1648  * ndmpd_zfs_dmp_name_valid()
1649  *
1650  * This function verifies that the dmp_name is valid.
1651  *
1652  * The dmp_name is restricted to alphanumeric characters plus
1653  * the underscore and hyphen, and must be 31 characters or less.
1654  * This is due to its use in the NDMPD_ZFS_PROP_INCR property
1655  * and in the ZFS snapshot name (if an ndmpd-generated snapshot
1656  * is required).
1657  */
1658 
1659 static boolean_t
1660 ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name)
1661 {
1662         char *c;
1663 
1664         if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) {
1665                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1666                     "DMP_NAME %s is longer than %d\n",
1667                     dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1);
1668                 return (B_FALSE);
1669         }
1670 
1671         for (c = dmp_name; *c != '\0'; c++) {
1672                 if (!isalpha(*c) && !isdigit(*c) &&
1673                     (*c != '_') && (*c != '-')) {
1674                         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1675                             "DMP_NAME %s contains illegal character %c\n",
1676                             dmp_name, *c);
1677                         return (B_FALSE);
1678                 }
1679         }
1680 
1681         NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name);
1682         return (B_TRUE);
1683 }
1684 
1685 /*
1686  * ndmpd_zfs_is_incremental()
1687  *
1688  * This can only be called after ndmpd_zfs_getenv_level()
1689  * has been called.
1690  */
1691 
1692 static boolean_t
1693 ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args)
1694 {
1695         return (ndmpd_zfs_args->nz_level != 0);
1696 }
1697 
1698 /*
1699  * ndmpd_zfs_snapshot_prepare()
1700  *
1701  * If no snapshot was supplied by the user, create a snapshot
1702  * for use by ndmpd.
1703  */
1704 
1705 static int
1706 ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args)
1707 {
1708         ndmpd_session_t *session = (ndmpd_session_t *)
1709             (ndmpd_zfs_params->mp_daemon_cookie);
1710         boolean_t recursive = B_FALSE;
1711         int zfs_err = 0;
1712 
1713         if (session->ns_data.dd_abort) {
1714                 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
1715                     ndmpd_zfs_args->nz_dataset);
1716                 return (-1);
1717         }
1718 
1719         if (ndmpd_zfs_args->nz_snapname[0] == '\0') {
1720                 ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE;
1721 
1722                 if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) {
1723                         ndmpd_zfs_args->nz_snapname[0] = '\0';
1724 
1725                         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1726                             "Error creating snapshot for %s\n",
1727                             ndmpd_zfs_args->nz_dataset);
1728 
1729                         return (-1);
1730                 }
1731         }
1732 
1733         if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) {
1734                 NDMP_LOG(LOG_DEBUG,
1735                     "ndmpd_zfs_snapshot_prop_add error\n");
1736 
1737                 if (ndmpd_zfs_args->nz_ndmpd_snap) {
1738 
1739                         if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1740                                 recursive = B_TRUE;
1741 
1742                         (void) snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1743                             ndmpd_zfs_args->nz_snapname, recursive, B_FALSE,
1744                             &zfs_err);
1745                 }
1746 
1747                 return (-1);
1748         }
1749 
1750         return (0);
1751 }
1752 
1753 /*
1754  * ndmpd_zfs_snapshot_cleanup()
1755  *
1756  * If UPDATE = y, find the old snapshot (if any) corresponding to
1757  * {LEVEL, DMP_NAME, ZFS_MODE}. If it was ndmpd-generated,
1758  * remove the snapshot.  Otherwise, update its NDMPD_ZFS_PROP_INCR
1759  * property to remove {L, D, Z}.
1760  *
1761  * If UPDATE = n, if an ndmpd-generated snapshot was used for backup,
1762  * remove the snapshot.  Otherwise, update its NDMPD_ZFS_PROP_INCR
1763  * property to remove {L, D, Z}.
1764  */
1765 
1766 static int
1767 ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err)
1768 {
1769         ndmpd_session_t *session = (ndmpd_session_t *)
1770             (ndmpd_zfs_params->mp_daemon_cookie);
1771         ndmpd_zfs_snapfind_t snapdata;
1772         boolean_t ndmpd_generated = B_FALSE;
1773 
1774         bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t));
1775 
1776         (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
1777             snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE);
1778 
1779         if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) {
1780                 /*
1781                  * Find the existing snapshot, if any, to "unuse."
1782                  * Indicate that the current snapshot used for backup
1783                  * should be skipped in the search.  (The search is
1784                  * sorted by creation time but this cannot be relied
1785                  * upon for user-supplied snapshots.)
1786                  */
1787 
1788                 (void) snprintf(snapdata.nzs_snapskip, ZFS_MAX_DATASET_NAME_LEN,
1789                     "%s", ndmpd_zfs_args->nz_snapname);
1790 
1791                 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) {
1792                         NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n");
1793                         goto _remove_tmp_snap;
1794                 }
1795 
1796                 if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */
1797                         ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated
1798                             (snapdata.nzs_snapprop);
1799 
1800                         if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
1801                             ndmpd_generated, &snapdata) != 0) {
1802                                 NDMP_LOG(LOG_DEBUG,
1803                                     "ndmpd_zfs_snapshot_unuse error\n");
1804                                 goto _remove_tmp_snap;
1805                         }
1806                 }
1807 
1808                 if (session->ns_data.dd_abort)
1809                         goto _remove_tmp_snap;
1810 
1811                 return (0);
1812         }
1813 
1814 _remove_tmp_snap:
1815 
1816         (void) snprintf(snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN, "%s",
1817             ndmpd_zfs_args->nz_snapname);
1818 
1819         (void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop,
1820             ZFS_MAXPROPLEN);
1821 
1822         snapdata.nzs_snapskip[0] = '\0';
1823 
1824         if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args,
1825             ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) {
1826                 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n");
1827                 return (-1);
1828         }
1829 
1830         if (!ndmpd_zfs_args->nz_update)
1831                 return (0);
1832 
1833         return (-1);
1834 }
1835 
1836 static int
1837 ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args)
1838 {
1839         boolean_t recursive = B_FALSE;
1840 
1841         if (ndmpd_zfs_snapname_create(ndmpd_zfs_args,
1842             ndmpd_zfs_args->nz_snapname, ZFS_MAX_DATASET_NAME_LEN - 1) < 0) {
1843                 NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s",
1844                     errno, ndmpd_zfs_args->nz_dataset);
1845                 return (-1);
1846         }
1847 
1848         if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1849                 recursive = B_TRUE;
1850 
1851         if (snapshot_create(ndmpd_zfs_args->nz_dataset,
1852             ndmpd_zfs_args->nz_snapname, recursive, B_FALSE) != 0) {
1853                 NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s",
1854                     ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
1855                 return (-1);
1856         }
1857 
1858         NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s",
1859             ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname);
1860 
1861         return (0);
1862 }
1863 
1864 /*
1865  * ndmpd_zfs_snapshot_unuse()
1866  *
1867  * Given a pre-existing snapshot of the given {L, D, Z}:
1868  * If snapshot is ndmpd-generated, remove snapshot.
1869  * If not ndmpd-generated, or if the ndmpd-generated snapshot
1870  * cannot be destroyed, remove the {L, D, Z} substring from the
1871  * snapshot's NDMPD_ZFS_PROP_INCR property.
1872  *
1873  * In the event of a failure, it may be that two snapshots will
1874  * have the {L, D, Z} property set on them.  This is not desirable,
1875  * so return an error and log the failure.
1876  */
1877 
1878 static int
1879 ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args,
1880     boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p)
1881 {
1882         boolean_t recursive = B_FALSE;
1883         int zfs_err = 0;
1884         int err = 0;
1885 
1886         if (ndmpd_generated) {
1887                 if (ndmpd_zfs_args->nz_zfs_mode != 'd')
1888                         recursive = B_TRUE;
1889 
1890                 err = snapshot_destroy(ndmpd_zfs_args->nz_dataset,
1891                     snapdata_p->nzs_snapname, recursive, B_FALSE, &zfs_err);
1892 
1893                 if (err) {
1894                         NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;"
1895                             " err: %d; zfs_err: %d",
1896                             ndmpd_zfs_args->nz_dataset,
1897                             snapdata_p->nzs_snapname, err, zfs_err);
1898                         return (-1);
1899                 }
1900         }
1901 
1902         if (!ndmpd_generated || zfs_err) {
1903                 if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p))
1904                         return (-1);
1905         }
1906 
1907         return (0);
1908 }
1909 
1910 static boolean_t
1911 ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop)
1912 {
1913         char origin;
1914 
1915         (void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin);
1916 
1917         return (origin == 'n');
1918 }
1919 
1920 /*
1921  * ndmpd_zfs_snapshot_find()
1922  *
1923  * Find a snapshot with a particular value for
1924  * the NDMPD_ZFS_PROP_INCR property.
1925  */
1926 
1927 static int
1928 ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args,
1929     ndmpd_zfs_snapfind_t *snapdata)
1930 {
1931         zfs_handle_t *zhp;
1932         int err;
1933 
1934         zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
1935             ndmpd_zfs_args->nz_type);
1936 
1937         if (!zhp) {
1938                 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
1939                 return (-1);
1940         }
1941 
1942         err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find,
1943             snapdata);
1944 
1945         zfs_close(zhp);
1946 
1947         if (err) {
1948                 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d",
1949                     err);
1950                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
1951                     "Error iterating snapshots\n");
1952                 return (-1);
1953         }
1954 
1955         return (0);
1956 }
1957 
1958 /*
1959  * ndmpd_zfs_snapshot_prop_find()
1960  *
1961  * Find a snapshot with a particular value for
1962  * NDMPD_ZFS_PROP_INCR.  Fill in data for the first one
1963  * found (sorted by creation time).  However, skip the
1964  * the snapshot indicated in nzs_snapskip, if any.
1965  */
1966 
1967 static int
1968 ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg)
1969 {
1970         ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg;
1971         char propstr[ZFS_MAXPROPLEN];
1972         char findprop_plus_slash[ZFS_MAXPROPLEN];
1973         char *justsnap;
1974         int err = 0;
1975 
1976         if (snapdata_p->nzs_snapname[0] != '\0') {
1977                 NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s",
1978                     (char *)zfs_get_name(zhp));
1979                 goto _done;
1980         }
1981 
1982         err = ndmpd_zfs_snapshot_prop_get(zhp, propstr);
1983 
1984         if (err) {
1985                 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed");
1986                 goto _done;
1987         }
1988 
1989         if (propstr[0] == '\0') {
1990                 NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set",
1991                     (char *)zfs_get_name(zhp));
1992                 goto _done;
1993         }
1994 
1995         (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
1996             snapdata_p->nzs_findprop);
1997 
1998         if (!strstr((const char *)propstr,
1999             (const char *)findprop_plus_slash)) {
2000                 NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)",
2001                     (char *)zfs_get_name(zhp), propstr,
2002                     snapdata_p->nzs_findprop);
2003                 goto _done;
2004         }
2005 
2006         if (!ndmpd_zfs_prop_version_check(propstr,
2007             &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) {
2008                 NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)",
2009                     (char *)zfs_get_name(zhp),  propstr,
2010                     snapdata_p->nzs_findprop);
2011                 NDMP_LOG(LOG_DEBUG, "did not pass version check");
2012                 goto _done;
2013         }
2014 
2015         justsnap = strchr(zfs_get_name(zhp), '@') + 1;
2016 
2017         if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) {
2018                 (void) strlcpy(snapdata_p->nzs_snapname, justsnap,
2019                     ZFS_MAX_DATASET_NAME_LEN);
2020 
2021                 (void) strlcpy(snapdata_p->nzs_snapprop, propstr,
2022                     ZFS_MAXPROPLEN);
2023 
2024                 NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n",
2025                     snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop);
2026         }
2027 
2028 _done:
2029         zfs_close(zhp);
2030         return (err);
2031 }
2032 
2033 /*
2034  * ndmpd_zfs_snapshot_prop_get()
2035  *
2036  * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot
2037  */
2038 
2039 static int
2040 ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr)
2041 {
2042         nvlist_t *userprop;
2043         nvlist_t *propval;
2044         char *strval;
2045         int err;
2046 
2047         propstr[0] = '\0';
2048 
2049         userprop = zfs_get_user_props(zhp);
2050 
2051         if (userprop == NULL)
2052                 return (0);
2053 
2054         err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval);
2055 
2056         if (err != 0) {
2057                 if (err == ENOENT)
2058                         return (0);
2059 
2060                 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err);
2061 
2062                 return (-1);
2063         }
2064 
2065         err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval);
2066 
2067         if (err != 0) {
2068                 if (err == ENOENT)
2069                         return (0);
2070 
2071                 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err);
2072 
2073                 return (-1);
2074         }
2075 
2076         (void) strlcpy(propstr, strval, ZFS_MAXPROPLEN);
2077 
2078         return (0);
2079 }
2080 
2081 /*
2082  * ndmpd_zfs_snapshot_prop_add()
2083  *
2084  * Update snapshot's NDMPD_ZFS_PROP_INCR property with
2085  * the current LEVEL, DMP_NAME, and ZFS_MODE values
2086  * (add property if it doesn't exist)
2087  */
2088 
2089 static int
2090 ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args)
2091 {
2092         char fullname[ZFS_MAX_DATASET_NAME_LEN];
2093         char propstr[ZFS_MAXPROPLEN];
2094         zfs_handle_t *zhp;
2095         boolean_t set;
2096         int err;
2097 
2098         (void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
2099             ndmpd_zfs_args->nz_dataset,
2100             ndmpd_zfs_args->nz_snapname);
2101 
2102         zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
2103 
2104         if (!zhp) {
2105                 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)");
2106                 return (-1);
2107         }
2108 
2109         bzero(propstr, ZFS_MAXPROPLEN);
2110 
2111         if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) {
2112                 NDMP_LOG(LOG_DEBUG, "error getting property");
2113                 zfs_close(zhp);
2114                 return (-1);
2115         }
2116 
2117         if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) {
2118                 zfs_close(zhp);
2119                 return (-1);
2120         }
2121 
2122         if (set) {
2123                 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr);
2124                 if (err) {
2125                         NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
2126                             err);
2127                         NDMP_LOG(LOG_ERR, "error setting property %s",
2128                             propstr);
2129                         zfs_close(zhp);
2130                         return (-1);
2131                 }
2132         }
2133 
2134         zfs_close(zhp);
2135 
2136         (void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN);
2137 
2138         return (0);
2139 }
2140 
2141 static int
2142 ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
2143     char *propstr, boolean_t *set)
2144 {
2145         char subprop[ZFS_MAXPROPLEN];
2146         char *p = propstr;
2147         int slash_count = 0;
2148 
2149         *set = B_TRUE;
2150 
2151         (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
2152             subprop, ZFS_MAXPROPLEN, B_FALSE);
2153 
2154         if (propstr[0] == '\0') {
2155                 (void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s",
2156                     NDMPD_ZFS_PROP_MAJOR_VERSION,
2157                     NDMPD_ZFS_PROP_MINOR_VERSION,
2158                     (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u',
2159                     subprop);
2160                 return (0);
2161         }
2162 
2163         if (strstr((const char *)propstr, (const char *)subprop)) {
2164                 NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists",
2165                     subprop);
2166                 *set = B_FALSE;
2167                 return (0);
2168         }
2169 
2170         while (*p) {
2171                 if (*(p++) == '/')
2172                         slash_count++;
2173         }
2174 
2175         if (slash_count >= NDMPD_ZFS_SUBPROP_MAX) {
2176                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2177                     "snapshot %s: user property %s limit of %d subprops "
2178                     "reached; cannot complete operation",
2179                     ndmpd_zfs_args->nz_snapname,
2180                     NDMPD_ZFS_PROP_INCR,
2181                     NDMPD_ZFS_SUBPROP_MAX);
2182                 return (-1);
2183         }
2184 
2185         assert((strlen(propstr) + strlen(subprop) + 2) < ZFS_MAXPROPLEN);
2186 
2187         (void) strlcat(propstr, "/", ZFS_MAXPROPLEN);
2188         (void) strlcat(propstr, subprop, ZFS_MAXPROPLEN);
2189 
2190         return (0);
2191 }
2192 
2193 static int
2194 ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args,
2195     char *subprop, int len, boolean_t prev_level)
2196 {
2197         return (snprintf(subprop, len, "%d.%s.%c",
2198             prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level,
2199             ndmpd_zfs_args->nz_dmp_name,
2200             ndmpd_zfs_args->nz_zfs_mode));
2201 }
2202 
2203 /*
2204  * ndmpd_zfs_snapshot_prop_remove()
2205  *
2206  * Remove specified substring from the snapshot's
2207  * NDMPD_ZFS_PROP_INCR property
2208  */
2209 
2210 static int
2211 ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args,
2212     ndmpd_zfs_snapfind_t *snapdata_p)
2213 {
2214         char findprop_plus_slash[ZFS_MAXPROPLEN];
2215         char fullname[ZFS_MAX_DATASET_NAME_LEN];
2216         char newprop[ZFS_MAXPROPLEN];
2217         char tmpstr[ZFS_MAXPROPLEN];
2218         zfs_handle_t *zhp;
2219         char *ptr;
2220         int err;
2221 
2222         (void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
2223             ndmpd_zfs_args->nz_dataset,
2224             snapdata_p->nzs_snapname);
2225 
2226         zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT);
2227 
2228         if (!zhp) {
2229                 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open");
2230                 return (-1);
2231         }
2232 
2233         bzero(newprop, ZFS_MAXPROPLEN);
2234 
2235         /*
2236          * If the substring to be removed is the only {L, D, Z}
2237          * in the property, remove the entire property
2238          */
2239 
2240         tmpstr[0] = '\0';
2241 
2242         (void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr);
2243 
2244         if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) {
2245 
2246                 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
2247 
2248                 zfs_close(zhp);
2249 
2250                 if (err) {
2251                         NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d",
2252                             err);
2253                         NDMP_LOG(LOG_ERR, "error setting property %s", newprop);
2254                         return (-1);
2255                 }
2256 
2257                 return (0);
2258         }
2259 
2260         (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s",
2261             snapdata_p->nzs_findprop);
2262 
2263         ptr = strstr((const char *)snapdata_p->nzs_snapprop,
2264             (const char *)findprop_plus_slash);
2265 
2266         if (ptr == NULL) {
2267                 /*
2268                  * This shouldn't happen.  Just return success.
2269                  */
2270                 zfs_close(zhp);
2271 
2272                 return (0);
2273         }
2274 
2275         /*
2276          * Remove "nzs_findprop" substring from property
2277          *
2278          * Example property:
2279          *      0.0.u/1.bob.p/0.jane.d
2280          *
2281          * Note that there will always be a prefix to the
2282          * strstr() result.  Hence the below code works for
2283          * all cases.
2284          */
2285 
2286         ptr--;
2287         (void) strncpy(newprop, snapdata_p->nzs_snapprop,
2288             (char *)ptr - snapdata_p->nzs_snapprop);
2289         ptr += strlen(snapdata_p->nzs_findprop) + 1;
2290         (void) strlcat(newprop, ptr, ZFS_MAXPROPLEN);
2291 
2292         err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop);
2293 
2294         zfs_close(zhp);
2295 
2296         if (err) {
2297                 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err);
2298                 NDMP_LOG(LOG_ERR, "error modifying property %s", newprop);
2299                 return (-1);
2300         }
2301 
2302         return (0);
2303 }
2304 
2305 static boolean_t
2306 ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor)
2307 {
2308         (void) sscanf(propstr, "%u.%u.%*c%*s", major, minor);
2309 
2310         if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) {
2311                 NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)",
2312                     *major, NDMPD_ZFS_PROP_MAJOR_VERSION);
2313                 return (B_FALSE);
2314         }
2315 
2316         if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) {
2317                 NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)",
2318                     *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
2319         }
2320 
2321         NDMP_LOG(LOG_DEBUG, "passed version check: "
2322             "supported prop major (%u <= %u); (snapprop minor: %u [%u])",
2323             *major, NDMPD_ZFS_PROP_MAJOR_VERSION,
2324             *minor, NDMPD_ZFS_PROP_MINOR_VERSION);
2325 
2326         return (B_TRUE);
2327 }
2328 
2329 static int
2330 ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args,
2331     char *snapname, int namelen)
2332 {
2333         char subprop[ZFS_MAXPROPLEN];
2334         struct timeval tp;
2335         int err = 0;
2336 
2337         (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args,
2338             subprop, ZFS_MAXPROPLEN, B_FALSE);
2339 
2340         (void) gettimeofday(&tp, NULL);
2341 
2342         err = snprintf(snapname, namelen,
2343             "ndmp.%s.%ld.%ld",
2344             subprop,
2345             tp.tv_sec,
2346             tp.tv_usec);
2347 
2348         if (err > namelen) {
2349                 NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d",
2350                     snapname, namelen);
2351                 return (-1);
2352         }
2353 
2354         return (0);
2355 }
2356 
2357 static void
2358 ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args)
2359 {
2360         switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) {
2361         case EZFS_EXISTS:
2362         case EZFS_BUSY:
2363         case EZFS_NOENT:
2364         case EZFS_INVALIDNAME:
2365         case EZFS_MOUNTFAILED:
2366         case EZFS_UMOUNTFAILED:
2367         case EZFS_NAMETOOLONG:
2368         case EZFS_BADRESTORE:
2369 
2370                 /* use existing error text */
2371 
2372                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2373                     "%s: %s: %s\n",
2374                     ndmpd_zfs_args->nz_dataset,
2375                     libzfs_error_action(ndmpd_zfs_args->nz_zlibh),
2376                     libzfs_error_description(ndmpd_zfs_args->nz_zlibh));
2377 
2378                 break;
2379 
2380         case EZFS_NOMEM:
2381                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2382                     "Unable to obtain memory for operation\n");
2383                 break;
2384 
2385         case EZFS_PROPSPACE:
2386                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2387                     "A bad ZFS quota or reservation was encountered.\n");
2388                 break;
2389 
2390         case EZFS_BADSTREAM:
2391                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2392                     "The backup stream is invalid.\n");
2393                 break;
2394 
2395         case EZFS_ZONED:
2396                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2397                     "An error related to the local zone occurred.\n");
2398                 break;
2399 
2400         case EZFS_NOSPC:
2401                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2402                     "No more space is available\n");
2403                 break;
2404 
2405         case EZFS_IO:
2406                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2407                     "An I/O error occurred.\n");
2408                 break;
2409 
2410         default:
2411                 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR,
2412                     "An internal ndmpd error occurred.  "
2413                     "Please contact support\n");
2414                 break;
2415         }
2416 }
2417 
2418 void
2419 ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type,
2420     char *format, ...)
2421 {
2422         static char buf[1024];
2423         va_list ap;
2424 
2425         va_start(ap, format);
2426 
2427         /*LINTED variable format specifier */
2428         (void) vsnprintf(buf, sizeof (buf), format, ap);
2429         va_end(ap);
2430 
2431         MOD_LOGV3(ndmpd_zfs_params, log_type, buf);
2432 
2433         if ((log_type) == NDMP_LOG_ERROR) {
2434                 NDMP_LOG(LOG_ERR, buf);
2435         } else {
2436                 NDMP_LOG(LOG_NOTICE, buf);
2437         }
2438 }