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