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