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 void *ndmpd_zfs_backup_send_read(void *); 78 static void *ndmpd_zfs_backup_tape_write(void *); 79 80 static int ndmpd_zfs_restore(ndmpd_zfs_args_t *); 81 static void *ndmpd_zfs_restore_tape_read(void *); 82 static void *ndmpd_zfs_restore_recv_write(void *); 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 void * 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 ((void *)(uintptr_t)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 void * 611 ndmpd_zfs_backup_send_read(void *ptr) 612 { 613 ndmpd_zfs_args_t *ndmpd_zfs_args = ptr; 614 ndmpd_session_t *session = (ndmpd_session_t *) 615 (ndmpd_zfs_params->mp_daemon_cookie); 616 sendflags_t flags = { 0 }; 617 char *fromsnap = NULL; 618 zfs_handle_t *zhp; 619 int err; 620 621 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, 622 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type); 623 624 if (!zhp) { 625 if (!session->ns_data.dd_abort) 626 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open"); 627 return ((void *)(uintptr_t)-1); 628 } 629 630 switch (ndmpd_zfs_args->nz_zfs_mode) { 631 case ('d'): 632 flags.props = B_TRUE; 633 break; 634 case ('r'): 635 flags.replicate = B_TRUE; 636 break; 637 case ('p'): 638 flags.doall = B_TRUE; 639 flags.replicate = B_TRUE; 640 break; 641 default: 642 NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c", 643 ndmpd_zfs_args->nz_zfs_mode); 644 zfs_close(zhp); 645 return ((void *)(uintptr_t)-1); 646 } 647 648 if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { 649 if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') { 650 NDMP_LOG(LOG_ERR, "no fromsnap"); 651 zfs_close(zhp); 652 return ((void *)(uintptr_t)-1); 653 } 654 fromsnap = ndmpd_zfs_args->nz_fromsnap; 655 } 656 657 err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, &flags, 658 ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL); 659 660 if (err && !session->ns_data.dd_abort) 661 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err); 662 663 zfs_close(zhp); 664 665 return ((void *)(uintptr_t)err); 666 } 667 668 /* 669 * ndmpd_zfs_backup_tape_write() 670 * 671 * The data begins on a mover record boundary (because 672 * the header is the size of a mover record--i.e. 673 * ndmpd_zfs_args->nz_bufsize). 674 */ 675 676 static void * 677 ndmpd_zfs_backup_tape_write(void *ptr) 678 { 679 ndmpd_zfs_args_t *ndmpd_zfs_args = ptr; 680 ndmpd_session_t *session = (ndmpd_session_t *) 681 (ndmpd_zfs_params->mp_daemon_cookie); 682 int bufsize = ndmpd_zfs_args->nz_bufsize; 683 u_longlong_t *bytes_totalp; 684 int count; 685 char *buf; 686 687 buf = ndmp_malloc(bufsize); 688 if (buf == NULL) { 689 NDMP_LOG(LOG_DEBUG, "buf NULL"); 690 return ((void *)(uintptr_t)-1); 691 } 692 693 bytes_totalp = 694 &(session->ns_data.dd_module.dm_stats.ms_bytes_processed); 695 696 for (;;) { 697 bzero(buf, bufsize); 698 699 count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf, 700 bufsize); 701 702 if (count == 0) /* EOF */ { 703 NDMP_LOG(LOG_DEBUG, 704 "zfs_send stream size: %llu bytes; " 705 "full backup size (including header): %llu", 706 *bytes_totalp - bufsize, *bytes_totalp); 707 free(buf); 708 709 return ((void *)(uintptr_t) 710 ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args, 711 *bytes_totalp)); 712 } 713 714 if (count == -1) { 715 NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)", 716 errno); 717 free(buf); 718 return ((void *)(uintptr_t)-1); 719 } 720 NS_ADD(rdisk, count); 721 722 if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) { 723 (void) ndmpd_zfs_abort((void *) ndmpd_zfs_args); 724 NDMP_LOG(LOG_ERR, "MOD_WRITE error"); 725 free(buf); 726 return ((void *)(uintptr_t)-1); 727 } 728 729 *bytes_totalp += count; 730 } 731 /* NOTREACHED */ 732 } 733 734 static int 735 ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args, 736 u_longlong_t bytes_total) 737 { 738 char zfs_backup_size[32]; 739 int err; 740 741 (void) snprintf(zfs_backup_size, sizeof (zfs_backup_size), "%llu", 742 bytes_total); 743 744 err = MOD_ADDENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE", zfs_backup_size); 745 746 if (err) { 747 NDMP_LOG(LOG_ERR, "Failed to add ZFS_BACKUP_SIZE env"); 748 return (-1); 749 } 750 751 NDMP_LOG(LOG_DEBUG, "Added ZFS_BACKUP_SIZE env: %s", zfs_backup_size); 752 753 return (0); 754 } 755 756 void * 757 ndmpd_zfs_restore_starter(void *arg) 758 { 759 ndmpd_zfs_args_t *ndmpd_zfs_args = arg; 760 ndmpd_session_t *session = (ndmpd_session_t *) 761 (ndmpd_zfs_params->mp_daemon_cookie); 762 int err; 763 764 ndmp_session_ref(session); 765 766 err = ndmpd_zfs_restore(ndmpd_zfs_args); 767 768 MOD_DONE(ndmpd_zfs_params, err); 769 770 NS_DEC(nrs); 771 772 ndmp_session_unref(session); 773 774 ndmpd_zfs_fini(ndmpd_zfs_args); 775 776 return ((void *)(uintptr_t)err); 777 } 778 779 static int 780 ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) 781 { 782 ndmpd_session_t *session = (ndmpd_session_t *) 783 (ndmpd_zfs_params->mp_daemon_cookie); 784 int *read_err = NULL; 785 int *write_err = NULL; 786 int result = 0; 787 int err; 788 789 if (!session->ns_data.dd_abort) { 790 if (ndmpd_zfs_header_read(ndmpd_zfs_args)) { 791 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 792 "ndmpd_zfs header read error\n"); 793 return (-1); 794 } 795 796 err = ndmpd_zfs_reader_writer(ndmpd_zfs_args, 797 &write_err, &read_err); 798 799 if (err || read_err || write_err || session->ns_eof) 800 result = EIO; 801 } 802 803 if (session->ns_data.dd_abort) { 804 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.", 805 ndmpd_zfs_args->nz_dataset); 806 ndmpd_audit_restore(session->ns_connection, 807 ndmpd_zfs_args->nz_dataset, 808 session->ns_data.dd_data_addr.addr_type, 809 ndmpd_zfs_args->nz_dataset, EINTR); 810 (void) ndmpd_zfs_post_restore(ndmpd_zfs_args); 811 err = -1; 812 } else { 813 ndmpd_audit_restore(session->ns_connection, 814 ndmpd_zfs_args->nz_dataset, 815 session->ns_data.dd_data_addr.addr_type, 816 ndmpd_zfs_args->nz_dataset, result); 817 err = ndmpd_zfs_post_restore(ndmpd_zfs_args); 818 if (err || result) 819 err = -1; 820 821 if (err == 0) { 822 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished", 823 ndmpd_zfs_args->nz_dataset); 824 } else { 825 NDMP_LOG(LOG_DEBUG, "An error occurred while restoring" 826 " to \"%s\"", ndmpd_zfs_args->nz_dataset); 827 } 828 } 829 830 return (err); 831 } 832 833 static void * 834 ndmpd_zfs_restore_tape_read(void *ptr) 835 { 836 ndmpd_zfs_args_t *ndmpd_zfs_args = ptr; 837 ndmpd_session_t *session = (ndmpd_session_t *) 838 (ndmpd_zfs_params->mp_daemon_cookie); 839 int bufsize = ndmpd_zfs_args->nz_bufsize; 840 u_longlong_t backup_size = ndmpd_zfs_args->nz_zfs_backup_size; 841 u_longlong_t *bytes_totalp; 842 u_longlong_t bytes; 843 char *buf; 844 int count; 845 int err; 846 847 buf = ndmp_malloc(bufsize); 848 if (buf == NULL) { 849 NDMP_LOG(LOG_DEBUG, "buf NULL"); 850 return ((void *)(uintptr_t)-1); 851 } 852 853 bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total; 854 855 while (*bytes_totalp < backup_size) { 856 857 bytes = backup_size - *bytes_totalp; 858 859 if (bytes >= bufsize) 860 bytes = bufsize; 861 862 err = MOD_READ(ndmpd_zfs_params, buf, bytes); 863 864 if (err != 0) { 865 NDMP_LOG(LOG_ERR, "MOD_READ error: %d; returning -1", 866 err); 867 free(buf); 868 return ((void *)(uintptr_t)-1); 869 } 870 871 count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf, 872 bytes); 873 874 if (count != bytes) { 875 NDMP_LOG(LOG_ERR, "count (%d) != bytes (%d)", 876 count, bytes); 877 878 if (count == -1) { 879 NDMP_LOG(LOG_ERR, "pipe write error: errno: %d", 880 errno); 881 882 if (session->ns_data.dd_abort) 883 NDMP_LOG(LOG_DEBUG, "abort set"); 884 } 885 886 free(buf); 887 return ((void *)(uintptr_t)-1); 888 } 889 890 NS_ADD(wdisk, count); 891 892 *bytes_totalp += count; 893 } 894 895 free(buf); 896 return (NULL); 897 } 898 899 /* 900 * ndmpd_zfs_restore_recv_write() 901 * 902 * This routine executes zfs_receive() to restore the backup. 903 */ 904 905 static void * 906 ndmpd_zfs_restore_recv_write(void *ptr) 907 { 908 ndmpd_zfs_args_t *ndmpd_zfs_args = ptr; 909 ndmpd_session_t *session = (ndmpd_session_t *) 910 (ndmpd_zfs_params->mp_daemon_cookie); 911 recvflags_t flags; 912 int err; 913 914 bzero(&flags, sizeof (recvflags_t)); 915 916 flags.nomount = B_TRUE; 917 918 NDMP_LOG(LOG_DEBUG, "nz_zfs_force: %d\n", ndmpd_zfs_args->nz_zfs_force); 919 920 if (ndmpd_zfs_args->nz_zfs_force) 921 flags.force = B_TRUE; 922 923 err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset, 924 NULL, &flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL); 925 926 if (err && !session->ns_data.dd_abort) 927 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err); 928 929 return ((void *)(uintptr_t)err); 930 } 931 932 /* 933 * ndmpd_zfs_reader_writer() 934 * 935 * Two separate threads are used for actual backup or restore. 936 */ 937 938 static int 939 ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args, 940 int **sendrecv_errp, int **tape_errp) 941 { 942 funct_t sendrecv_func; 943 funct_t tape_func; 944 int sendrecv_err; 945 int tape_err; 946 947 switch (ndmpd_zfs_params->mp_operation) { 948 case NDMP_DATA_OP_BACKUP: 949 sendrecv_func = ndmpd_zfs_backup_send_read; 950 tape_func = ndmpd_zfs_backup_tape_write; 951 break; 952 case NDMP_DATA_OP_RECOVER: 953 sendrecv_func = ndmpd_zfs_restore_recv_write; 954 tape_func = ndmpd_zfs_restore_tape_read; 955 break; 956 } 957 958 sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread, 959 NULL, sendrecv_func, ndmpd_zfs_args); 960 961 if (sendrecv_err == 0) { 962 tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread, 963 NULL, tape_func, ndmpd_zfs_args); 964 965 if (tape_err) { 966 /* 967 * The close of the tape side of the pipe will cause 968 * nz_sendrecv_thread to error in the zfs_send/recv() 969 * call and to return. Hence we do not need 970 * to explicitly cancel the sendrecv_thread here 971 * (the pthread_join() below is sufficient). 972 */ 973 974 (void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]); 975 NDMP_LOG(LOG_ERR, "Could not start tape thread; " 976 "aborting z-op"); 977 } 978 979 (void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread, 980 (void **) sendrecv_errp); 981 } 982 983 if ((tape_err == 0) && 984 (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER)) 985 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE); 986 987 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS); 988 989 if ((sendrecv_err == 0) && (tape_err == 0)) { 990 (void) pthread_join(ndmpd_zfs_args->nz_tape_thread, 991 (void **) tape_errp); 992 } 993 994 if ((tape_err == 0) && 995 (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)) 996 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE); 997 998 return (sendrecv_err ? sendrecv_err : tape_err); 999 } 1000 1001 int 1002 ndmpd_zfs_abort(void *arg) 1003 { 1004 ndmpd_zfs_args_t *ndmpd_zfs_args = arg; 1005 char str[8]; 1006 1007 if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) 1008 (void) strlcpy(str, "backup", 8); 1009 else 1010 (void) strlcpy(str, "recover", 8); 1011 1012 NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation", 1013 str); 1014 1015 ndmpd_zfs_close_fds(ndmpd_zfs_args); 1016 1017 return (0); 1018 } 1019 1020 /* 1021 * ndmpd_zfs_pre_backup() 1022 * 1023 * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL. 1024 * This ensures that ndmp_include_zfs() will fail, which is 1025 * a requirement for "zfs"-type backup. 1026 */ 1027 1028 int 1029 ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args) 1030 { 1031 ndmpd_session_t *session = (ndmpd_session_t *) 1032 (ndmpd_zfs_params->mp_daemon_cookie); 1033 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1034 int err; 1035 1036 if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL) 1037 return (0); 1038 1039 (void) memset(nctxp, 0, sizeof (ndmp_context_t)); 1040 nctxp->nc_plversion = ndmp_pl->np_plversion; 1041 nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH); 1042 nctxp->nc_ddata = (void *) session; 1043 nctxp->nc_params = ndmpd_zfs_params; 1044 1045 err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp, 1046 ndmpd_zfs_args->nz_dataset); 1047 1048 if (err != 0) { 1049 NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m"); 1050 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args); 1051 } 1052 1053 return (err); 1054 } 1055 1056 int 1057 ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args) 1058 { 1059 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1060 int err = 0; 1061 1062 if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL) 1063 return (0); 1064 1065 err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err); 1066 1067 if (err == -1) 1068 NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m"); 1069 1070 return (err); 1071 } 1072 1073 int 1074 ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) 1075 { 1076 ndmpd_session_t *session = (ndmpd_session_t *) 1077 (ndmpd_zfs_params->mp_daemon_cookie); 1078 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1079 char bkpath[ZFS_MAX_DATASET_NAME_LEN]; 1080 int err; 1081 1082 if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL) 1083 return (0); 1084 1085 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath, 1086 ZFS_MAX_DATASET_NAME_LEN); 1087 1088 if (err != 0) { 1089 NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err); 1090 return (-1); 1091 } 1092 1093 err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args); 1094 1095 if (err != 0) { 1096 NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err); 1097 return (-1); 1098 } 1099 1100 (void) memset(nctxp, 0, sizeof (ndmp_context_t)); 1101 nctxp->nc_ddata = (void *) session; 1102 nctxp->nc_params = ndmpd_zfs_params; 1103 1104 err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath, 1105 ndmpd_zfs_args->nz_dataset); 1106 1107 if (err != 0) { 1108 NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m"); 1109 return (-1); 1110 } 1111 1112 return (0); 1113 } 1114 1115 int 1116 ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) 1117 { 1118 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1119 int err = 0; 1120 1121 if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL) 1122 return (0); 1123 1124 err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err); 1125 1126 if (err == -1) 1127 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m"); 1128 1129 return (err); 1130 } 1131 1132 boolean_t 1133 ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1134 { 1135 ndmpd_zfs_snapfind_t snapdata; 1136 1137 if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0) 1138 return (B_FALSE); 1139 1140 if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args)) 1141 return (B_FALSE); 1142 1143 if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { 1144 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, 1145 snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE); 1146 1147 snapdata.nzs_snapname[0] = '\0'; 1148 snapdata.nzs_snapprop[0] = '\0'; 1149 1150 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) 1151 return (B_FALSE); 1152 1153 if (snapdata.nzs_snapname[0] == '\0') { /* not found */ 1154 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1155 "Snapshot for level %d does not exist\n", 1156 ndmpd_zfs_args->nz_level-1); 1157 return (B_FALSE); 1158 } 1159 1160 (void) strlcpy(ndmpd_zfs_args->nz_fromsnap, 1161 snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN); 1162 } 1163 1164 return (B_TRUE); 1165 } 1166 1167 /* 1168 * ndmpd_zfs_backup_pathvalid() 1169 * 1170 * Make sure the path is of an existing dataset 1171 */ 1172 1173 static boolean_t 1174 ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1175 { 1176 char zpath[ZFS_MAX_DATASET_NAME_LEN]; 1177 char propstr[ZFS_MAXPROPLEN]; 1178 zfs_handle_t *zhp; 1179 zfs_type_t ztype = 0; 1180 int err; 1181 1182 if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, 1183 ZFS_MAX_DATASET_NAME_LEN) != 0) 1184 return (B_FALSE); 1185 1186 if (ndmpd_zfs_args->nz_snapname[0] != '\0') { 1187 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath, 1188 ZFS_TYPE_SNAPSHOT); 1189 1190 if (!zhp) { 1191 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, 1192 "zfs_open (snap)"); 1193 ndmpd_zfs_args->nz_snapname[0] = '\0'; 1194 ndmpd_zfs_args->nz_dataset[0] = '\0'; 1195 return (B_FALSE); 1196 } 1197 1198 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr); 1199 1200 zfs_close(zhp); 1201 1202 if (err) { 1203 NDMP_LOG(LOG_DEBUG, 1204 "ndmpd_zfs_snapshot_prop_get failed"); 1205 return (-1); 1206 } 1207 1208 if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) { 1209 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1210 "cannot use an ndmpd-generated snapshot\n"); 1211 return (B_FALSE); 1212 } 1213 } 1214 1215 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, 1216 ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET); 1217 1218 if (zhp) { 1219 ztype = zfs_get_type(zhp); 1220 zfs_close(zhp); 1221 } 1222 1223 if ((ztype == ZFS_TYPE_VOLUME) || 1224 (ztype == ZFS_TYPE_FILESYSTEM)) { 1225 ndmpd_zfs_args->nz_type = ztype; 1226 return (B_TRUE); 1227 } 1228 1229 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1230 "Invalid file system or volume.\n"); 1231 1232 return (B_FALSE); 1233 } 1234 1235 /* 1236 * ndmpd_zfs_backup_getpath() 1237 * 1238 * Retrieve the backup path from the environment, which should 1239 * be of the form "/dataset[@snap]". The leading slash is required 1240 * by certain DMA's but can otherwise be ignored. 1241 * 1242 * (Note: "dataset" can consist of more than one component, 1243 * e.g. "pool", "pool/volume", "pool/fs/fs2".) 1244 * 1245 * The dataset name and the snapshot name (if any) will be 1246 * stored in ndmpd_zfs_args. 1247 */ 1248 1249 static int 1250 ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath, 1251 int zlen) 1252 { 1253 char *env_path; 1254 char *at; 1255 1256 env_path = get_backup_path_v3(ndmpd_zfs_params); 1257 if (env_path == NULL) 1258 return (-1); 1259 1260 if (env_path[0] != '/') { 1261 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1262 "Invalid path: %s (leading slash required)\n", env_path); 1263 return (-1); 1264 } 1265 1266 (void) strlcpy(zpath, &env_path[1], zlen); 1267 (void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1], 1268 ZFS_MAX_DATASET_NAME_LEN); 1269 1270 at = strchr(ndmpd_zfs_args->nz_dataset, '@'); 1271 if (at) { 1272 *at = '\0'; 1273 (void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at, 1274 ZFS_MAX_DATASET_NAME_LEN); 1275 } else { 1276 ndmpd_zfs_args->nz_snapname[0] = '\0'; 1277 } 1278 1279 (void) trim_whitespace(ndmpd_zfs_args->nz_dataset); 1280 1281 return (0); 1282 } 1283 1284 static int 1285 ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) 1286 { 1287 return (ndmpd_zfs_getenv(ndmpd_zfs_args)); 1288 } 1289 1290 boolean_t 1291 ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1292 { 1293 if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0) 1294 return (B_FALSE); 1295 1296 if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args)) 1297 return (B_FALSE); 1298 1299 return (B_TRUE); 1300 } 1301 1302 static boolean_t 1303 ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1304 { 1305 zfs_handle_t *zhp; 1306 char *at; 1307 1308 if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0) 1309 return (B_FALSE); 1310 1311 at = strchr(ndmpd_zfs_args->nz_dataset, '@'); 1312 1313 if (at) { 1314 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING, 1315 "%s ignored in restore path\n", at); 1316 *at = '\0'; 1317 } 1318 1319 ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM; 1320 1321 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, 1322 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type); 1323 1324 if (zhp) { 1325 zfs_close(zhp); 1326 1327 if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { 1328 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1329 "Restore dataset exists.\n" 1330 "A nonexistent dataset must be specified " 1331 "for 'zfs' non-incremental restore.\n"); 1332 return (B_FALSE); 1333 } 1334 } 1335 1336 NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset); 1337 1338 return (B_TRUE); 1339 } 1340 1341 /* 1342 * ndmpd_zfs_restore_getpath() 1343 * 1344 * Be sure to not include the leading slash, which is required for 1345 * compatibility with backup applications (NBU) but which is not part 1346 * of the ZFS syntax. (Note that this done explicitly in all paths 1347 * below except those calling ndmpd_zfs_backup_getpath(), because it is 1348 * already stripped in that function.) 1349 * 1350 * In addition, the DMA might add a trailing slash to the path. 1351 * Strip all such slashes. 1352 */ 1353 1354 static int 1355 ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args) 1356 { 1357 int version = ndmpd_zfs_params->mp_protocol_version; 1358 char zpath[ZFS_MAX_DATASET_NAME_LEN]; 1359 mem_ndmp_name_v3_t *namep_v3; 1360 char *dataset = ndmpd_zfs_args->nz_dataset; 1361 char *nm; 1362 char *p; 1363 int len; 1364 int err; 1365 1366 namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0); 1367 1368 if (namep_v3 == NULL) { 1369 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]"); 1370 return (-1); 1371 } 1372 1373 if (namep_v3->nm3_dpath) { 1374 if (namep_v3->nm3_dpath[0] != '/') { 1375 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1376 "Invalid path: %s (leading slash required)\n", 1377 namep_v3->nm3_dpath); 1378 return (-1); 1379 } 1380 1381 (void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]), 1382 ZFS_MAX_DATASET_NAME_LEN); 1383 1384 if (namep_v3->nm3_newnm) { 1385 (void) strlcat(dataset, "/", ZFS_MAX_DATASET_NAME_LEN); 1386 (void) strlcat(dataset, namep_v3->nm3_newnm, 1387 ZFS_MAX_DATASET_NAME_LEN); 1388 1389 } else { 1390 if (version == NDMPV3) { 1391 /* 1392 * The following does not apply for V4. 1393 * 1394 * Find the last component of nm3_opath. 1395 * nm3_opath has no trailing '/'. 1396 */ 1397 p = strrchr(namep_v3->nm3_opath, '/'); 1398 nm = p? p : namep_v3->nm3_opath; 1399 (void) strlcat(dataset, "/", 1400 ZFS_MAX_DATASET_NAME_LEN); 1401 (void) strlcat(dataset, nm, 1402 ZFS_MAX_DATASET_NAME_LEN); 1403 } 1404 } 1405 } else { 1406 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, 1407 ZFS_MAX_DATASET_NAME_LEN); 1408 if (err) 1409 return (err); 1410 } 1411 1412 len = strlen(dataset); 1413 while (dataset[len-1] == '/') { 1414 dataset[len-1] = '\0'; 1415 len--; 1416 } 1417 1418 return (0); 1419 } 1420 1421 static int 1422 ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) 1423 { 1424 if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args) != 0) 1425 return (-1); 1426 1427 return (ndmpd_zfs_getenv(ndmpd_zfs_args)); 1428 } 1429 1430 static int 1431 ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) 1432 { 1433 1434 if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0) 1435 return (-1); 1436 1437 if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0) 1438 return (-1); 1439 1440 if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0) 1441 return (-1); 1442 1443 if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0) 1444 return (-1); 1445 1446 if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0) 1447 return (-1); 1448 1449 return (0); 1450 } 1451 1452 static int 1453 ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args) 1454 { 1455 char *envp; 1456 1457 envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE"); 1458 1459 if (envp == NULL) { 1460 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, " 1461 "defaulting to recursive"); 1462 ndmpd_zfs_args->nz_zfs_mode = 'r'; 1463 return (0); 1464 } 1465 1466 if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) { 1467 ndmpd_zfs_args->nz_zfs_mode = 'd'; 1468 } else if ((strcmp(envp, "recursive") == 0) || 1469 (strcmp(envp, "r") == 0)) { 1470 ndmpd_zfs_args->nz_zfs_mode = 'r'; 1471 } else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) { 1472 ndmpd_zfs_args->nz_zfs_mode = 'p'; 1473 } else { 1474 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1475 "Invalid ZFS_MODE value \"%s\".\n", envp); 1476 return (-1); 1477 } 1478 1479 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"", 1480 ndmpd_zfs_args->nz_zfs_mode); 1481 1482 return (0); 1483 } 1484 1485 /* 1486 * ndmpd_zfs_getenv_zfs_force() 1487 * 1488 * If SMF property zfs-force-override is set to "yes" or "no", this 1489 * value will override any value of NDMP environment variable ZFS_FORCE 1490 * as set by the DMA admin (or override the default of 'n', if ZFS_FORCE 1491 * is not set). By default, zfs-force-override is "off", which means it 1492 * will not override ZFS_FORCE. 1493 */ 1494 1495 static int 1496 ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args) 1497 { 1498 char *envp_force; 1499 char *override; 1500 1501 override = ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE); 1502 1503 if (strcasecmp(override, "yes") == 0) { 1504 ndmpd_zfs_args->nz_zfs_force = B_TRUE; 1505 NDMP_LOG(LOG_NOTICE, 1506 "SMF property zfs-force-override set to 'yes', " 1507 "overriding ZFS_FORCE"); 1508 return (0); 1509 } 1510 1511 if (strcasecmp(override, "no") == 0) { 1512 ndmpd_zfs_args->nz_zfs_force = B_FALSE; 1513 NDMP_LOG(LOG_NOTICE, 1514 "SMF property zfs-force-override set to 'no', " 1515 "overriding ZFS_FORCE"); 1516 return (0); 1517 } 1518 1519 if (strcasecmp(override, "off") != 0) { 1520 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1521 "SMF property zfs-force-override set to invalid value of " 1522 "'%s'; treating it as 'off'.", override); 1523 } 1524 1525 envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE"); 1526 1527 if (envp_force == NULL) { 1528 NDMP_LOG(LOG_DEBUG, 1529 "env(ZFS_FORCE) not specified, defaulting to FALSE"); 1530 ndmpd_zfs_args->nz_zfs_force = B_FALSE; 1531 return (0); 1532 } 1533 1534 /* 1535 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4). 1536 */ 1537 1538 if (strchr("tTyY", *envp_force)) 1539 ndmpd_zfs_args->nz_zfs_force = B_TRUE; 1540 1541 NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force); 1542 1543 return (0); 1544 } 1545 1546 static int 1547 ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args) 1548 { 1549 char *envp; 1550 1551 envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL"); 1552 1553 if (envp == NULL) { 1554 NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, " 1555 "defaulting to 0"); 1556 ndmpd_zfs_args->nz_level = 0; 1557 return (0); 1558 } 1559 1560 if (envp[1] != '\0') { 1561 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1562 "Invalid backup level \"%s\".\n", envp); 1563 return (-1); 1564 } 1565 1566 if (!isdigit(*envp)) { 1567 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1568 "Invalid backup level \"%s\".\n", envp); 1569 return (-1); 1570 } 1571 1572 ndmpd_zfs_args->nz_level = atoi(envp); 1573 1574 NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"", 1575 ndmpd_zfs_args->nz_level); 1576 1577 return (0); 1578 } 1579 1580 static int 1581 ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args) 1582 { 1583 char *envp_update; 1584 1585 envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE"); 1586 1587 if (envp_update == NULL) { 1588 NDMP_LOG(LOG_DEBUG, 1589 "env(UPDATE) not specified, defaulting to TRUE"); 1590 ndmpd_zfs_args->nz_update = B_TRUE; 1591 return (0); 1592 } 1593 1594 /* 1595 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4). 1596 */ 1597 1598 if (strchr("tTyY", *envp_update)) 1599 ndmpd_zfs_args->nz_update = B_TRUE; 1600 1601 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update); 1602 1603 return (0); 1604 } 1605 1606 static int 1607 ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args) 1608 { 1609 char *envp; 1610 1611 envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME"); 1612 1613 if (envp == NULL) { 1614 NDMP_LOG(LOG_DEBUG, 1615 "env(DMP_NAME) not specified, defaulting to 'level'"); 1616 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level", 1617 NDMPD_ZFS_DMP_NAME_MAX); 1618 return (0); 1619 } 1620 1621 if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp)) 1622 return (-1); 1623 1624 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp, 1625 NDMPD_ZFS_DMP_NAME_MAX); 1626 1627 NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp); 1628 1629 return (0); 1630 } 1631 1632 static int 1633 ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args) 1634 { 1635 char *zfs_backup_size; 1636 1637 zfs_backup_size = MOD_GETENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE"); 1638 1639 if (zfs_backup_size == NULL) { 1640 NDMP_LOG(LOG_ERR, "ZFS_BACKUP_SIZE env is NULL"); 1641 return (-1); 1642 } 1643 1644 NDMP_LOG(LOG_DEBUG, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size); 1645 1646 (void) sscanf(zfs_backup_size, "%llu", 1647 &ndmpd_zfs_args->nz_zfs_backup_size); 1648 1649 return (0); 1650 } 1651 1652 /* 1653 * ndmpd_zfs_dmp_name_valid() 1654 * 1655 * This function verifies that the dmp_name is valid. 1656 * 1657 * The dmp_name is restricted to alphanumeric characters plus 1658 * the underscore and hyphen, and must be 31 characters or less. 1659 * This is due to its use in the NDMPD_ZFS_PROP_INCR property 1660 * and in the ZFS snapshot name (if an ndmpd-generated snapshot 1661 * is required). 1662 */ 1663 1664 static boolean_t 1665 ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name) 1666 { 1667 char *c; 1668 1669 if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) { 1670 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1671 "DMP_NAME %s is longer than %d\n", 1672 dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1); 1673 return (B_FALSE); 1674 } 1675 1676 for (c = dmp_name; *c != '\0'; c++) { 1677 if (!isalpha(*c) && !isdigit(*c) && 1678 (*c != '_') && (*c != '-')) { 1679 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1680 "DMP_NAME %s contains illegal character %c\n", 1681 dmp_name, *c); 1682 return (B_FALSE); 1683 } 1684 } 1685 1686 NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name); 1687 return (B_TRUE); 1688 } 1689 1690 /* 1691 * ndmpd_zfs_is_incremental() 1692 * 1693 * This can only be called after ndmpd_zfs_getenv_level() 1694 * has been called. 1695 */ 1696 1697 static boolean_t 1698 ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args) 1699 { 1700 return (ndmpd_zfs_args->nz_level != 0); 1701 } 1702 1703 /* 1704 * ndmpd_zfs_snapshot_prepare() 1705 * 1706 * If no snapshot was supplied by the user, create a snapshot 1707 * for use by ndmpd. 1708 */ 1709 1710 static int 1711 ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args) 1712 { 1713 ndmpd_session_t *session = (ndmpd_session_t *) 1714 (ndmpd_zfs_params->mp_daemon_cookie); 1715 boolean_t recursive = B_FALSE; 1716 int zfs_err = 0; 1717 1718 if (session->ns_data.dd_abort) { 1719 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.", 1720 ndmpd_zfs_args->nz_dataset); 1721 return (-1); 1722 } 1723 1724 if (ndmpd_zfs_args->nz_snapname[0] == '\0') { 1725 ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE; 1726 1727 if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) { 1728 ndmpd_zfs_args->nz_snapname[0] = '\0'; 1729 1730 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1731 "Error creating snapshot for %s\n", 1732 ndmpd_zfs_args->nz_dataset); 1733 1734 return (-1); 1735 } 1736 } 1737 1738 if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) { 1739 NDMP_LOG(LOG_DEBUG, 1740 "ndmpd_zfs_snapshot_prop_add error\n"); 1741 1742 if (ndmpd_zfs_args->nz_ndmpd_snap) { 1743 1744 if (ndmpd_zfs_args->nz_zfs_mode != 'd') 1745 recursive = B_TRUE; 1746 1747 (void) snapshot_destroy(ndmpd_zfs_args->nz_dataset, 1748 ndmpd_zfs_args->nz_snapname, recursive, B_FALSE, 1749 &zfs_err); 1750 } 1751 1752 return (-1); 1753 } 1754 1755 return (0); 1756 } 1757 1758 /* 1759 * ndmpd_zfs_snapshot_cleanup() 1760 * 1761 * If UPDATE = y, find the old snapshot (if any) corresponding to 1762 * {LEVEL, DMP_NAME, ZFS_MODE}. If it was ndmpd-generated, 1763 * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR 1764 * property to remove {L, D, Z}. 1765 * 1766 * If UPDATE = n, if an ndmpd-generated snapshot was used for backup, 1767 * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR 1768 * property to remove {L, D, Z}. 1769 */ 1770 1771 static int 1772 ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err) 1773 { 1774 ndmpd_session_t *session = (ndmpd_session_t *) 1775 (ndmpd_zfs_params->mp_daemon_cookie); 1776 ndmpd_zfs_snapfind_t snapdata; 1777 boolean_t ndmpd_generated = B_FALSE; 1778 1779 bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t)); 1780 1781 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, 1782 snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE); 1783 1784 if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) { 1785 /* 1786 * Find the existing snapshot, if any, to "unuse." 1787 * Indicate that the current snapshot used for backup 1788 * should be skipped in the search. (The search is 1789 * sorted by creation time but this cannot be relied 1790 * upon for user-supplied snapshots.) 1791 */ 1792 1793 (void) snprintf(snapdata.nzs_snapskip, ZFS_MAX_DATASET_NAME_LEN, 1794 "%s", ndmpd_zfs_args->nz_snapname); 1795 1796 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) { 1797 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n"); 1798 goto _remove_tmp_snap; 1799 } 1800 1801 if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */ 1802 ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated 1803 (snapdata.nzs_snapprop); 1804 1805 if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args, 1806 ndmpd_generated, &snapdata) != 0) { 1807 NDMP_LOG(LOG_DEBUG, 1808 "ndmpd_zfs_snapshot_unuse error\n"); 1809 goto _remove_tmp_snap; 1810 } 1811 } 1812 1813 if (session->ns_data.dd_abort) 1814 goto _remove_tmp_snap; 1815 1816 return (0); 1817 } 1818 1819 _remove_tmp_snap: 1820 1821 (void) snprintf(snapdata.nzs_snapname, ZFS_MAX_DATASET_NAME_LEN, "%s", 1822 ndmpd_zfs_args->nz_snapname); 1823 1824 (void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop, 1825 ZFS_MAXPROPLEN); 1826 1827 snapdata.nzs_snapskip[0] = '\0'; 1828 1829 if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args, 1830 ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) { 1831 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n"); 1832 return (-1); 1833 } 1834 1835 if (!ndmpd_zfs_args->nz_update) 1836 return (0); 1837 1838 return (-1); 1839 } 1840 1841 static int 1842 ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args) 1843 { 1844 boolean_t recursive = B_FALSE; 1845 1846 if (ndmpd_zfs_snapname_create(ndmpd_zfs_args, 1847 ndmpd_zfs_args->nz_snapname, ZFS_MAX_DATASET_NAME_LEN - 1) < 0) { 1848 NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s", 1849 errno, ndmpd_zfs_args->nz_dataset); 1850 return (-1); 1851 } 1852 1853 if (ndmpd_zfs_args->nz_zfs_mode != 'd') 1854 recursive = B_TRUE; 1855 1856 if (snapshot_create(ndmpd_zfs_args->nz_dataset, 1857 ndmpd_zfs_args->nz_snapname, recursive, B_FALSE) != 0) { 1858 NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s", 1859 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname); 1860 return (-1); 1861 } 1862 1863 NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s", 1864 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname); 1865 1866 return (0); 1867 } 1868 1869 /* 1870 * ndmpd_zfs_snapshot_unuse() 1871 * 1872 * Given a pre-existing snapshot of the given {L, D, Z}: 1873 * If snapshot is ndmpd-generated, remove snapshot. 1874 * If not ndmpd-generated, or if the ndmpd-generated snapshot 1875 * cannot be destroyed, remove the {L, D, Z} substring from the 1876 * snapshot's NDMPD_ZFS_PROP_INCR property. 1877 * 1878 * In the event of a failure, it may be that two snapshots will 1879 * have the {L, D, Z} property set on them. This is not desirable, 1880 * so return an error and log the failure. 1881 */ 1882 1883 static int 1884 ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args, 1885 boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p) 1886 { 1887 boolean_t recursive = B_FALSE; 1888 int zfs_err = 0; 1889 int err = 0; 1890 1891 if (ndmpd_generated) { 1892 if (ndmpd_zfs_args->nz_zfs_mode != 'd') 1893 recursive = B_TRUE; 1894 1895 err = snapshot_destroy(ndmpd_zfs_args->nz_dataset, 1896 snapdata_p->nzs_snapname, recursive, B_FALSE, &zfs_err); 1897 1898 if (err) { 1899 NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;" 1900 " err: %d; zfs_err: %d", 1901 ndmpd_zfs_args->nz_dataset, 1902 snapdata_p->nzs_snapname, err, zfs_err); 1903 return (-1); 1904 } 1905 } 1906 1907 if (!ndmpd_generated || zfs_err) { 1908 if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p)) 1909 return (-1); 1910 } 1911 1912 return (0); 1913 } 1914 1915 static boolean_t 1916 ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop) 1917 { 1918 char origin; 1919 1920 (void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin); 1921 1922 return (origin == 'n'); 1923 } 1924 1925 /* 1926 * ndmpd_zfs_snapshot_find() 1927 * 1928 * Find a snapshot with a particular value for 1929 * the NDMPD_ZFS_PROP_INCR property. 1930 */ 1931 1932 static int 1933 ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args, 1934 ndmpd_zfs_snapfind_t *snapdata) 1935 { 1936 zfs_handle_t *zhp; 1937 int err; 1938 1939 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset, 1940 ndmpd_zfs_args->nz_type); 1941 1942 if (!zhp) { 1943 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open"); 1944 return (-1); 1945 } 1946 1947 err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find, 1948 snapdata); 1949 1950 zfs_close(zhp); 1951 1952 if (err) { 1953 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d", 1954 err); 1955 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1956 "Error iterating snapshots\n"); 1957 return (-1); 1958 } 1959 1960 return (0); 1961 } 1962 1963 /* 1964 * ndmpd_zfs_snapshot_prop_find() 1965 * 1966 * Find a snapshot with a particular value for 1967 * NDMPD_ZFS_PROP_INCR. Fill in data for the first one 1968 * found (sorted by creation time). However, skip the 1969 * the snapshot indicated in nzs_snapskip, if any. 1970 */ 1971 1972 static int 1973 ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg) 1974 { 1975 ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg; 1976 char propstr[ZFS_MAXPROPLEN]; 1977 char findprop_plus_slash[ZFS_MAXPROPLEN]; 1978 char *justsnap; 1979 int err = 0; 1980 1981 if (snapdata_p->nzs_snapname[0] != '\0') { 1982 NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s", 1983 (char *)zfs_get_name(zhp)); 1984 goto _done; 1985 } 1986 1987 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr); 1988 1989 if (err) { 1990 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed"); 1991 goto _done; 1992 } 1993 1994 if (propstr[0] == '\0') { 1995 NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set", 1996 (char *)zfs_get_name(zhp)); 1997 goto _done; 1998 } 1999 2000 (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s", 2001 snapdata_p->nzs_findprop); 2002 2003 if (!strstr((const char *)propstr, 2004 (const char *)findprop_plus_slash)) { 2005 NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)", 2006 (char *)zfs_get_name(zhp), propstr, 2007 snapdata_p->nzs_findprop); 2008 goto _done; 2009 } 2010 2011 if (!ndmpd_zfs_prop_version_check(propstr, 2012 &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) { 2013 NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)", 2014 (char *)zfs_get_name(zhp), propstr, 2015 snapdata_p->nzs_findprop); 2016 NDMP_LOG(LOG_DEBUG, "did not pass version check"); 2017 goto _done; 2018 } 2019 2020 justsnap = strchr(zfs_get_name(zhp), '@') + 1; 2021 2022 if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) { 2023 (void) strlcpy(snapdata_p->nzs_snapname, justsnap, 2024 ZFS_MAX_DATASET_NAME_LEN); 2025 2026 (void) strlcpy(snapdata_p->nzs_snapprop, propstr, 2027 ZFS_MAXPROPLEN); 2028 2029 NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n", 2030 snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop); 2031 } 2032 2033 _done: 2034 zfs_close(zhp); 2035 return (err); 2036 } 2037 2038 /* 2039 * ndmpd_zfs_snapshot_prop_get() 2040 * 2041 * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot 2042 */ 2043 2044 static int 2045 ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr) 2046 { 2047 nvlist_t *userprop; 2048 nvlist_t *propval; 2049 char *strval; 2050 int err; 2051 2052 propstr[0] = '\0'; 2053 2054 userprop = zfs_get_user_props(zhp); 2055 2056 if (userprop == NULL) 2057 return (0); 2058 2059 err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval); 2060 2061 if (err != 0) { 2062 if (err == ENOENT) 2063 return (0); 2064 2065 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err); 2066 2067 return (-1); 2068 } 2069 2070 err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval); 2071 2072 if (err != 0) { 2073 if (err == ENOENT) 2074 return (0); 2075 2076 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err); 2077 2078 return (-1); 2079 } 2080 2081 (void) strlcpy(propstr, strval, ZFS_MAXPROPLEN); 2082 2083 return (0); 2084 } 2085 2086 /* 2087 * ndmpd_zfs_snapshot_prop_add() 2088 * 2089 * Update snapshot's NDMPD_ZFS_PROP_INCR property with 2090 * the current LEVEL, DMP_NAME, and ZFS_MODE values 2091 * (add property if it doesn't exist) 2092 */ 2093 2094 static int 2095 ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args) 2096 { 2097 char fullname[ZFS_MAX_DATASET_NAME_LEN]; 2098 char propstr[ZFS_MAXPROPLEN]; 2099 zfs_handle_t *zhp; 2100 boolean_t set; 2101 int err; 2102 2103 (void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s", 2104 ndmpd_zfs_args->nz_dataset, 2105 ndmpd_zfs_args->nz_snapname); 2106 2107 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT); 2108 2109 if (!zhp) { 2110 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)"); 2111 return (-1); 2112 } 2113 2114 bzero(propstr, ZFS_MAXPROPLEN); 2115 2116 if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) { 2117 NDMP_LOG(LOG_DEBUG, "error getting property"); 2118 zfs_close(zhp); 2119 return (-1); 2120 } 2121 2122 if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) { 2123 zfs_close(zhp); 2124 return (-1); 2125 } 2126 2127 if (set) { 2128 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr); 2129 if (err) { 2130 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", 2131 err); 2132 NDMP_LOG(LOG_ERR, "error setting property %s", 2133 propstr); 2134 zfs_close(zhp); 2135 return (-1); 2136 } 2137 } 2138 2139 zfs_close(zhp); 2140 2141 (void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN); 2142 2143 return (0); 2144 } 2145 2146 static int 2147 ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args, 2148 char *propstr, boolean_t *set) 2149 { 2150 char subprop[ZFS_MAXPROPLEN]; 2151 char *p = propstr; 2152 int slash_count = 0; 2153 2154 *set = B_TRUE; 2155 2156 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, 2157 subprop, ZFS_MAXPROPLEN, B_FALSE); 2158 2159 if (propstr[0] == '\0') { 2160 (void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s", 2161 NDMPD_ZFS_PROP_MAJOR_VERSION, 2162 NDMPD_ZFS_PROP_MINOR_VERSION, 2163 (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u', 2164 subprop); 2165 return (0); 2166 } 2167 2168 if (strstr((const char *)propstr, (const char *)subprop)) { 2169 NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists", 2170 subprop); 2171 *set = B_FALSE; 2172 return (0); 2173 } 2174 2175 while (*p) { 2176 if (*(p++) == '/') 2177 slash_count++; 2178 } 2179 2180 if (slash_count >= NDMPD_ZFS_SUBPROP_MAX) { 2181 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2182 "snapshot %s: user property %s limit of %d subprops " 2183 "reached; cannot complete operation", 2184 ndmpd_zfs_args->nz_snapname, 2185 NDMPD_ZFS_PROP_INCR, 2186 NDMPD_ZFS_SUBPROP_MAX); 2187 return (-1); 2188 } 2189 2190 assert((strlen(propstr) + strlen(subprop) + 2) < ZFS_MAXPROPLEN); 2191 2192 (void) strlcat(propstr, "/", ZFS_MAXPROPLEN); 2193 (void) strlcat(propstr, subprop, ZFS_MAXPROPLEN); 2194 2195 return (0); 2196 } 2197 2198 static int 2199 ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args, 2200 char *subprop, int len, boolean_t prev_level) 2201 { 2202 return (snprintf(subprop, len, "%d.%s.%c", 2203 prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level, 2204 ndmpd_zfs_args->nz_dmp_name, 2205 ndmpd_zfs_args->nz_zfs_mode)); 2206 } 2207 2208 /* 2209 * ndmpd_zfs_snapshot_prop_remove() 2210 * 2211 * Remove specified substring from the snapshot's 2212 * NDMPD_ZFS_PROP_INCR property 2213 */ 2214 2215 static int 2216 ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args, 2217 ndmpd_zfs_snapfind_t *snapdata_p) 2218 { 2219 char findprop_plus_slash[ZFS_MAXPROPLEN]; 2220 char fullname[ZFS_MAX_DATASET_NAME_LEN]; 2221 char newprop[ZFS_MAXPROPLEN]; 2222 char tmpstr[ZFS_MAXPROPLEN]; 2223 zfs_handle_t *zhp; 2224 char *ptr; 2225 int err; 2226 2227 (void) snprintf(fullname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s", 2228 ndmpd_zfs_args->nz_dataset, 2229 snapdata_p->nzs_snapname); 2230 2231 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT); 2232 2233 if (!zhp) { 2234 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open"); 2235 return (-1); 2236 } 2237 2238 bzero(newprop, ZFS_MAXPROPLEN); 2239 2240 /* 2241 * If the substring to be removed is the only {L, D, Z} 2242 * in the property, remove the entire property 2243 */ 2244 2245 tmpstr[0] = '\0'; 2246 2247 (void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr); 2248 2249 if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) { 2250 2251 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop); 2252 2253 zfs_close(zhp); 2254 2255 if (err) { 2256 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", 2257 err); 2258 NDMP_LOG(LOG_ERR, "error setting property %s", newprop); 2259 return (-1); 2260 } 2261 2262 return (0); 2263 } 2264 2265 (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s", 2266 snapdata_p->nzs_findprop); 2267 2268 ptr = strstr((const char *)snapdata_p->nzs_snapprop, 2269 (const char *)findprop_plus_slash); 2270 2271 if (ptr == NULL) { 2272 /* 2273 * This shouldn't happen. Just return success. 2274 */ 2275 zfs_close(zhp); 2276 2277 return (0); 2278 } 2279 2280 /* 2281 * Remove "nzs_findprop" substring from property 2282 * 2283 * Example property: 2284 * 0.0.u/1.bob.p/0.jane.d 2285 * 2286 * Note that there will always be a prefix to the 2287 * strstr() result. Hence the below code works for 2288 * all cases. 2289 */ 2290 2291 ptr--; 2292 (void) strncpy(newprop, snapdata_p->nzs_snapprop, 2293 (char *)ptr - snapdata_p->nzs_snapprop); 2294 ptr += strlen(snapdata_p->nzs_findprop) + 1; 2295 (void) strlcat(newprop, ptr, ZFS_MAXPROPLEN); 2296 2297 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop); 2298 2299 zfs_close(zhp); 2300 2301 if (err) { 2302 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err); 2303 NDMP_LOG(LOG_ERR, "error modifying property %s", newprop); 2304 return (-1); 2305 } 2306 2307 return (0); 2308 } 2309 2310 static boolean_t 2311 ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor) 2312 { 2313 (void) sscanf(propstr, "%u.%u.%*c%*s", major, minor); 2314 2315 if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) { 2316 NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)", 2317 *major, NDMPD_ZFS_PROP_MAJOR_VERSION); 2318 return (B_FALSE); 2319 } 2320 2321 if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) { 2322 NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)", 2323 *minor, NDMPD_ZFS_PROP_MINOR_VERSION); 2324 } 2325 2326 NDMP_LOG(LOG_DEBUG, "passed version check: " 2327 "supported prop major (%u <= %u); (snapprop minor: %u [%u])", 2328 *major, NDMPD_ZFS_PROP_MAJOR_VERSION, 2329 *minor, NDMPD_ZFS_PROP_MINOR_VERSION); 2330 2331 return (B_TRUE); 2332 } 2333 2334 static int 2335 ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args, 2336 char *snapname, int namelen) 2337 { 2338 char subprop[ZFS_MAXPROPLEN]; 2339 struct timeval tp; 2340 int err = 0; 2341 2342 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, 2343 subprop, ZFS_MAXPROPLEN, B_FALSE); 2344 2345 (void) gettimeofday(&tp, NULL); 2346 2347 err = snprintf(snapname, namelen, 2348 "ndmp.%s.%ld.%ld", 2349 subprop, 2350 tp.tv_sec, 2351 tp.tv_usec); 2352 2353 if (err > namelen) { 2354 NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d", 2355 snapname, namelen); 2356 return (-1); 2357 } 2358 2359 return (0); 2360 } 2361 2362 static void 2363 ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args) 2364 { 2365 switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) { 2366 case EZFS_EXISTS: 2367 case EZFS_BUSY: 2368 case EZFS_NOENT: 2369 case EZFS_INVALIDNAME: 2370 case EZFS_MOUNTFAILED: 2371 case EZFS_UMOUNTFAILED: 2372 case EZFS_NAMETOOLONG: 2373 case EZFS_BADRESTORE: 2374 2375 /* use existing error text */ 2376 2377 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2378 "%s: %s: %s\n", 2379 ndmpd_zfs_args->nz_dataset, 2380 libzfs_error_action(ndmpd_zfs_args->nz_zlibh), 2381 libzfs_error_description(ndmpd_zfs_args->nz_zlibh)); 2382 2383 break; 2384 2385 case EZFS_NOMEM: 2386 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2387 "Unable to obtain memory for operation\n"); 2388 break; 2389 2390 case EZFS_PROPSPACE: 2391 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2392 "A bad ZFS quota or reservation was encountered.\n"); 2393 break; 2394 2395 case EZFS_BADSTREAM: 2396 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2397 "The backup stream is invalid.\n"); 2398 break; 2399 2400 case EZFS_ZONED: 2401 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2402 "An error related to the local zone occurred.\n"); 2403 break; 2404 2405 case EZFS_NOSPC: 2406 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2407 "No more space is available\n"); 2408 break; 2409 2410 case EZFS_IO: 2411 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2412 "An I/O error occurred.\n"); 2413 break; 2414 2415 default: 2416 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2417 "An internal ndmpd error occurred. " 2418 "Please contact support\n"); 2419 break; 2420 } 2421 } 2422 2423 void 2424 ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type, 2425 char *format, ...) 2426 { 2427 static char buf[1024]; 2428 va_list ap; 2429 2430 va_start(ap, format); 2431 2432 /*LINTED variable format specifier */ 2433 (void) vsnprintf(buf, sizeof (buf), format, ap); 2434 va_end(ap); 2435 2436 MOD_LOGV3(ndmpd_zfs_params, log_type, buf); 2437 2438 if ((log_type) == NDMP_LOG_ERROR) { 2439 NDMP_LOG(LOG_ERR, buf); 2440 } else { 2441 NDMP_LOG(LOG_NOTICE, buf); 2442 } 2443 } 2444