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