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