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 nctxp->nc_params = ndmpd_zfs_params; 1038 1039 err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp, 1040 ndmpd_zfs_args->nz_dataset); 1041 1042 if (err != 0) { 1043 NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m"); 1044 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args); 1045 } 1046 1047 return (err); 1048 } 1049 1050 int 1051 ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args) 1052 { 1053 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1054 int err = 0; 1055 1056 if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL) 1057 return (0); 1058 1059 err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err); 1060 1061 if (err == -1) 1062 NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m"); 1063 1064 return (err); 1065 } 1066 1067 int 1068 ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) 1069 { 1070 ndmpd_session_t *session = (ndmpd_session_t *) 1071 (ndmpd_zfs_params->mp_daemon_cookie); 1072 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1073 char bkpath[ZFS_MAXNAMELEN]; 1074 int err; 1075 1076 if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL) 1077 return (0); 1078 1079 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath, ZFS_MAXNAMELEN); 1080 1081 if (err != 0) { 1082 NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err); 1083 return (-1); 1084 } 1085 1086 err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args); 1087 1088 if (err != 0) { 1089 NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err); 1090 return (-1); 1091 } 1092 1093 (void) memset(nctxp, 0, sizeof (ndmp_context_t)); 1094 nctxp->nc_ddata = (void *) session; 1095 nctxp->nc_params = ndmpd_zfs_params; 1096 1097 err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath, 1098 ndmpd_zfs_args->nz_dataset); 1099 1100 if (err != 0) { 1101 NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m"); 1102 return (-1); 1103 } 1104 1105 return (0); 1106 } 1107 1108 int 1109 ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) 1110 { 1111 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1112 int err = 0; 1113 1114 if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL) 1115 return (0); 1116 1117 err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err); 1118 1119 if (err == -1) 1120 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m"); 1121 1122 return (err); 1123 } 1124 1125 boolean_t 1126 ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1127 { 1128 ndmpd_zfs_snapfind_t snapdata; 1129 1130 if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0) 1131 return (B_FALSE); 1132 1133 if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args)) 1134 return (B_FALSE); 1135 1136 if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { 1137 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, 1138 snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE); 1139 1140 snapdata.nzs_snapname[0] = '\0'; 1141 snapdata.nzs_snapprop[0] = '\0'; 1142 1143 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) 1144 return (B_FALSE); 1145 1146 if (snapdata.nzs_snapname[0] == '\0') { /* not found */ 1147 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1148 "Snapshot for level %d does not exist\n", 1149 ndmpd_zfs_args->nz_level-1); 1150 return (B_FALSE); 1151 } 1152 1153 (void) strlcpy(ndmpd_zfs_args->nz_fromsnap, 1154 snapdata.nzs_snapname, ZFS_MAXNAMELEN); 1155 } 1156 1157 return (B_TRUE); 1158 } 1159 1160 /* 1161 * ndmpd_zfs_backup_pathvalid() 1162 * 1163 * Make sure the path is of an existing dataset 1164 */ 1165 1166 static boolean_t 1167 ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1168 { 1169 char zpath[ZFS_MAXNAMELEN]; 1170 char propstr[ZFS_MAXPROPLEN]; 1171 zfs_handle_t *zhp; 1172 zfs_type_t ztype = 0; 1173 int err; 1174 1175 if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, ZFS_MAXNAMELEN) 1176 != 0) 1177 return (B_FALSE); 1178 1179 if (ndmpd_zfs_args->nz_snapname[0] != '\0') { 1180 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath, 1181 ZFS_TYPE_SNAPSHOT); 1182 1183 if (!zhp) { 1184 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, 1185 "zfs_open (snap)"); 1186 ndmpd_zfs_args->nz_snapname[0] = '\0'; 1187 ndmpd_zfs_args->nz_dataset[0] = '\0'; 1188 return (B_FALSE); 1189 } 1190 1191 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr); 1192 1193 zfs_close(zhp); 1194 1195 if (err) { 1196 NDMP_LOG(LOG_DEBUG, 1197 "ndmpd_zfs_snapshot_prop_get failed"); 1198 return (-1); 1199 } 1200 1201 if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) { 1202 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1203 "cannot use an ndmpd-generated snapshot\n"); 1204 return (B_FALSE); 1205 } 1206 } 1207 1208 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, 1209 ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET); 1210 1211 if (zhp) { 1212 ztype = zfs_get_type(zhp); 1213 zfs_close(zhp); 1214 } 1215 1216 if ((ztype == ZFS_TYPE_VOLUME) || 1217 (ztype == ZFS_TYPE_FILESYSTEM)) { 1218 ndmpd_zfs_args->nz_type = ztype; 1219 return (B_TRUE); 1220 } 1221 1222 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1223 "Invalid file system or volume.\n"); 1224 1225 return (B_FALSE); 1226 } 1227 1228 /* 1229 * ndmpd_zfs_backup_getpath() 1230 * 1231 * Retrieve the backup path from the environment, which should 1232 * be of the form "/dataset[@snap]". The leading slash is required 1233 * by certain DMA's but can otherwise be ignored. 1234 * 1235 * (Note: "dataset" can consist of more than one component, 1236 * e.g. "pool", "pool/volume", "pool/fs/fs2".) 1237 * 1238 * The dataset name and the snapshot name (if any) will be 1239 * stored in ndmpd_zfs_args. 1240 */ 1241 1242 static int 1243 ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath, 1244 int zlen) 1245 { 1246 char *env_path; 1247 char *at; 1248 1249 env_path = get_backup_path_v3(ndmpd_zfs_params); 1250 if (env_path == NULL) 1251 return (-1); 1252 1253 if (env_path[0] != '/') { 1254 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1255 "Invalid path: %s (leading slash required)\n", env_path); 1256 return (-1); 1257 } 1258 1259 (void) strlcpy(zpath, &env_path[1], zlen); 1260 (void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1], 1261 ZFS_MAXNAMELEN); 1262 1263 at = strchr(ndmpd_zfs_args->nz_dataset, '@'); 1264 if (at) { 1265 *at = '\0'; 1266 (void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at, 1267 ZFS_MAXNAMELEN); 1268 } else { 1269 ndmpd_zfs_args->nz_snapname[0] = '\0'; 1270 } 1271 1272 (void) trim_whitespace(ndmpd_zfs_args->nz_dataset); 1273 1274 return (0); 1275 } 1276 1277 static int 1278 ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) 1279 { 1280 return (ndmpd_zfs_getenv(ndmpd_zfs_args)); 1281 } 1282 1283 boolean_t 1284 ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1285 { 1286 if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0) 1287 return (B_FALSE); 1288 1289 if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args)) 1290 return (B_FALSE); 1291 1292 return (B_TRUE); 1293 } 1294 1295 static boolean_t 1296 ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1297 { 1298 zfs_handle_t *zhp; 1299 char *at; 1300 1301 if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0) 1302 return (B_FALSE); 1303 1304 at = strchr(ndmpd_zfs_args->nz_dataset, '@'); 1305 1306 if (at) { 1307 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING, 1308 "%s ignored in restore path\n", at); 1309 *at = '\0'; 1310 } 1311 1312 ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM; 1313 1314 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, 1315 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type); 1316 1317 if (zhp) { 1318 zfs_close(zhp); 1319 1320 if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { 1321 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1322 "Restore dataset exists.\n" 1323 "A nonexistent dataset must be specified " 1324 "for 'zfs' non-incremental restore.\n"); 1325 return (B_FALSE); 1326 } 1327 } 1328 1329 NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset); 1330 1331 return (B_TRUE); 1332 } 1333 1334 /* 1335 * ndmpd_zfs_restore_getpath() 1336 * 1337 * Be sure to not include the leading slash, which is required for 1338 * compatibility with backup applications (NBU) but which is not part 1339 * of the ZFS syntax. (Note that this done explicitly in all paths 1340 * below except those calling ndmpd_zfs_backup_getpath(), because it is 1341 * already stripped in that function.) 1342 * 1343 * In addition, the DMA might add a trailing slash to the path. 1344 * Strip all such slashes. 1345 */ 1346 1347 static int 1348 ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args) 1349 { 1350 int version = ndmpd_zfs_params->mp_protocol_version; 1351 char zpath[ZFS_MAXNAMELEN]; 1352 mem_ndmp_name_v3_t *namep_v3; 1353 char *dataset = ndmpd_zfs_args->nz_dataset; 1354 char *nm; 1355 char *p; 1356 int len; 1357 int err; 1358 1359 dataset = ndmpd_zfs_args->nz_dataset; 1360 1361 namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0); 1362 1363 if (namep_v3 == NULL) { 1364 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]"); 1365 return (-1); 1366 } 1367 1368 if (namep_v3->nm3_dpath) { 1369 if (namep_v3->nm3_dpath[0] != '/') { 1370 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1371 "Invalid path: %s (leading slash required)\n", 1372 namep_v3->nm3_dpath); 1373 return (-1); 1374 } 1375 1376 (void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]), 1377 ZFS_MAXNAMELEN); 1378 1379 if (namep_v3->nm3_newnm) { 1380 (void) strlcat(dataset, "/", ZFS_MAXNAMELEN); 1381 (void) strlcat(dataset, namep_v3->nm3_newnm, 1382 ZFS_MAXNAMELEN); 1383 1384 } else { 1385 if (version == NDMPV3) { 1386 /* 1387 * The following does not apply for V4. 1388 * 1389 * Find the last component of nm3_opath. 1390 * nm3_opath has no trailing '/'. 1391 */ 1392 p = strrchr(namep_v3->nm3_opath, '/'); 1393 nm = p? p : namep_v3->nm3_opath; 1394 (void) strlcat(dataset, "/", ZFS_MAXNAMELEN); 1395 (void) strlcat(dataset, nm, ZFS_MAXNAMELEN); 1396 } 1397 } 1398 } else { 1399 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, 1400 ZFS_MAXNAMELEN); 1401 if (err) 1402 return (err); 1403 } 1404 1405 len = strlen(dataset); 1406 while (dataset[len-1] == '/') { 1407 dataset[len-1] = '\0'; 1408 len--; 1409 } 1410 1411 return (0); 1412 } 1413 1414 static int 1415 ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) 1416 { 1417 if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args) != 0) 1418 return (-1); 1419 1420 return (ndmpd_zfs_getenv(ndmpd_zfs_args)); 1421 } 1422 1423 static int 1424 ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) 1425 { 1426 1427 if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0) 1428 return (-1); 1429 1430 if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0) 1431 return (-1); 1432 1433 if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0) 1434 return (-1); 1435 1436 if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0) 1437 return (-1); 1438 1439 if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0) 1440 return (-1); 1441 1442 return (0); 1443 } 1444 1445 static int 1446 ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args) 1447 { 1448 char *envp; 1449 1450 envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE"); 1451 1452 if (envp == NULL) { 1453 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, " 1454 "defaulting to recursive"); 1455 ndmpd_zfs_args->nz_zfs_mode = 'r'; 1456 return (0); 1457 } 1458 1459 if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) { 1460 ndmpd_zfs_args->nz_zfs_mode = 'd'; 1461 } else if ((strcmp(envp, "recursive") == 0) || 1462 (strcmp(envp, "r") == 0)) { 1463 ndmpd_zfs_args->nz_zfs_mode = 'r'; 1464 } else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) { 1465 ndmpd_zfs_args->nz_zfs_mode = 'p'; 1466 } else { 1467 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1468 "Invalid ZFS_MODE value \"%s\".\n", envp); 1469 return (-1); 1470 } 1471 1472 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"", 1473 ndmpd_zfs_args->nz_zfs_mode); 1474 1475 return (0); 1476 } 1477 1478 /* 1479 * ndmpd_zfs_getenv_zfs_force() 1480 * 1481 * If SMF property zfs-force-override is set to "yes" or "no", this 1482 * value will override any value of NDMP environment variable ZFS_FORCE 1483 * as set by the DMA admin (or override the default of 'n', if ZFS_FORCE 1484 * is not set). By default, zfs-force-override is "off", which means it 1485 * will not override ZFS_FORCE. 1486 */ 1487 1488 static int 1489 ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args) 1490 { 1491 char *envp_force; 1492 char *override; 1493 1494 override = ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE); 1495 1496 if (strcasecmp(override, "yes") == 0) { 1497 ndmpd_zfs_args->nz_zfs_force = B_TRUE; 1498 NDMP_LOG(LOG_NOTICE, 1499 "SMF property zfs-force-override set to 'yes', " 1500 "overriding ZFS_FORCE"); 1501 return (0); 1502 } 1503 1504 if (strcasecmp(override, "no") == 0) { 1505 ndmpd_zfs_args->nz_zfs_force = B_FALSE; 1506 NDMP_LOG(LOG_NOTICE, 1507 "SMF property zfs-force-override set to 'no', " 1508 "overriding ZFS_FORCE"); 1509 return (0); 1510 } 1511 1512 if (strcasecmp(override, "off") != 0) { 1513 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1514 "SMF property zfs-force-override set to invalid value of " 1515 "'%s'; treating it as 'off'.", override); 1516 } 1517 1518 envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE"); 1519 1520 if (envp_force == NULL) { 1521 NDMP_LOG(LOG_DEBUG, 1522 "env(ZFS_FORCE) not specified, defaulting to FALSE"); 1523 ndmpd_zfs_args->nz_zfs_force = B_FALSE; 1524 return (0); 1525 } 1526 1527 /* 1528 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4). 1529 */ 1530 1531 if (strchr("tTyY", *envp_force)) 1532 ndmpd_zfs_args->nz_zfs_force = B_TRUE; 1533 1534 NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force); 1535 1536 return (0); 1537 } 1538 1539 static int 1540 ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args) 1541 { 1542 char *envp; 1543 1544 envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL"); 1545 1546 if (envp == NULL) { 1547 NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, " 1548 "defaulting to 0"); 1549 ndmpd_zfs_args->nz_level = 0; 1550 return (0); 1551 } 1552 1553 if (envp[1] != '\0') { 1554 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1555 "Invalid backup level \"%s\".\n", envp); 1556 return (-1); 1557 } 1558 1559 if (!isdigit(*envp)) { 1560 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1561 "Invalid backup level \"%s\".\n", envp); 1562 return (-1); 1563 } 1564 1565 ndmpd_zfs_args->nz_level = atoi(envp); 1566 1567 NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"", 1568 ndmpd_zfs_args->nz_level); 1569 1570 return (0); 1571 } 1572 1573 static int 1574 ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args) 1575 { 1576 char *envp_update; 1577 1578 envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE"); 1579 1580 if (envp_update == NULL) { 1581 NDMP_LOG(LOG_DEBUG, 1582 "env(UPDATE) not specified, defaulting to TRUE"); 1583 ndmpd_zfs_args->nz_update = B_TRUE; 1584 return (0); 1585 } 1586 1587 /* 1588 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4). 1589 */ 1590 1591 if (strchr("tTyY", *envp_update)) 1592 ndmpd_zfs_args->nz_update = B_TRUE; 1593 1594 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update); 1595 1596 return (0); 1597 } 1598 1599 static int 1600 ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args) 1601 { 1602 char *envp; 1603 1604 envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME"); 1605 1606 if (envp == NULL) { 1607 NDMP_LOG(LOG_DEBUG, 1608 "env(DMP_NAME) not specified, defaulting to 'level'"); 1609 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level", 1610 NDMPD_ZFS_DMP_NAME_MAX); 1611 return (0); 1612 } 1613 1614 if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp)) 1615 return (-1); 1616 1617 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp, 1618 NDMPD_ZFS_DMP_NAME_MAX); 1619 1620 NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp); 1621 1622 return (0); 1623 } 1624 1625 static int 1626 ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args) 1627 { 1628 char *zfs_backup_size; 1629 1630 zfs_backup_size = MOD_GETENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE"); 1631 1632 if (zfs_backup_size == NULL) { 1633 NDMP_LOG(LOG_ERR, "ZFS_BACKUP_SIZE env is NULL"); 1634 return (-1); 1635 } 1636 1637 NDMP_LOG(LOG_DEBUG, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size); 1638 1639 (void) sscanf(zfs_backup_size, "%llu", 1640 &ndmpd_zfs_args->nz_zfs_backup_size); 1641 1642 return (0); 1643 } 1644 1645 /* 1646 * ndmpd_zfs_dmp_name_valid() 1647 * 1648 * This function verifies that the dmp_name is valid. 1649 * 1650 * The dmp_name is restricted to alphanumeric characters plus 1651 * the underscore and hyphen, and must be 31 characters or less. 1652 * This is due to its use in the NDMPD_ZFS_PROP_INCR property 1653 * and in the ZFS snapshot name (if an ndmpd-generated snapshot 1654 * is required). 1655 */ 1656 1657 static boolean_t 1658 ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name) 1659 { 1660 char *c; 1661 1662 if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) { 1663 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1664 "DMP_NAME %s is longer than %d\n", 1665 dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1); 1666 return (B_FALSE); 1667 } 1668 1669 for (c = dmp_name; *c != '\0'; c++) { 1670 if (!isalpha(*c) && !isdigit(*c) && 1671 (*c != '_') && (*c != '-')) { 1672 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1673 "DMP_NAME %s contains illegal character %c\n", 1674 dmp_name, *c); 1675 return (B_FALSE); 1676 } 1677 } 1678 1679 NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name); 1680 return (B_TRUE); 1681 } 1682 1683 /* 1684 * ndmpd_zfs_is_incremental() 1685 * 1686 * This can only be called after ndmpd_zfs_getenv_level() 1687 * has been called. 1688 */ 1689 1690 static boolean_t 1691 ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args) 1692 { 1693 return (ndmpd_zfs_args->nz_level != 0); 1694 } 1695 1696 /* 1697 * ndmpd_zfs_snapshot_prepare() 1698 * 1699 * If no snapshot was supplied by the user, create a snapshot 1700 * for use by ndmpd. 1701 */ 1702 1703 static int 1704 ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args) 1705 { 1706 ndmpd_session_t *session = (ndmpd_session_t *) 1707 (ndmpd_zfs_params->mp_daemon_cookie); 1708 boolean_t recursive = B_FALSE; 1709 int zfs_err = 0; 1710 1711 if (session->ns_data.dd_abort) { 1712 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.", 1713 ndmpd_zfs_args->nz_dataset); 1714 return (-1); 1715 } 1716 1717 if (ndmpd_zfs_args->nz_snapname[0] == '\0') { 1718 ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE; 1719 1720 if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) { 1721 ndmpd_zfs_args->nz_snapname[0] = '\0'; 1722 1723 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1724 "Error creating snapshot for %s\n", 1725 ndmpd_zfs_args->nz_dataset); 1726 1727 return (-1); 1728 } 1729 } 1730 1731 if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) { 1732 NDMP_LOG(LOG_DEBUG, 1733 "ndmpd_zfs_snapshot_prop_add error\n"); 1734 1735 if (ndmpd_zfs_args->nz_ndmpd_snap) { 1736 1737 if (ndmpd_zfs_args->nz_zfs_mode != 'd') 1738 recursive = B_TRUE; 1739 1740 (void) snapshot_destroy(ndmpd_zfs_args->nz_dataset, 1741 ndmpd_zfs_args->nz_snapname, recursive, B_FALSE, 1742 &zfs_err); 1743 } 1744 1745 return (-1); 1746 } 1747 1748 return (0); 1749 } 1750 1751 /* 1752 * ndmpd_zfs_snapshot_cleanup() 1753 * 1754 * If UPDATE = y, find the old snapshot (if any) corresponding to 1755 * {LEVEL, DMP_NAME, ZFS_MODE}. If it was ndmpd-generated, 1756 * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR 1757 * property to remove {L, D, Z}. 1758 * 1759 * If UPDATE = n, if an ndmpd-generated snapshot was used for backup, 1760 * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR 1761 * property to remove {L, D, Z}. 1762 */ 1763 1764 static int 1765 ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err) 1766 { 1767 ndmpd_session_t *session = (ndmpd_session_t *) 1768 (ndmpd_zfs_params->mp_daemon_cookie); 1769 ndmpd_zfs_snapfind_t snapdata; 1770 boolean_t ndmpd_generated = B_FALSE; 1771 1772 bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t)); 1773 1774 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, 1775 snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE); 1776 1777 if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) { 1778 /* 1779 * Find the existing snapshot, if any, to "unuse." 1780 * Indicate that the current snapshot used for backup 1781 * should be skipped in the search. (The search is 1782 * sorted by creation time but this cannot be relied 1783 * upon for user-supplied snapshots.) 1784 */ 1785 1786 (void) snprintf(snapdata.nzs_snapskip, ZFS_MAXNAMELEN, "%s", 1787 ndmpd_zfs_args->nz_snapname); 1788 1789 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) { 1790 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n"); 1791 goto _remove_tmp_snap; 1792 } 1793 1794 if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */ 1795 ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated 1796 (snapdata.nzs_snapprop); 1797 1798 if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args, 1799 ndmpd_generated, &snapdata) != 0) { 1800 NDMP_LOG(LOG_DEBUG, 1801 "ndmpd_zfs_snapshot_unuse error\n"); 1802 goto _remove_tmp_snap; 1803 } 1804 } 1805 1806 if (session->ns_data.dd_abort) 1807 goto _remove_tmp_snap; 1808 1809 return (0); 1810 } 1811 1812 _remove_tmp_snap: 1813 1814 (void) snprintf(snapdata.nzs_snapname, ZFS_MAXNAMELEN, "%s", 1815 ndmpd_zfs_args->nz_snapname); 1816 1817 (void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop, 1818 ZFS_MAXPROPLEN); 1819 1820 snapdata.nzs_snapskip[0] = '\0'; 1821 1822 if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args, 1823 ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) { 1824 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n"); 1825 return (-1); 1826 } 1827 1828 if (!ndmpd_zfs_args->nz_update) 1829 return (0); 1830 1831 return (-1); 1832 } 1833 1834 static int 1835 ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args) 1836 { 1837 boolean_t recursive = B_FALSE; 1838 1839 if (ndmpd_zfs_snapname_create(ndmpd_zfs_args, 1840 ndmpd_zfs_args->nz_snapname, ZFS_MAXNAMELEN -1) < 0) { 1841 NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s", 1842 errno, ndmpd_zfs_args->nz_dataset); 1843 return (-1); 1844 } 1845 1846 if (ndmpd_zfs_args->nz_zfs_mode != 'd') 1847 recursive = B_TRUE; 1848 1849 if (snapshot_create(ndmpd_zfs_args->nz_dataset, 1850 ndmpd_zfs_args->nz_snapname, recursive, B_FALSE) != 0) { 1851 NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s", 1852 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname); 1853 return (-1); 1854 } 1855 1856 NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s", 1857 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname); 1858 1859 return (0); 1860 } 1861 1862 /* 1863 * ndmpd_zfs_snapshot_unuse() 1864 * 1865 * Given a pre-existing snapshot of the given {L, D, Z}: 1866 * If snapshot is ndmpd-generated, remove snapshot. 1867 * If not ndmpd-generated, or if the ndmpd-generated snapshot 1868 * cannot be destroyed, remove the {L, D, Z} substring from the 1869 * snapshot's NDMPD_ZFS_PROP_INCR property. 1870 * 1871 * In the event of a failure, it may be that two snapshots will 1872 * have the {L, D, Z} property set on them. This is not desirable, 1873 * so return an error and log the failure. 1874 */ 1875 1876 static int 1877 ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args, 1878 boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p) 1879 { 1880 boolean_t recursive = B_FALSE; 1881 int zfs_err = 0; 1882 int err = 0; 1883 1884 if (ndmpd_generated) { 1885 if (ndmpd_zfs_args->nz_zfs_mode != 'd') 1886 recursive = B_TRUE; 1887 1888 err = snapshot_destroy(ndmpd_zfs_args->nz_dataset, 1889 snapdata_p->nzs_snapname, recursive, B_FALSE, &zfs_err); 1890 1891 if (err) { 1892 NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;" 1893 " err: %d; zfs_err: %d", 1894 ndmpd_zfs_args->nz_dataset, 1895 snapdata_p->nzs_snapname, err, zfs_err); 1896 return (-1); 1897 } 1898 } 1899 1900 if (!ndmpd_generated || zfs_err) { 1901 if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p)) 1902 return (-1); 1903 } 1904 1905 return (0); 1906 } 1907 1908 static boolean_t 1909 ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop) 1910 { 1911 char origin; 1912 1913 (void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin); 1914 1915 return (origin == 'n'); 1916 } 1917 1918 /* 1919 * ndmpd_zfs_snapshot_find() 1920 * 1921 * Find a snapshot with a particular value for 1922 * the NDMPD_ZFS_PROP_INCR property. 1923 */ 1924 1925 static int 1926 ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args, 1927 ndmpd_zfs_snapfind_t *snapdata) 1928 { 1929 zfs_handle_t *zhp; 1930 int err; 1931 1932 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset, 1933 ndmpd_zfs_args->nz_type); 1934 1935 if (!zhp) { 1936 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open"); 1937 return (-1); 1938 } 1939 1940 err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find, 1941 snapdata); 1942 1943 zfs_close(zhp); 1944 1945 if (err) { 1946 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d", 1947 err); 1948 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1949 "Error iterating snapshots\n"); 1950 return (-1); 1951 } 1952 1953 return (0); 1954 } 1955 1956 /* 1957 * ndmpd_zfs_snapshot_prop_find() 1958 * 1959 * Find a snapshot with a particular value for 1960 * NDMPD_ZFS_PROP_INCR. Fill in data for the first one 1961 * found (sorted by creation time). However, skip the 1962 * the snapshot indicated in nzs_snapskip, if any. 1963 */ 1964 1965 static int 1966 ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg) 1967 { 1968 ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg; 1969 char propstr[ZFS_MAXPROPLEN]; 1970 char findprop_plus_slash[ZFS_MAXPROPLEN]; 1971 char *justsnap; 1972 int err = 0; 1973 1974 if (snapdata_p->nzs_snapname[0] != '\0') { 1975 NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s", 1976 (char *)zfs_get_name(zhp)); 1977 goto _done; 1978 } 1979 1980 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr); 1981 1982 if (err) { 1983 NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed"); 1984 goto _done; 1985 } 1986 1987 if (propstr[0] == '\0') { 1988 NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set", 1989 (char *)zfs_get_name(zhp)); 1990 goto _done; 1991 } 1992 1993 (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s", 1994 snapdata_p->nzs_findprop); 1995 1996 if (!strstr((const char *)propstr, 1997 (const char *)findprop_plus_slash)) { 1998 NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)", 1999 (char *)zfs_get_name(zhp), propstr, 2000 snapdata_p->nzs_findprop); 2001 goto _done; 2002 } 2003 2004 if (!ndmpd_zfs_prop_version_check(propstr, 2005 &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) { 2006 NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)", 2007 (char *)zfs_get_name(zhp), propstr, 2008 snapdata_p->nzs_findprop); 2009 NDMP_LOG(LOG_DEBUG, "did not pass version check"); 2010 goto _done; 2011 } 2012 2013 justsnap = strchr(zfs_get_name(zhp), '@') + 1; 2014 2015 if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) { 2016 (void) strlcpy(snapdata_p->nzs_snapname, justsnap, 2017 ZFS_MAXNAMELEN); 2018 2019 (void) strlcpy(snapdata_p->nzs_snapprop, propstr, 2020 ZFS_MAXPROPLEN); 2021 2022 NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n", 2023 snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop); 2024 } 2025 2026 _done: 2027 zfs_close(zhp); 2028 return (err); 2029 } 2030 2031 /* 2032 * ndmpd_zfs_snapshot_prop_get() 2033 * 2034 * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot 2035 */ 2036 2037 static int 2038 ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr) 2039 { 2040 nvlist_t *userprop; 2041 nvlist_t *propval; 2042 char *strval; 2043 int err; 2044 2045 propstr[0] = '\0'; 2046 2047 userprop = zfs_get_user_props(zhp); 2048 2049 if (userprop == NULL) 2050 return (0); 2051 2052 err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval); 2053 2054 if (err != 0) { 2055 if (err == ENOENT) 2056 return (0); 2057 2058 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err); 2059 2060 return (-1); 2061 } 2062 2063 err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval); 2064 2065 if (err != 0) { 2066 if (err == ENOENT) 2067 return (0); 2068 2069 NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err); 2070 2071 return (-1); 2072 } 2073 2074 (void) strlcpy(propstr, strval, ZFS_MAXPROPLEN); 2075 2076 return (0); 2077 } 2078 2079 /* 2080 * ndmpd_zfs_snapshot_prop_add() 2081 * 2082 * Update snapshot's NDMPD_ZFS_PROP_INCR property with 2083 * the current LEVEL, DMP_NAME, and ZFS_MODE values 2084 * (add property if it doesn't exist) 2085 */ 2086 2087 static int 2088 ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args) 2089 { 2090 char fullname[ZFS_MAXNAMELEN]; 2091 char propstr[ZFS_MAXPROPLEN]; 2092 zfs_handle_t *zhp; 2093 boolean_t set; 2094 int err; 2095 2096 (void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s", 2097 ndmpd_zfs_args->nz_dataset, 2098 ndmpd_zfs_args->nz_snapname); 2099 2100 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT); 2101 2102 if (!zhp) { 2103 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)"); 2104 return (-1); 2105 } 2106 2107 bzero(propstr, ZFS_MAXPROPLEN); 2108 2109 if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) { 2110 NDMP_LOG(LOG_DEBUG, "error getting property"); 2111 zfs_close(zhp); 2112 return (-1); 2113 } 2114 2115 if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) { 2116 zfs_close(zhp); 2117 return (-1); 2118 } 2119 2120 if (set) { 2121 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr); 2122 if (err) { 2123 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", 2124 err); 2125 NDMP_LOG(LOG_ERR, "error setting property %s", 2126 propstr); 2127 zfs_close(zhp); 2128 return (-1); 2129 } 2130 } 2131 2132 zfs_close(zhp); 2133 2134 (void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN); 2135 2136 return (0); 2137 } 2138 2139 static int 2140 ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args, 2141 char *propstr, boolean_t *set) 2142 { 2143 char subprop[ZFS_MAXPROPLEN]; 2144 char *p = propstr; 2145 int slash_count = 0; 2146 2147 *set = B_TRUE; 2148 2149 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, 2150 subprop, ZFS_MAXPROPLEN, B_FALSE); 2151 2152 if (propstr[0] == '\0') { 2153 (void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s", 2154 NDMPD_ZFS_PROP_MAJOR_VERSION, 2155 NDMPD_ZFS_PROP_MINOR_VERSION, 2156 (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u', 2157 subprop); 2158 return (0); 2159 } 2160 2161 if (strstr((const char *)propstr, (const char *)subprop)) { 2162 NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists", 2163 subprop); 2164 *set = B_FALSE; 2165 return (0); 2166 } 2167 2168 while (*p) { 2169 if (*(p++) == '/') 2170 slash_count++; 2171 } 2172 2173 if (slash_count >= NDMPD_ZFS_SUBPROP_MAX) { 2174 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2175 "snapshot %s: user property %s limit of %d subprops " 2176 "reached; cannot complete operation", 2177 ndmpd_zfs_args->nz_snapname, 2178 NDMPD_ZFS_PROP_INCR, 2179 NDMPD_ZFS_SUBPROP_MAX); 2180 return (-1); 2181 } 2182 2183 assert((strlen(propstr) + strlen(subprop) + 2) < ZFS_MAXPROPLEN); 2184 2185 (void) strlcat(propstr, "/", ZFS_MAXPROPLEN); 2186 (void) strlcat(propstr, subprop, ZFS_MAXPROPLEN); 2187 2188 return (0); 2189 } 2190 2191 static int 2192 ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args, 2193 char *subprop, int len, boolean_t prev_level) 2194 { 2195 return (snprintf(subprop, len, "%d.%s.%c", 2196 prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level, 2197 ndmpd_zfs_args->nz_dmp_name, 2198 ndmpd_zfs_args->nz_zfs_mode)); 2199 } 2200 2201 /* 2202 * ndmpd_zfs_snapshot_prop_remove() 2203 * 2204 * Remove specified substring from the snapshot's 2205 * NDMPD_ZFS_PROP_INCR property 2206 */ 2207 2208 static int 2209 ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args, 2210 ndmpd_zfs_snapfind_t *snapdata_p) 2211 { 2212 char findprop_plus_slash[ZFS_MAXPROPLEN]; 2213 char fullname[ZFS_MAXNAMELEN]; 2214 char newprop[ZFS_MAXPROPLEN]; 2215 char tmpstr[ZFS_MAXPROPLEN]; 2216 zfs_handle_t *zhp; 2217 char *ptr; 2218 int err; 2219 2220 (void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s", 2221 ndmpd_zfs_args->nz_dataset, 2222 snapdata_p->nzs_snapname); 2223 2224 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT); 2225 2226 if (!zhp) { 2227 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open"); 2228 return (-1); 2229 } 2230 2231 bzero(newprop, ZFS_MAXPROPLEN); 2232 2233 /* 2234 * If the substring to be removed is the only {L, D, Z} 2235 * in the property, remove the entire property 2236 */ 2237 2238 tmpstr[0] = '\0'; 2239 2240 (void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr); 2241 2242 if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) { 2243 2244 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop); 2245 2246 zfs_close(zhp); 2247 2248 if (err) { 2249 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", 2250 err); 2251 NDMP_LOG(LOG_ERR, "error setting property %s", newprop); 2252 return (-1); 2253 } 2254 2255 return (0); 2256 } 2257 2258 (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s", 2259 snapdata_p->nzs_findprop); 2260 2261 ptr = strstr((const char *)snapdata_p->nzs_snapprop, 2262 (const char *)findprop_plus_slash); 2263 2264 if (ptr == NULL) { 2265 /* 2266 * This shouldn't happen. Just return success. 2267 */ 2268 zfs_close(zhp); 2269 2270 return (0); 2271 } 2272 2273 /* 2274 * Remove "nzs_findprop" substring from property 2275 * 2276 * Example property: 2277 * 0.0.u/1.bob.p/0.jane.d 2278 * 2279 * Note that there will always be a prefix to the 2280 * strstr() result. Hence the below code works for 2281 * all cases. 2282 */ 2283 2284 ptr--; 2285 (void) strncpy(newprop, snapdata_p->nzs_snapprop, 2286 (char *)ptr - snapdata_p->nzs_snapprop); 2287 ptr += strlen(snapdata_p->nzs_findprop) + 1; 2288 (void) strlcat(newprop, ptr, ZFS_MAXPROPLEN); 2289 2290 err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop); 2291 2292 zfs_close(zhp); 2293 2294 if (err) { 2295 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err); 2296 NDMP_LOG(LOG_ERR, "error modifying property %s", newprop); 2297 return (-1); 2298 } 2299 2300 return (0); 2301 } 2302 2303 static boolean_t 2304 ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor) 2305 { 2306 (void) sscanf(propstr, "%u.%u.%*c%*s", major, minor); 2307 2308 if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) { 2309 NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)", 2310 *major, NDMPD_ZFS_PROP_MAJOR_VERSION); 2311 return (B_FALSE); 2312 } 2313 2314 if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) { 2315 NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)", 2316 *minor, NDMPD_ZFS_PROP_MINOR_VERSION); 2317 } 2318 2319 NDMP_LOG(LOG_DEBUG, "passed version check: " 2320 "supported prop major (%u <= %u); (snapprop minor: %u [%u])", 2321 *major, NDMPD_ZFS_PROP_MAJOR_VERSION, 2322 *minor, NDMPD_ZFS_PROP_MINOR_VERSION); 2323 2324 return (B_TRUE); 2325 } 2326 2327 static int 2328 ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args, 2329 char *snapname, int namelen) 2330 { 2331 char subprop[ZFS_MAXPROPLEN]; 2332 struct timeval tp; 2333 int err = 0; 2334 2335 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, 2336 subprop, ZFS_MAXPROPLEN, B_FALSE); 2337 2338 (void) gettimeofday(&tp, NULL); 2339 2340 err = snprintf(snapname, namelen, 2341 "ndmp.%s.%ld.%ld", 2342 subprop, 2343 tp.tv_sec, 2344 tp.tv_usec); 2345 2346 if (err > namelen) { 2347 NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d", 2348 snapname, namelen); 2349 return (-1); 2350 } 2351 2352 return (0); 2353 } 2354 2355 static void 2356 ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args) 2357 { 2358 switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) { 2359 case EZFS_EXISTS: 2360 case EZFS_BUSY: 2361 case EZFS_NOENT: 2362 case EZFS_INVALIDNAME: 2363 case EZFS_MOUNTFAILED: 2364 case EZFS_UMOUNTFAILED: 2365 case EZFS_NAMETOOLONG: 2366 case EZFS_BADRESTORE: 2367 2368 /* use existing error text */ 2369 2370 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2371 "%s: %s: %s\n", 2372 ndmpd_zfs_args->nz_dataset, 2373 libzfs_error_action(ndmpd_zfs_args->nz_zlibh), 2374 libzfs_error_description(ndmpd_zfs_args->nz_zlibh)); 2375 2376 break; 2377 2378 case EZFS_NOMEM: 2379 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2380 "Unable to obtain memory for operation\n"); 2381 break; 2382 2383 case EZFS_PROPSPACE: 2384 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2385 "A bad ZFS quota or reservation was encountered.\n"); 2386 break; 2387 2388 case EZFS_BADSTREAM: 2389 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2390 "The backup stream is invalid.\n"); 2391 break; 2392 2393 case EZFS_ZONED: 2394 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2395 "An error related to the local zone occurred.\n"); 2396 break; 2397 2398 case EZFS_NOSPC: 2399 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2400 "No more space is available\n"); 2401 break; 2402 2403 case EZFS_IO: 2404 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2405 "An I/O error occurred.\n"); 2406 break; 2407 2408 default: 2409 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 2410 "An internal ndmpd error occurred. " 2411 "Please contact support\n"); 2412 break; 2413 } 2414 } 2415 2416 void 2417 ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type, 2418 char *format, ...) 2419 { 2420 static char buf[1024]; 2421 va_list ap; 2422 2423 va_start(ap, format); 2424 2425 /*LINTED variable format specifier */ 2426 (void) vsnprintf(buf, sizeof (buf), format, ap); 2427 va_end(ap); 2428 2429 MOD_LOGV3(ndmpd_zfs_params, log_type, buf); 2430 2431 if ((log_type) == NDMP_LOG_ERROR) { 2432 NDMP_LOG(LOG_ERR, buf); 2433 } else { 2434 NDMP_LOG(LOG_NOTICE, buf); 2435 } 2436 } 2437