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 508 envp = MOD_GETENV(ndmpd_zfs_params, "HIST"); 509 if (!envp) 510 return (0); 511 512 if (!(strchr("YT", toupper(*envp)))) { 513 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING, 514 "HIST is not set. No file history will be " 515 "generated.\n"); 516 return (0); 517 } 518 519 /* Build up a sample root dir stat */ 520 (void) memset(&st, 0, sizeof (struct stat64)); 521 st.st_mode = S_IFDIR | 0777; 522 st.st_mtime = st.st_atime = st.st_ctime = time(NULL); 523 st.st_uid = st.st_gid = 0; 524 st.st_size = 1; 525 st.st_nlink = 1; 526 527 if (ndmpd_api_file_history_dir_v3(session, ".", ROOT_INODE, 528 ROOT_INODE) != 0) 529 return (-1); 530 if (ndmpd_api_file_history_dir_v3(session, "..", ROOT_INODE, 531 ROOT_INODE) != 0) 532 return (-1); 533 if (ndmpd_api_file_history_node_v3(session, ROOT_INODE, &st, 0) != 0) 534 return (-1); 535 536 ndmpd_file_history_cleanup(session, TRUE); 537 return (0); 538 } 539 540 static int 541 ndmpd_zfs_backup(ndmpd_zfs_args_t *ndmpd_zfs_args) 542 { 543 ndmpd_session_t *session = (ndmpd_session_t *) 544 (ndmpd_zfs_params->mp_daemon_cookie); 545 int *read_err = NULL; 546 int *write_err = NULL; 547 int result = 0; 548 int err; 549 550 if (session->ns_eof) 551 return (-1); 552 553 if (!session->ns_data.dd_abort) { 554 if (ndmpd_zfs_header_write(session)) { 555 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 556 "ndmpd_zfs header write error\n"); 557 return (-1); 558 } 559 560 err = ndmpd_zfs_reader_writer(ndmpd_zfs_args, 561 &read_err, &write_err); 562 563 if (err || read_err || write_err || session->ns_eof) 564 result = EPIPE; 565 } 566 567 if (session->ns_data.dd_abort) { 568 ndmpd_audit_backup(session->ns_connection, 569 ndmpd_zfs_args->nz_dataset, 570 session->ns_data.dd_data_addr.addr_type, 571 ndmpd_zfs_args->nz_dataset, EINTR); 572 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.", 573 ndmpd_zfs_args->nz_dataset); 574 575 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args); 576 err = -1; 577 } else { 578 ndmpd_audit_backup(session->ns_connection, 579 ndmpd_zfs_args->nz_dataset, 580 session->ns_data.dd_data_addr.addr_type, 581 ndmpd_zfs_args->nz_dataset, result); 582 583 err = ndmpd_zfs_post_backup(ndmpd_zfs_args); 584 if (err || result) 585 err = -1; 586 587 if (err == 0) { 588 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished.", 589 ndmpd_zfs_args->nz_dataset); 590 } else { 591 NDMP_LOG(LOG_DEBUG, "An error occurred while backing up" 592 " \"%s\"", ndmpd_zfs_args->nz_dataset); 593 } 594 } 595 596 return (err); 597 } 598 599 /* 600 * ndmpd_zfs_backup_send_read() 601 * 602 * This routine executes zfs_send() to create the backup data stream. 603 * The value of ZFS_MODE determines the type of zfs_send(): 604 * dataset ('d'): Only the dataset specified (i.e., top level) is backed up 605 * recursive ('r'): The dataset and its child file systems are backed up 606 * package ('p'): Same as 'r', except all intermediate snapshots are also 607 * backed up 608 * 609 * Volumes do not have descednants, so 'd' and 'r' produce equivalent results. 610 */ 611 612 static int 613 ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *ndmpd_zfs_args) 614 { 615 ndmpd_session_t *session = (ndmpd_session_t *) 616 (ndmpd_zfs_params->mp_daemon_cookie); 617 sendflags_t flags = { 0 }; 618 char *fromsnap = NULL; 619 zfs_handle_t *zhp; 620 int err; 621 622 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, 623 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type); 624 625 if (!zhp) { 626 if (!session->ns_data.dd_abort) 627 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open"); 628 return (-1); 629 } 630 631 switch (ndmpd_zfs_args->nz_zfs_mode) { 632 case ('d'): 633 flags.props = B_TRUE; 634 break; 635 case ('r'): 636 flags.replicate = B_TRUE; 637 break; 638 case ('p'): 639 flags.doall = B_TRUE; 640 flags.replicate = B_TRUE; 641 break; 642 default: 643 NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c", 644 ndmpd_zfs_args->nz_zfs_mode); 645 zfs_close(zhp); 646 return (-1); 647 } 648 649 if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { 650 if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') { 651 NDMP_LOG(LOG_ERR, "no fromsnap"); 652 zfs_close(zhp); 653 return (-1); 654 } 655 fromsnap = ndmpd_zfs_args->nz_fromsnap; 656 } 657 658 err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, flags, 659 ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL); 660 661 if (err && !session->ns_data.dd_abort) 662 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err); 663 664 zfs_close(zhp); 665 666 return (err); 667 } 668 669 /* 670 * ndmpd_zfs_backup_tape_write() 671 * 672 * The data begins on a mover record boundary (because 673 * the header is the size of a mover record--i.e. 674 * ndmpd_zfs_args->nz_bufsize). 675 */ 676 677 static int 678 ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *ndmpd_zfs_args) 679 { 680 ndmpd_session_t *session = (ndmpd_session_t *) 681 (ndmpd_zfs_params->mp_daemon_cookie); 682 int bufsize = ndmpd_zfs_args->nz_bufsize; 683 u_longlong_t *bytes_totalp; 684 int count; 685 char *buf; 686 687 buf = ndmp_malloc(bufsize); 688 if (buf == NULL) { 689 NDMP_LOG(LOG_DEBUG, "buf NULL"); 690 return (-1); 691 } 692 693 bytes_totalp = 694 &(session->ns_data.dd_module.dm_stats.ms_bytes_processed); 695 696 for (;;) { 697 bzero(buf, bufsize); 698 699 count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf, 700 bufsize); 701 702 if (count == 0) /* EOF */ { 703 NDMP_LOG(LOG_DEBUG, 704 "zfs_send stream size: %llu bytes; " 705 "full backup size (including header): %llu", 706 *bytes_totalp - bufsize, *bytes_totalp); 707 free(buf); 708 709 return (ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args, 710 *bytes_totalp)); 711 } 712 713 if (count == -1) { 714 NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)", 715 errno); 716 free(buf); 717 return (-1); 718 } 719 NS_ADD(rdisk, count); 720 721 if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) { 722 (void) ndmpd_zfs_abort((void *) ndmpd_zfs_args); 723 NDMP_LOG(LOG_ERR, "MOD_WRITE error"); 724 free(buf); 725 return (-1); 726 } 727 728 *bytes_totalp += count; 729 } 730 /* NOTREACHED */ 731 } 732 733 static int 734 ndmpd_zfs_addenv_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args, 735 u_longlong_t bytes_total) 736 { 737 char zfs_backup_size[32]; 738 int err; 739 740 (void) snprintf(zfs_backup_size, sizeof (zfs_backup_size), "%llu", 741 bytes_total); 742 743 err = MOD_ADDENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE", zfs_backup_size); 744 745 if (err) { 746 NDMP_LOG(LOG_ERR, "Failed to add ZFS_BACKUP_SIZE env"); 747 return (-1); 748 } 749 750 NDMP_LOG(LOG_DEBUG, "Added ZFS_BACKUP_SIZE env: %s", zfs_backup_size); 751 752 return (0); 753 } 754 755 int 756 ndmpd_zfs_restore_starter(void *arg) 757 { 758 ndmpd_zfs_args_t *ndmpd_zfs_args = arg; 759 ndmpd_session_t *session = (ndmpd_session_t *) 760 (ndmpd_zfs_params->mp_daemon_cookie); 761 int err; 762 763 ndmp_session_ref(session); 764 765 err = ndmpd_zfs_restore(ndmpd_zfs_args); 766 767 MOD_DONE(ndmpd_zfs_params, err); 768 769 NS_DEC(nrs); 770 771 ndmp_session_unref(session); 772 773 ndmpd_zfs_fini(ndmpd_zfs_args); 774 775 return (err); 776 } 777 778 static int 779 ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) 780 { 781 ndmpd_session_t *session = (ndmpd_session_t *) 782 (ndmpd_zfs_params->mp_daemon_cookie); 783 int *read_err = NULL; 784 int *write_err = NULL; 785 int result = 0; 786 int err; 787 788 if (!session->ns_data.dd_abort) { 789 if (ndmpd_zfs_header_read(ndmpd_zfs_args)) { 790 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 791 "ndmpd_zfs header read error\n"); 792 return (-1); 793 } 794 795 err = ndmpd_zfs_reader_writer(ndmpd_zfs_args, 796 &write_err, &read_err); 797 798 if (err || read_err || write_err || session->ns_eof) 799 result = EIO; 800 } 801 802 if (session->ns_data.dd_abort) { 803 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.", 804 ndmpd_zfs_args->nz_dataset); 805 ndmpd_audit_restore(session->ns_connection, 806 ndmpd_zfs_args->nz_dataset, 807 session->ns_data.dd_data_addr.addr_type, 808 ndmpd_zfs_args->nz_dataset, EINTR); 809 (void) ndmpd_zfs_post_restore(ndmpd_zfs_args); 810 err = -1; 811 } else { 812 ndmpd_audit_restore(session->ns_connection, 813 ndmpd_zfs_args->nz_dataset, 814 session->ns_data.dd_data_addr.addr_type, 815 ndmpd_zfs_args->nz_dataset, result); 816 err = ndmpd_zfs_post_restore(ndmpd_zfs_args); 817 if (err || result) 818 err = -1; 819 820 if (err == 0) { 821 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished", 822 ndmpd_zfs_args->nz_dataset); 823 } else { 824 NDMP_LOG(LOG_DEBUG, "An error occurred while restoring" 825 " to \"%s\"", ndmpd_zfs_args->nz_dataset); 826 } 827 } 828 829 return (err); 830 } 831 832 static int 833 ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *ndmpd_zfs_args) 834 { 835 ndmpd_session_t *session = (ndmpd_session_t *) 836 (ndmpd_zfs_params->mp_daemon_cookie); 837 int bufsize = ndmpd_zfs_args->nz_bufsize; 838 u_longlong_t backup_size = ndmpd_zfs_args->nz_zfs_backup_size; 839 u_longlong_t *bytes_totalp; 840 u_longlong_t bytes; 841 char *buf; 842 int count; 843 int err; 844 845 buf = ndmp_malloc(bufsize); 846 if (buf == NULL) { 847 NDMP_LOG(LOG_DEBUG, "buf NULL"); 848 return (-1); 849 } 850 851 bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total; 852 853 while (*bytes_totalp < backup_size) { 854 855 bytes = backup_size - *bytes_totalp; 856 857 if (bytes >= bufsize) 858 bytes = bufsize; 859 860 err = MOD_READ(ndmpd_zfs_params, buf, bytes); 861 862 if (err != 0) { 863 NDMP_LOG(LOG_ERR, "MOD_READ error: %d; returning -1", 864 err); 865 free(buf); 866 return (-1); 867 } 868 869 count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf, 870 bytes); 871 872 if (count != bytes) { 873 NDMP_LOG(LOG_ERR, "count (%d) != bytes (%d)", 874 count, bytes); 875 876 if (count == -1) { 877 NDMP_LOG(LOG_ERR, "pipe write error: errno: %d", 878 errno); 879 880 if (session->ns_data.dd_abort) 881 NDMP_LOG(LOG_DEBUG, "abort set"); 882 } 883 884 free(buf); 885 return (-1); 886 } 887 888 NS_ADD(wdisk, count); 889 890 *bytes_totalp += count; 891 } 892 893 free(buf); 894 return (0); 895 } 896 897 /* 898 * ndmpd_zfs_restore_recv_write() 899 * 900 * This routine executes zfs_receive() to restore the backup. 901 */ 902 903 static int 904 ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *ndmpd_zfs_args) 905 { 906 ndmpd_session_t *session = (ndmpd_session_t *) 907 (ndmpd_zfs_params->mp_daemon_cookie); 908 recvflags_t flags; 909 int err; 910 911 bzero(&flags, sizeof (recvflags_t)); 912 913 flags.nomount = B_TRUE; 914 915 NDMP_LOG(LOG_DEBUG, "nz_zfs_force: %d\n", ndmpd_zfs_args->nz_zfs_force); 916 917 if (ndmpd_zfs_args->nz_zfs_force) 918 flags.force = B_TRUE; 919 920 err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset, 921 flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL); 922 923 if (err && !session->ns_data.dd_abort) 924 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err); 925 926 return (err); 927 } 928 929 /* 930 * ndmpd_zfs_reader_writer() 931 * 932 * Two separate threads are used for actual backup or restore. 933 */ 934 935 static int 936 ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args, 937 int **sendrecv_errp, int **tape_errp) 938 { 939 funct_t sendrecv_func; 940 funct_t tape_func; 941 int sendrecv_err; 942 int tape_err; 943 944 switch (ndmpd_zfs_params->mp_operation) { 945 case NDMP_DATA_OP_BACKUP: 946 sendrecv_func = (funct_t)ndmpd_zfs_backup_send_read; 947 tape_func = (funct_t)ndmpd_zfs_backup_tape_write; 948 break; 949 case NDMP_DATA_OP_RECOVER: 950 sendrecv_func = (funct_t)ndmpd_zfs_restore_recv_write; 951 tape_func = (funct_t)ndmpd_zfs_restore_tape_read; 952 break; 953 } 954 955 sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread, 956 NULL, sendrecv_func, ndmpd_zfs_args); 957 958 if (sendrecv_err == 0) { 959 tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread, 960 NULL, tape_func, ndmpd_zfs_args); 961 962 if (tape_err) { 963 /* 964 * The close of the tape side of the pipe will cause 965 * nz_sendrecv_thread to error in the zfs_send/recv() 966 * call and to return. Hence we do not need 967 * to explicitly cancel the sendrecv_thread here 968 * (the pthread_join() below is sufficient). 969 */ 970 971 (void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]); 972 NDMP_LOG(LOG_ERR, "Could not start tape thread; " 973 "aborting z-op"); 974 } 975 976 (void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread, 977 (void **) sendrecv_errp); 978 } 979 980 if ((tape_err == 0) && 981 (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER)) 982 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE); 983 984 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS); 985 986 if ((sendrecv_err == 0) && (tape_err == 0)) { 987 (void) pthread_join(ndmpd_zfs_args->nz_tape_thread, 988 (void **) tape_errp); 989 } 990 991 if ((tape_err == 0) && 992 (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)) 993 ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE); 994 995 return (sendrecv_err ? sendrecv_err : tape_err); 996 } 997 998 int 999 ndmpd_zfs_abort(void *arg) 1000 { 1001 ndmpd_zfs_args_t *ndmpd_zfs_args = arg; 1002 char str[8]; 1003 1004 if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) 1005 (void) strlcpy(str, "backup", 8); 1006 else 1007 (void) strlcpy(str, "recover", 8); 1008 1009 NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation", 1010 str); 1011 1012 ndmpd_zfs_close_fds(ndmpd_zfs_args); 1013 1014 return (0); 1015 } 1016 1017 /* 1018 * ndmpd_zfs_pre_backup() 1019 * 1020 * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL. 1021 * This ensures that ndmp_include_zfs() will fail, which is 1022 * a requirement for "zfs"-type backup. 1023 */ 1024 1025 int 1026 ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args) 1027 { 1028 ndmpd_session_t *session = (ndmpd_session_t *) 1029 (ndmpd_zfs_params->mp_daemon_cookie); 1030 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1031 int err; 1032 1033 if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL) 1034 return (0); 1035 1036 (void) memset(nctxp, 0, sizeof (ndmp_context_t)); 1037 nctxp->nc_plversion = ndmp_pl->np_plversion; 1038 nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH); 1039 nctxp->nc_ddata = (void *) session; 1040 1041 err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp, 1042 ndmpd_zfs_args->nz_dataset); 1043 1044 if (err != 0) { 1045 NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m"); 1046 (void) ndmpd_zfs_post_backup(ndmpd_zfs_args); 1047 } 1048 1049 return (err); 1050 } 1051 1052 int 1053 ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args) 1054 { 1055 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1056 int err = 0; 1057 1058 if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL) 1059 return (0); 1060 1061 err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err); 1062 1063 if (err == -1) 1064 NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m"); 1065 1066 return (err); 1067 } 1068 1069 int 1070 ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) 1071 { 1072 ndmpd_session_t *session = (ndmpd_session_t *) 1073 (ndmpd_zfs_params->mp_daemon_cookie); 1074 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1075 char bkpath[ZFS_MAXNAMELEN]; 1076 int err; 1077 1078 if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL) 1079 return (0); 1080 1081 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath, ZFS_MAXNAMELEN); 1082 1083 if (err != 0) { 1084 NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err); 1085 return (-1); 1086 } 1087 1088 err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args); 1089 1090 if (err != 0) { 1091 NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err); 1092 return (-1); 1093 } 1094 1095 (void) memset(nctxp, 0, sizeof (ndmp_context_t)); 1096 nctxp->nc_ddata = (void *) session; 1097 1098 err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath, 1099 ndmpd_zfs_args->nz_dataset); 1100 1101 if (err != 0) { 1102 NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m"); 1103 return (-1); 1104 } 1105 1106 return (0); 1107 } 1108 1109 int 1110 ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) 1111 { 1112 ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; 1113 int err = 0; 1114 1115 if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL) 1116 return (0); 1117 1118 err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err); 1119 1120 if (err == -1) 1121 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m"); 1122 1123 return (err); 1124 } 1125 1126 boolean_t 1127 ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1128 { 1129 ndmpd_zfs_snapfind_t snapdata; 1130 1131 if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0) 1132 return (B_FALSE); 1133 1134 if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args)) 1135 return (B_FALSE); 1136 1137 if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { 1138 (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, 1139 snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE); 1140 1141 snapdata.nzs_snapname[0] = '\0'; 1142 snapdata.nzs_snapprop[0] = '\0'; 1143 1144 if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) 1145 return (B_FALSE); 1146 1147 if (snapdata.nzs_snapname[0] == '\0') { /* not found */ 1148 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1149 "Snapshot for level %d does not exist\n", 1150 ndmpd_zfs_args->nz_level-1); 1151 return (B_FALSE); 1152 } 1153 1154 (void) strlcpy(ndmpd_zfs_args->nz_fromsnap, 1155 snapdata.nzs_snapname, ZFS_MAXNAMELEN); 1156 } 1157 1158 return (B_TRUE); 1159 } 1160 1161 /* 1162 * ndmpd_zfs_backup_pathvalid() 1163 * 1164 * Make sure the path is of an existing dataset 1165 */ 1166 1167 static boolean_t 1168 ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1169 { 1170 char zpath[ZFS_MAXNAMELEN]; 1171 char propstr[ZFS_MAXPROPLEN]; 1172 zfs_handle_t *zhp; 1173 zfs_type_t ztype = 0; 1174 int err; 1175 1176 if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, ZFS_MAXNAMELEN) 1177 != 0) 1178 return (B_FALSE); 1179 1180 if (ndmpd_zfs_args->nz_snapname[0] != '\0') { 1181 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath, 1182 ZFS_TYPE_SNAPSHOT); 1183 1184 if (!zhp) { 1185 NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, 1186 "zfs_open (snap)"); 1187 ndmpd_zfs_args->nz_snapname[0] = '\0'; 1188 ndmpd_zfs_args->nz_dataset[0] = '\0'; 1189 return (B_FALSE); 1190 } 1191 1192 err = ndmpd_zfs_snapshot_prop_get(zhp, propstr); 1193 1194 zfs_close(zhp); 1195 1196 if (err) { 1197 NDMP_LOG(LOG_DEBUG, 1198 "ndmpd_zfs_snapshot_prop_get failed"); 1199 return (-1); 1200 } 1201 1202 if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) { 1203 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1204 "cannot use an ndmpd-generated snapshot\n"); 1205 return (B_FALSE); 1206 } 1207 } 1208 1209 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, 1210 ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET); 1211 1212 if (zhp) { 1213 ztype = zfs_get_type(zhp); 1214 zfs_close(zhp); 1215 } 1216 1217 if ((ztype == ZFS_TYPE_VOLUME) || 1218 (ztype == ZFS_TYPE_FILESYSTEM)) { 1219 ndmpd_zfs_args->nz_type = ztype; 1220 return (B_TRUE); 1221 } 1222 1223 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1224 "Invalid file system or volume.\n"); 1225 1226 return (B_FALSE); 1227 } 1228 1229 /* 1230 * ndmpd_zfs_backup_getpath() 1231 * 1232 * Retrieve the backup path from the environment, which should 1233 * be of the form "/dataset[@snap]". The leading slash is required 1234 * by certain DMA's but can otherwise be ignored. 1235 * 1236 * (Note: "dataset" can consist of more than one component, 1237 * e.g. "pool", "pool/volume", "pool/fs/fs2".) 1238 * 1239 * The dataset name and the snapshot name (if any) will be 1240 * stored in ndmpd_zfs_args. 1241 */ 1242 1243 static int 1244 ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath, 1245 int zlen) 1246 { 1247 char *env_path; 1248 char *at; 1249 1250 env_path = get_backup_path_v3(ndmpd_zfs_params); 1251 if (env_path == NULL) 1252 return (-1); 1253 1254 if (env_path[0] != '/') { 1255 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1256 "Invalid path: %s (leading slash required)\n", env_path); 1257 return (-1); 1258 } 1259 1260 (void) strlcpy(zpath, &env_path[1], zlen); 1261 (void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1], 1262 ZFS_MAXNAMELEN); 1263 1264 at = strchr(ndmpd_zfs_args->nz_dataset, '@'); 1265 if (at) { 1266 *at = '\0'; 1267 (void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at, 1268 ZFS_MAXNAMELEN); 1269 } else { 1270 ndmpd_zfs_args->nz_snapname[0] = '\0'; 1271 } 1272 1273 (void) trim_whitespace(ndmpd_zfs_args->nz_dataset); 1274 1275 return (0); 1276 } 1277 1278 static int 1279 ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) 1280 { 1281 return (ndmpd_zfs_getenv(ndmpd_zfs_args)); 1282 } 1283 1284 boolean_t 1285 ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1286 { 1287 if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0) 1288 return (B_FALSE); 1289 1290 if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args)) 1291 return (B_FALSE); 1292 1293 return (B_TRUE); 1294 } 1295 1296 static boolean_t 1297 ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args) 1298 { 1299 zfs_handle_t *zhp; 1300 char *at; 1301 1302 if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0) 1303 return (B_FALSE); 1304 1305 at = strchr(ndmpd_zfs_args->nz_dataset, '@'); 1306 1307 if (at) { 1308 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING, 1309 "%s ignored in restore path\n", at); 1310 *at = '\0'; 1311 } 1312 1313 ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM; 1314 1315 zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, 1316 ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type); 1317 1318 if (zhp) { 1319 zfs_close(zhp); 1320 1321 if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { 1322 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1323 "Restore dataset exists.\n" 1324 "A nonexistent dataset must be specified " 1325 "for 'zfs' non-incremental restore.\n"); 1326 return (B_FALSE); 1327 } 1328 } 1329 1330 NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset); 1331 1332 return (B_TRUE); 1333 } 1334 1335 /* 1336 * ndmpd_zfs_restore_getpath() 1337 * 1338 * Be sure to not include the leading slash, which is required for 1339 * compatibility with backup applications (NBU) but which is not part 1340 * of the ZFS syntax. (Note that this done explicitly in all paths 1341 * below except those calling ndmpd_zfs_backup_getpath(), because it is 1342 * already stripped in that function.) 1343 * 1344 * In addition, the DMA might add a trailing slash to the path. 1345 * Strip all such slashes. 1346 */ 1347 1348 static int 1349 ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args) 1350 { 1351 int version = ndmpd_zfs_params->mp_protocol_version; 1352 char zpath[ZFS_MAXNAMELEN]; 1353 mem_ndmp_name_v3_t *namep_v3; 1354 char *dataset = ndmpd_zfs_args->nz_dataset; 1355 char *nm; 1356 char *p; 1357 int len; 1358 int err; 1359 1360 dataset = ndmpd_zfs_args->nz_dataset; 1361 1362 namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0); 1363 1364 if (namep_v3 == NULL) { 1365 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]"); 1366 return (-1); 1367 } 1368 1369 if (namep_v3->nm3_dpath) { 1370 if (namep_v3->nm3_dpath[0] != '/') { 1371 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1372 "Invalid path: %s (leading slash required)\n", 1373 namep_v3->nm3_dpath); 1374 return (-1); 1375 } 1376 1377 (void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]), 1378 ZFS_MAXNAMELEN); 1379 1380 if (namep_v3->nm3_newnm) { 1381 (void) strlcat(dataset, "/", ZFS_MAXNAMELEN); 1382 (void) strlcat(dataset, namep_v3->nm3_newnm, 1383 ZFS_MAXNAMELEN); 1384 1385 } else { 1386 if (version == NDMPV3) { 1387 /* 1388 * The following does not apply for V4. 1389 * 1390 * Find the last component of nm3_opath. 1391 * nm3_opath has no trailing '/'. 1392 */ 1393 p = strrchr(namep_v3->nm3_opath, '/'); 1394 nm = p? p : namep_v3->nm3_opath; 1395 (void) strlcat(dataset, "/", ZFS_MAXNAMELEN); 1396 (void) strlcat(dataset, nm, ZFS_MAXNAMELEN); 1397 } 1398 } 1399 } else { 1400 err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, 1401 ZFS_MAXNAMELEN); 1402 if (err) 1403 return (err); 1404 } 1405 1406 len = strlen(dataset); 1407 while (dataset[len-1] == '/') { 1408 dataset[len-1] = '\0'; 1409 len--; 1410 } 1411 1412 return (0); 1413 } 1414 1415 static int 1416 ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) 1417 { 1418 if (ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args) != 0) 1419 return (-1); 1420 1421 return (ndmpd_zfs_getenv(ndmpd_zfs_args)); 1422 } 1423 1424 static int 1425 ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) 1426 { 1427 1428 if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0) 1429 return (-1); 1430 1431 if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0) 1432 return (-1); 1433 1434 if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0) 1435 return (-1); 1436 1437 if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0) 1438 return (-1); 1439 1440 if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0) 1441 return (-1); 1442 1443 return (0); 1444 } 1445 1446 static int 1447 ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args) 1448 { 1449 char *envp; 1450 1451 envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE"); 1452 1453 if (envp == NULL) { 1454 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, " 1455 "defaulting to recursive"); 1456 ndmpd_zfs_args->nz_zfs_mode = 'r'; 1457 return (0); 1458 } 1459 1460 if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) { 1461 ndmpd_zfs_args->nz_zfs_mode = 'd'; 1462 } else if ((strcmp(envp, "recursive") == 0) || 1463 (strcmp(envp, "r") == 0)) { 1464 ndmpd_zfs_args->nz_zfs_mode = 'r'; 1465 } else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) { 1466 ndmpd_zfs_args->nz_zfs_mode = 'p'; 1467 } else { 1468 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1469 "Invalid ZFS_MODE value \"%s\".\n", envp); 1470 return (-1); 1471 } 1472 1473 NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"", 1474 ndmpd_zfs_args->nz_zfs_mode); 1475 1476 return (0); 1477 } 1478 1479 /* 1480 * ndmpd_zfs_getenv_zfs_force() 1481 * 1482 * If SMF property zfs-force-override is set to "yes" or "no", this 1483 * value will override any value of NDMP environment variable ZFS_FORCE 1484 * as set by the DMA admin (or override the default of 'n', if ZFS_FORCE 1485 * is not set). By default, zfs-force-override is "off", which means it 1486 * will not override ZFS_FORCE. 1487 */ 1488 1489 static int 1490 ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args) 1491 { 1492 char *envp_force; 1493 char *override; 1494 1495 override = ndmpd_get_prop(NDMP_ZFS_FORCE_OVERRIDE); 1496 1497 if (strcasecmp(override, "yes") == 0) { 1498 ndmpd_zfs_args->nz_zfs_force = B_TRUE; 1499 NDMP_LOG(LOG_NOTICE, 1500 "SMF property zfs-force-override set to 'yes', " 1501 "overriding ZFS_FORCE"); 1502 return (0); 1503 } 1504 1505 if (strcasecmp(override, "no") == 0) { 1506 ndmpd_zfs_args->nz_zfs_force = B_FALSE; 1507 NDMP_LOG(LOG_NOTICE, 1508 "SMF property zfs-force-override set to 'no', " 1509 "overriding ZFS_FORCE"); 1510 return (0); 1511 } 1512 1513 if (strcasecmp(override, "off") != 0) { 1514 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1515 "SMF property zfs-force-override set to invalid value of " 1516 "'%s'; treating it as 'off'.", override); 1517 } 1518 1519 envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE"); 1520 1521 if (envp_force == NULL) { 1522 NDMP_LOG(LOG_DEBUG, 1523 "env(ZFS_FORCE) not specified, defaulting to FALSE"); 1524 ndmpd_zfs_args->nz_zfs_force = B_FALSE; 1525 return (0); 1526 } 1527 1528 /* 1529 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4). 1530 */ 1531 1532 if (strchr("tTyY", *envp_force)) 1533 ndmpd_zfs_args->nz_zfs_force = B_TRUE; 1534 1535 NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force); 1536 1537 return (0); 1538 } 1539 1540 static int 1541 ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args) 1542 { 1543 char *envp; 1544 1545 envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL"); 1546 1547 if (envp == NULL) { 1548 NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, " 1549 "defaulting to 0"); 1550 ndmpd_zfs_args->nz_level = 0; 1551 return (0); 1552 } 1553 1554 if (envp[1] != '\0') { 1555 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1556 "Invalid backup level \"%s\".\n", envp); 1557 return (-1); 1558 } 1559 1560 if (!isdigit(*envp)) { 1561 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1562 "Invalid backup level \"%s\".\n", envp); 1563 return (-1); 1564 } 1565 1566 ndmpd_zfs_args->nz_level = atoi(envp); 1567 1568 NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"", 1569 ndmpd_zfs_args->nz_level); 1570 1571 return (0); 1572 } 1573 1574 static int 1575 ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args) 1576 { 1577 char *envp_update; 1578 1579 envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE"); 1580 1581 if (envp_update == NULL) { 1582 NDMP_LOG(LOG_DEBUG, 1583 "env(UPDATE) not specified, defaulting to TRUE"); 1584 ndmpd_zfs_args->nz_update = B_TRUE; 1585 return (0); 1586 } 1587 1588 /* 1589 * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4). 1590 */ 1591 1592 if (strchr("tTyY", *envp_update)) 1593 ndmpd_zfs_args->nz_update = B_TRUE; 1594 1595 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update); 1596 1597 return (0); 1598 } 1599 1600 static int 1601 ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args) 1602 { 1603 char *envp; 1604 1605 envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME"); 1606 1607 if (envp == NULL) { 1608 NDMP_LOG(LOG_DEBUG, 1609 "env(DMP_NAME) not specified, defaulting to 'level'"); 1610 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level", 1611 NDMPD_ZFS_DMP_NAME_MAX); 1612 return (0); 1613 } 1614 1615 if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp)) 1616 return (-1); 1617 1618 (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp, 1619 NDMPD_ZFS_DMP_NAME_MAX); 1620 1621 NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp); 1622 1623 return (0); 1624 } 1625 1626 static int 1627 ndmpd_zfs_getenv_zfs_backup_size(ndmpd_zfs_args_t *ndmpd_zfs_args) 1628 { 1629 char *zfs_backup_size; 1630 1631 zfs_backup_size = MOD_GETENV(ndmpd_zfs_params, "ZFS_BACKUP_SIZE"); 1632 1633 if (zfs_backup_size == NULL) { 1634 NDMP_LOG(LOG_ERR, "ZFS_BACKUP_SIZE env is NULL"); 1635 return (-1); 1636 } 1637 1638 NDMP_LOG(LOG_DEBUG, "ZFS_BACKUP_SIZE: %s\n", zfs_backup_size); 1639 1640 (void) sscanf(zfs_backup_size, "%llu", 1641 &ndmpd_zfs_args->nz_zfs_backup_size); 1642 1643 return (0); 1644 } 1645 1646 /* 1647 * ndmpd_zfs_dmp_name_valid() 1648 * 1649 * This function verifies that the dmp_name is valid. 1650 * 1651 * The dmp_name is restricted to alphanumeric characters plus 1652 * the underscore and hyphen, and must be 31 characters or less. 1653 * This is due to its use in the NDMPD_ZFS_PROP_INCR property 1654 * and in the ZFS snapshot name (if an ndmpd-generated snapshot 1655 * is required). 1656 */ 1657 1658 static boolean_t 1659 ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name) 1660 { 1661 char *c; 1662 1663 if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) { 1664 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1665 "DMP_NAME %s is longer than %d\n", 1666 dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1); 1667 return (B_FALSE); 1668 } 1669 1670 for (c = dmp_name; *c != '\0'; c++) { 1671 if (!isalpha(*c) && !isdigit(*c) && 1672 (*c != '_') && (*c != '-')) { 1673 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1674 "DMP_NAME %s contains illegal character %c\n", 1675 dmp_name, *c); 1676 return (B_FALSE); 1677 } 1678 } 1679 1680 NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name); 1681 return (B_TRUE); 1682 } 1683 1684 /* 1685 * ndmpd_zfs_is_incremental() 1686 * 1687 * This can only be called after ndmpd_zfs_getenv_level() 1688 * has been called. 1689 */ 1690 1691 static boolean_t 1692 ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args) 1693 { 1694 return (ndmpd_zfs_args->nz_level != 0); 1695 } 1696 1697 /* 1698 * ndmpd_zfs_snapshot_prepare() 1699 * 1700 * If no snapshot was supplied by the user, create a snapshot 1701 * for use by ndmpd. 1702 */ 1703 1704 static int 1705 ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args) 1706 { 1707 ndmpd_session_t *session = (ndmpd_session_t *) 1708 (ndmpd_zfs_params->mp_daemon_cookie); 1709 boolean_t recursive = B_FALSE; 1710 int zfs_err = 0; 1711 1712 if (session->ns_data.dd_abort) { 1713 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.", 1714 ndmpd_zfs_args->nz_dataset); 1715 return (-1); 1716 } 1717 1718 if (ndmpd_zfs_args->nz_snapname[0] == '\0') { 1719 ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE; 1720 1721 if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) { 1722 ndmpd_zfs_args->nz_snapname[0] = '\0'; 1723 1724 ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, 1725 "Error creating snapshot for %s\n", 1726 ndmpd_zfs_args->nz_dataset); 1727 1728 return (-1); 1729 } 1730 } 1731 1732 if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) { 1733 NDMP_LOG(LOG_DEBUG, 1734 "ndmpd_zfs_snapshot_prop_add error\n"); 1735 1736 if (ndmpd_zfs_args->nz_ndmpd_snap) { 1737 1738 if (ndmpd_zfs_args->nz_zfs_mode != 'd') 1739 recursive = B_TRUE; 1740 1741 (void) snapshot_destroy(ndmpd_zfs_args->nz_dataset, 1742 ndmpd_zfs_args->nz_snapname, recursive, &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) != 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, &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