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