1 /* 2 * Copyright (c) 2007, 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 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ 41 42 #include <sys/stat.h> 43 #include <sys/types.h> 44 #include <sys/socket.h> 45 #include <errno.h> 46 #include <stdio.h> 47 #include <string.h> 48 #include <unistd.h> 49 #include <time.h> 50 #include <cstack.h> 51 #include <dirent.h> 52 #include <traverse.h> 53 #include "bitmap.h" 54 #include "ndmpd.h" 55 #include "tlm_buffers.h" 56 57 58 typedef struct ndmp_run_args { 59 char *nr_chkp_nm; 60 char *nr_unchkp_nm; 61 char **nr_excls; 62 } ndmp_run_args_t; 63 64 65 /* 66 * backup_create_structs 67 * 68 * Allocate the structures before performing backup 69 * 70 * Parameters: 71 * sesison (input) - session handle 72 * jname (input) - backup job name 73 * 74 * Returns: 75 * 0: on success 76 * -1: otherwise 77 */ 78 static int 79 backup_create_structs(ndmpd_session_t *session, char *jname) 80 { 81 int n; 82 long xfer_size; 83 ndmp_lbr_params_t *nlp; 84 tlm_commands_t *cmds; 85 86 if ((nlp = ndmp_get_nlp(session)) == NULL) { 87 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 88 return (-1); 89 } 90 91 if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) { 92 NDMP_LOG(LOG_DEBUG, "Creating job stats"); 93 return (-1); 94 } 95 96 cmds = &nlp->nlp_cmds; 97 (void) memset(cmds, 0, sizeof (*cmds)); 98 99 xfer_size = ndmp_buffer_get_size(session); 100 if (xfer_size < 512*KILOBYTE) { 101 /* 102 * Read multiple of mover_record_size near to 512K. This 103 * will prevent the data being copied in the mover buffer 104 * when we write the data. 105 */ 106 if ((n = (512 * KILOBYTE/xfer_size)) <= 0) 107 n = 1; 108 xfer_size *= n; 109 NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d", xfer_size); 110 } 111 112 cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size); 113 if (cmds->tcs_command == NULL) { 114 NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers"); 115 tlm_un_ref_job_stats(jname); 116 return (-1); 117 } 118 119 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session, 120 ndmpd_file_history_path, 121 ndmpd_file_history_dir, 122 ndmpd_file_history_node); 123 if (nlp->nlp_logcallbacks == NULL) { 124 tlm_release_reader_writer_ipc(cmds->tcs_command); 125 tlm_un_ref_job_stats(jname); 126 return (-1); 127 } 128 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks); 129 130 return (0); 131 } 132 133 134 /* 135 * restore_create_structs 136 * 137 * Allocate structures for performing a restore 138 * 139 * Parameters: 140 * sesison (input) - session handle 141 * jname (input) - backup job name 142 * 143 * Returns: 144 * 0: on success 145 * -1: otherwise 146 */ 147 static int 148 restore_create_structs(ndmpd_session_t *session, char *jname) 149 { 150 int i; 151 long xfer_size; 152 ndmp_lbr_params_t *nlp; 153 tlm_commands_t *cmds; 154 155 if ((nlp = ndmp_get_nlp(session)) == NULL) { 156 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 157 return (-1); 158 } 159 if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) { 160 NDMP_LOG(LOG_DEBUG, "Creating job stats"); 161 return (-1); 162 } 163 164 cmds = &nlp->nlp_cmds; 165 (void) memset(cmds, 0, sizeof (*cmds)); 166 167 xfer_size = ndmp_buffer_get_size(session); 168 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size); 169 if (cmds->tcs_command == NULL) { 170 NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers"); 171 tlm_un_ref_job_stats(jname); 172 return (-1); 173 } 174 175 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session, 176 ndmpd_path_restored, NULL, NULL); 177 if (nlp->nlp_logcallbacks == NULL) { 178 tlm_release_reader_writer_ipc(cmds->tcs_command); 179 tlm_un_ref_job_stats(jname); 180 return (-1); 181 } 182 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks); 183 184 nlp->nlp_restored = ndmp_malloc(sizeof (boolean_t) * nlp->nlp_nfiles); 185 if (nlp->nlp_restored == NULL) { 186 lbrlog_callbacks_done(nlp->nlp_logcallbacks); 187 tlm_release_reader_writer_ipc(cmds->tcs_command); 188 tlm_un_ref_job_stats(jname); 189 return (-1); 190 } 191 for (i = 0; i < (int)nlp->nlp_nfiles; i++) 192 nlp->nlp_restored[i] = FALSE; 193 194 return (0); 195 } 196 197 198 /* 199 * send_unrecovered_list 200 * 201 * Creates a list of restored files 202 * 203 * Parameters: 204 * params (input) - NDMP parameters 205 * nlp (input) - NDMP/LBR parameters 206 * 207 * Returns: 208 * 0: on success 209 * -1: otherwise 210 */ 211 static int 212 send_unrecovered_list(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 213 { 214 int i, rv; 215 ndmp_name *ent; 216 217 if (params == NULL) { 218 NDMP_LOG(LOG_DEBUG, "params == NULL"); 219 return (-1); 220 } 221 if (nlp == NULL) { 222 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 223 return (-1); 224 } 225 226 rv = 0; 227 for (i = 0; i < (int)nlp->nlp_nfiles; i++) { 228 NDMP_LOG(LOG_DEBUG, "nlp->nlp_restored[%d]: %s", i, 229 nlp->nlp_restored[i] ? "TRUE" : "FALSE"); 230 231 if (!nlp->nlp_restored[i]) { 232 ent = (ndmp_name *)MOD_GETNAME(params, i); 233 if (ent == NULL) { 234 NDMP_LOG(LOG_DEBUG, "ent == NULL"); 235 rv = -1; 236 break; 237 } 238 if (ent->name == NULL) { 239 NDMP_LOG(LOG_DEBUG, "ent->name == NULL"); 240 rv = -1; 241 break; 242 } 243 244 NDMP_LOG(LOG_DEBUG, "ent.name: \"%s\"", ent->name); 245 246 rv = MOD_FILERECOVERD(params, ent->name, ENOENT); 247 if (rv < 0) 248 break; 249 } 250 } 251 252 return (rv); 253 } 254 255 256 /* 257 * backup_release_structs 258 * 259 * Deallocated the NDMP/LBR specific parameters 260 * 261 * Parameters: 262 * session (input) - session handle 263 * 264 * Returns: 265 * void 266 */ 267 /*ARGSUSED*/ 268 static void 269 backup_release_structs(ndmpd_session_t *session) 270 { 271 ndmp_lbr_params_t *nlp; 272 tlm_commands_t *cmds; 273 274 if ((nlp = ndmp_get_nlp(session)) == NULL) { 275 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 276 return; 277 } 278 cmds = &nlp->nlp_cmds; 279 if (cmds == NULL) { 280 NDMP_LOG(LOG_DEBUG, "cmds == NULL"); 281 return; 282 } 283 284 if (nlp->nlp_logcallbacks != NULL) { 285 lbrlog_callbacks_done(nlp->nlp_logcallbacks); 286 nlp->nlp_logcallbacks = NULL; 287 } else { 288 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL"); 289 } 290 291 if (cmds->tcs_command != NULL) { 292 if (cmds->tcs_command->tc_buffers != NULL) 293 tlm_release_reader_writer_ipc(cmds->tcs_command); 294 else 295 NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL"); 296 cmds->tcs_command = NULL; 297 } else { 298 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL"); 299 } 300 301 if (nlp->nlp_bkmap >= 0) { 302 (void) dbm_free(nlp->nlp_bkmap); 303 nlp->nlp_bkmap = -1; 304 } 305 306 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER && 307 nlp->nlp_restored != NULL) { 308 free(nlp->nlp_restored); 309 nlp->nlp_restored = NULL; 310 } else { 311 NDMP_LOG(LOG_DEBUG, "nlp_restored == NULL"); 312 } 313 } 314 315 /* 316 * ndmp_write_utf8magic 317 * 318 * Write a magic pattern to the tar header. This is used 319 * as a crest to indicate that tape belongs to us. 320 */ 321 int 322 ndmp_write_utf8magic(tlm_cmd_t *cmd) 323 { 324 char *cp; 325 long actual_size; 326 327 if (cmd->tc_buffers == NULL) { 328 NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL"); 329 return (-1); 330 } 331 332 cp = tlm_get_write_buffer(RECORDSIZE, &actual_size, 333 cmd->tc_buffers, TRUE); 334 if (actual_size < RECORDSIZE) { 335 NDMP_LOG(LOG_DEBUG, "Couldn't get enough buffer"); 336 return (-1); 337 } 338 339 (void) strlcpy(cp, NDMPUTF8MAGIC, RECORDSIZE); 340 return (0); 341 } 342 343 344 /* 345 * timecmp 346 * 347 * This callback function is used during backup. It checks 348 * if the object specified by the 'attr' should be backed 349 * up or not. 350 * 351 * Directories are backed up anyways for dump format. 352 * If this function is called, then the directory is 353 * marked in the bitmap vector, it shows that either the 354 * directory itself is modified or there is something below 355 * it that will be backed up. 356 * 357 * Directories for tar format are backed up if and only if 358 * they are modified. 359 * 360 * By setting ndmp_force_bk_dirs global variable to a non-zero 361 * value, directories are backed up anyways. 362 * 363 * Backing up the directories unconditionally, helps 364 * restoring the metadata of directories as well, when one 365 * of the objects below them are being restored. 366 * 367 * For non-directory objects, if the modification or change 368 * time of the object is after the date specified by the 369 * bk_selector_t, the the object must be backed up. 370 * 371 */ 372 static boolean_t 373 timecmp(bk_selector_t *bksp, 374 struct stat64 *attr) 375 { 376 ndmp_lbr_params_t *nlp; 377 378 nlp = (ndmp_lbr_params_t *)bksp->bs_cookie; 379 if (S_ISDIR(attr->st_mode) && ndmp_force_bk_dirs) { 380 NDMP_LOG(LOG_DEBUG, "d(%lu)", 381 (uint_t)attr->st_ino); 382 return (TRUE); 383 } 384 if (S_ISDIR(attr->st_mode) && 385 dbm_getone(nlp->nlp_bkmap, (u_longlong_t)attr->st_ino) && 386 ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) || 387 (NLP_ISTAR(nlp) && ndmp_tar_path_node))) { 388 /* 389 * If the object is a directory and it leads to a modified 390 * object (that should be backed up) and for that type of 391 * backup the path nodes should be backed up, then return 392 * TRUE. 393 * 394 * This is required by some DMAs like Backup Express, which 395 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar) 396 * for the intermediate directories of a modified object. 397 * Other DMAs, like net_backup and net_worker, do not have such 398 * requirement. This requirement makes sense for dump format 399 * but for 'tar' format, it does not. In provision to the 400 * NDMP-v4 spec, for 'tar' format the intermediate directories 401 * need not to be reported. 402 */ 403 NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)attr->st_ino); 404 return (TRUE); 405 } 406 if (attr->st_mtime > bksp->bs_ldate) { 407 NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu", 408 (uint_t)attr->st_ino, (uint_t)attr->st_mtime, 409 (uint_t)bksp->bs_ldate); 410 return (TRUE); 411 } 412 if (attr->st_ctime > bksp->bs_ldate) { 413 if (NLP_IGNCTIME(nlp)) { 414 NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu", 415 (uint_t)attr->st_ino, (uint_t)attr->st_ctime, 416 (uint_t)bksp->bs_ldate); 417 return (FALSE); 418 } 419 NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu", 420 (uint_t)attr->st_ino, (uint_t)attr->st_ctime, 421 (uint_t)bksp->bs_ldate); 422 return (TRUE); 423 } 424 NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu", 425 (uint_t)attr->st_ino, (uint_t)attr->st_mtime, 426 (uint_t)attr->st_ctime, (uint_t)bksp->bs_ldate); 427 return (FALSE); 428 } 429 430 431 /* 432 * get_acl_info 433 * 434 * load up all the access and attribute info 435 */ 436 static int 437 get_acl_info(char *name, tlm_acls_t *tlm_acls) 438 { 439 int erc; 440 acl_t *aclp = NULL; 441 char *acltp; 442 443 erc = lstat64(name, &tlm_acls->acl_attr); 444 if (erc != 0) { 445 NDMP_LOG(LOG_ERR, "Could not find file %s.", name); 446 erc = TLM_NO_SOURCE_FILE; 447 return (erc); 448 } 449 erc = acl_get(name, ACL_NO_TRIVIAL, &aclp); 450 if (erc != 0) { 451 NDMP_LOG(LOG_DEBUG, 452 "Could not read ACL for file [%s]", name); 453 erc = TLM_NO_SOURCE_FILE; 454 return (erc); 455 } 456 if (aclp && (acltp = acl_totext(aclp, 457 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) { 458 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp, 459 TLM_MAX_ACL_TXT); 460 acl_free(aclp); 461 free(acltp); 462 } 463 return (erc); 464 } 465 /* 466 * get_dir_acl_info 467 * 468 * load up all ACL and attr info about a directory 469 */ 470 static int 471 get_dir_acl_info(char *dir, tlm_acls_t *tlm_acls, tlm_job_stats_t *js) 472 { 473 int erc; 474 char *checkpointed_dir; 475 char root_dir[TLM_VOLNAME_MAX_LENGTH]; 476 char *spot; 477 char *fil; 478 acl_t *aclp = NULL; 479 char *acltp; 480 481 checkpointed_dir = ndmp_malloc(TLM_MAX_PATH_NAME); 482 if (checkpointed_dir == NULL) 483 return (-1); 484 485 if (tlm_acls->acl_checkpointed) 486 fil = tlm_build_snapshot_name(dir, checkpointed_dir, 487 js->js_job_name); 488 else 489 fil = dir; 490 erc = lstat64(fil, &tlm_acls->acl_attr); 491 if (erc != 0) { 492 NDMP_LOG(LOG_ERR, "Could not find directory %s.", dir); 493 free(checkpointed_dir); 494 return (-1); 495 } 496 497 spot = strchr(&fil[1], '/'); 498 if (spot == NULL) { 499 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH); 500 } else { 501 *spot = 0; 502 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH); 503 *spot = '/'; 504 } 505 if (strcmp(root_dir, tlm_acls->acl_root_dir) != 0) { 506 struct stat64 attr; 507 508 erc = lstat64(root_dir, &attr); 509 if (erc != 0) { 510 NDMP_LOG(LOG_ERR, "Cannot find root directory %s.", 511 root_dir); 512 free(checkpointed_dir); 513 return (-1); 514 } 515 (void) strlcpy(tlm_acls->acl_root_dir, root_dir, 516 TLM_VOLNAME_MAX_LENGTH); 517 } 518 erc = acl_get(fil, ACL_NO_TRIVIAL, &aclp); 519 if (erc != 0) { 520 NDMP_LOG(LOG_DEBUG, 521 "Could not read metadata for directory [%s]", dir); 522 free(checkpointed_dir); 523 return (-1); 524 } 525 if (aclp && (acltp = acl_totext(aclp, 526 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) { 527 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp, 528 TLM_MAX_ACL_TXT); 529 acl_free(aclp); 530 free(acltp); 531 } 532 533 free(checkpointed_dir); 534 return (0); 535 } 536 537 /* 538 * backup_dir 539 * 540 * Create a TAR entry record for a directory 541 */ 542 static int 543 backup_dir(char *dir, tlm_acls_t *tlm_acls, 544 tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats, 545 bk_selector_t *bksp) 546 { 547 int erc; 548 549 NDMP_LOG(LOG_DEBUG, "\"%s\"", dir); 550 551 erc = get_dir_acl_info(dir, tlm_acls, job_stats); 552 if (erc != 0) { 553 NDMP_LOG(LOG_DEBUG, 554 "Could not read directory info for %s", dir); 555 job_stats->js_errors++; 556 } else { 557 /* 558 * See if the directory must be backed up. 559 */ 560 if (bksp && !(*bksp->bs_fn)(bksp, &tlm_acls->acl_attr)) { 561 NDMP_LOG(LOG_DEBUG, "[%s] dir skipped", dir); 562 return (erc); 563 } 564 565 if (tm_tar_ops.tm_putdir != NULL) 566 (void) (tm_tar_ops.tm_putdir)(dir, tlm_acls, 567 local_commands, job_stats); 568 } 569 570 return (erc); 571 } 572 573 574 /* 575 * backup_file 576 * 577 * Create a TAR record entry for a file 578 */ 579 static longlong_t 580 backup_file(char *dir, char *name, tlm_acls_t *tlm_acls, 581 tlm_commands_t *commands, tlm_cmd_t *local_commands, 582 tlm_job_stats_t *job_stats, bk_selector_t *bksp) 583 { 584 585 int erc; 586 char buf[TLM_MAX_PATH_NAME]; 587 longlong_t rv; 588 589 NDMP_LOG(LOG_DEBUG, "\"%s/%s\"", dir, name); 590 591 (void) strlcpy(buf, dir, sizeof (buf)); 592 (void) strlcat(buf, "/", sizeof (buf)); 593 (void) strlcat(buf, name, sizeof (buf)); 594 595 /* 596 * get_acl_info extracts file handle, attributes and ACLs of the file. 597 * This is not efficient when the attributes and file handle of 598 * the file is already known. 599 */ 600 erc = get_acl_info(buf, tlm_acls); 601 if (erc != TLM_NO_ERRORS) { 602 NDMP_LOG(LOG_ERR, "Could not open file %s/%s.", dir, name); 603 return (-ENOENT); 604 } 605 606 /* Should the file be backed up? */ 607 if (!bksp) { 608 NDMP_LOG(LOG_DEBUG, 609 "[%s/%s] has no selection criteria", dir, name); 610 611 } else if (!((*bksp->bs_fn)(bksp, &tlm_acls->acl_attr))) { 612 NDMP_LOG(LOG_DEBUG, "[%s/%s] file skipped", dir, name); 613 return (0); 614 } 615 616 /* Only the regular files and symbolic links can be backed up. */ 617 if (!S_ISLNK(tlm_acls->acl_attr.st_mode) && 618 !S_ISREG(tlm_acls->acl_attr.st_mode)) { 619 NDMP_LOG(LOG_DEBUG, 620 "Warning: skip backing up [%s][%s]", dir, name); 621 return (-EINVAL); 622 } 623 624 625 if (tm_tar_ops.tm_putfile != NULL) 626 rv = (tm_tar_ops.tm_putfile)(dir, name, tlm_acls, commands, 627 local_commands, job_stats); 628 629 return (rv); 630 } 631 632 633 634 /* 635 * backup_work 636 * 637 * Start the NDMP backup (V2 only). 638 */ 639 int 640 backup_work(char *bk_path, tlm_job_stats_t *job_stats, 641 ndmp_run_args_t *np, tlm_commands_t *commands, 642 ndmp_lbr_params_t *nlp) 643 { 644 struct full_dir_info dir_info; /* the blob to push/pop with cstack_t */ 645 struct full_dir_info *t_dir_info, *p_dir_info; 646 struct stat64 ret_attr; /* attributes of current file name */ 647 fs_fhandle_t ret_fh; 648 char *first_name; /* where the first name is located */ 649 char *dname; 650 int erc; 651 int retval; 652 cstack_t *stk; 653 unsigned long fileid; 654 tlm_acls_t tlm_acls; 655 int dname_size; 656 longlong_t fsize; 657 bk_selector_t bks; 658 tlm_cmd_t *local_commands; 659 long dpos; 660 661 NDMP_LOG(LOG_DEBUG, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"", 662 NLP_ISCHKPNTED(nlp), nlp->nlp_ldate, bk_path); 663 664 /* Get every name in this directory */ 665 dname = ndmp_malloc(TLM_MAX_PATH_NAME); 666 if (dname == NULL) 667 return (-ENOMEM); 668 669 local_commands = commands->tcs_command; 670 retval = 0; 671 (void) memset(&bks, 0, sizeof (bks)); 672 bks.bs_cookie = (void *)nlp; 673 bks.bs_level = nlp->nlp_clevel; 674 bks.bs_ldate = nlp->nlp_ldate; 675 bks.bs_fn = timecmp; 676 677 /* 678 * should we skip the whole thing? 679 */ 680 if (tlm_is_excluded("", bk_path, np->nr_excls)) { 681 NDMP_LOG(LOG_DEBUG, "%s excluded", bk_path); 682 free(dname); 683 return (0); 684 } 685 686 /* 687 * Search for the top-level file-directory 688 */ 689 if (NLP_ISCHKPNTED(nlp)) { 690 first_name = np->nr_chkp_nm; 691 (void) strlcpy(first_name, bk_path, TLM_MAX_PATH_NAME); 692 } else { 693 first_name = tlm_build_snapshot_name(bk_path, np->nr_chkp_nm, 694 nlp->nlp_jstat->js_job_name); 695 } 696 697 (void) memset(&ret_fh, 0, sizeof (ret_fh)); 698 erc = fs_getstat(first_name, &ret_fh, &ret_attr); 699 if (erc != 0) { 700 NDMP_LOG(LOG_ERR, "Path %s not found.", first_name); 701 free(dname); 702 return (-EINVAL); 703 } 704 705 if ((stk = cstack_new()) == NULL) { 706 free(dname); 707 NDMP_LOG(LOG_DEBUG, "cstack_new failed"); 708 return (-ENOMEM); 709 } 710 (void) strlcpy(dir_info.fd_dir_name, first_name, TLM_MAX_PATH_NAME); 711 (void) memcpy(&dir_info.fd_dir_fh, &ret_fh, sizeof (fs_fhandle_t)); 712 p_dir_info = dup_dir_info(&dir_info); 713 714 /* 715 * Push the first name onto the stack so that we can pop it back 716 * off as part of the normal cycle 717 */ 718 if (cstack_push(stk, p_dir_info, 0)) { 719 free(dname); 720 free(p_dir_info); 721 cstack_delete(stk); 722 NDMP_LOG(LOG_DEBUG, "cstack_push failed"); 723 return (-ENOMEM); 724 } 725 726 (void) memset(&tlm_acls, 0, sizeof (tlm_acls)); 727 /* 728 * Did NDMP create a checkpoint? 729 */ 730 if (NLP_ISCHKPNTED(nlp) || fs_is_rdonly(bk_path)) { 731 tlm_acls.acl_checkpointed = FALSE; 732 } else { 733 /* Use the checkpoint created by NDMP */ 734 tlm_acls.acl_checkpointed = TRUE; 735 } 736 737 /* 738 * This is level-backup. It never resets the archive bit. 739 */ 740 tlm_acls.acl_clear_archive = FALSE; 741 742 NDMP_LOG(LOG_DEBUG, "acls.chkpnt: %c acls.clear_arcbit: %c", 743 NDMP_YORN(tlm_acls.acl_checkpointed), 744 NDMP_YORN(tlm_acls.acl_clear_archive)); 745 746 while (commands->tcs_reader == TLM_BACKUP_RUN && 747 local_commands->tc_reader == TLM_BACKUP_RUN && 748 cstack_pop(stk, (void **)&p_dir_info, 0) == 0) { 749 750 if (NLP_ISCHKPNTED(nlp)) 751 (void) strlcpy(np->nr_unchkp_nm, 752 p_dir_info->fd_dir_name, TLM_MAX_PATH_NAME); 753 else 754 (void) tlm_remove_checkpoint(p_dir_info->fd_dir_name, 755 np->nr_unchkp_nm); 756 757 (void) backup_dir(np->nr_unchkp_nm, &tlm_acls, local_commands, 758 job_stats, &bks); 759 760 761 while (commands->tcs_reader == TLM_BACKUP_RUN && 762 local_commands->tc_reader == TLM_BACKUP_RUN) { 763 764 dname_size = TLM_MAX_PATH_NAME - 1; 765 766 NDMP_LOG(LOG_DEBUG, 767 "dir_name: %s", p_dir_info->fd_dir_name); 768 769 (void) memset(&ret_fh, 0, sizeof (ret_fh)); 770 erc = fs_readdir(&p_dir_info->fd_dir_fh, 771 p_dir_info->fd_dir_name, &dpos, 772 dname, &dname_size, &ret_fh, &ret_attr); 773 if (erc == 0) { 774 fileid = ret_fh.fh_fid; 775 } else { 776 NDMP_LOG(LOG_DEBUG, 777 "Filesystem readdir in [%s]", 778 p_dir_info->fd_dir_name); 779 retval = -ENOENT; 780 break; 781 } 782 783 /* an empty name size marks the end of the list */ 784 if (dname_size == 0) 785 break; 786 dname[dname_size] = '\0'; 787 788 NDMP_LOG(LOG_DEBUG, "dname: \"%s\"", dname); 789 790 /* 791 * If name refers to a directory, push its file 792 * handle onto the stack (skip "." and ".."). 793 */ 794 if (rootfs_dot_or_dotdot(dname)) { 795 fileid = 0; 796 continue; 797 } 798 799 /* 800 * Skip the: 801 * non-dir entries which should not be backed up 802 * Or 803 * dir-type entries which have have nothing under 804 * their hierarchy to be backed up. 805 */ 806 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)fileid)) { 807 NDMP_LOG(LOG_DEBUG, "Skipping %s/%s", 808 p_dir_info->fd_dir_name, dname); 809 fileid = 0; 810 continue; 811 } 812 813 if (tlm_is_excluded(np->nr_unchkp_nm, dname, 814 np->nr_excls)) { 815 fileid = 0; 816 continue; 817 } 818 if (S_ISDIR(ret_attr.st_mode)) { 819 /* 820 * only directories get pushed onto this stack, 821 * so we do not have to test for regular files. 822 */ 823 t_dir_info = tlm_new_dir_info(&ret_fh, 824 p_dir_info->fd_dir_name, dname); 825 if (t_dir_info == NULL) { 826 NDMP_LOG(LOG_DEBUG, 827 "While backing up [%s][%s]", 828 p_dir_info->fd_dir_name, dname); 829 } else if (cstack_push(stk, t_dir_info, 830 0) != 0) { 831 NDMP_LOG(LOG_DEBUG, 832 "No enough memory stack_push"); 833 retval = -ENOMEM; 834 break; 835 } 836 } else if (S_ISREG(ret_attr.st_mode) || 837 S_ISLNK(ret_attr.st_mode)) { 838 839 fsize = backup_file(np->nr_unchkp_nm, dname, 840 &tlm_acls, commands, local_commands, 841 job_stats, &bks); 842 843 if (fsize >= 0) { 844 job_stats->js_files_so_far++; 845 job_stats->js_bytes_total += fsize; 846 } else 847 job_stats->js_errors++; 848 fileid = 0; 849 } 850 } 851 fileid = 0; 852 free(p_dir_info); 853 if (retval != 0) 854 break; 855 } 856 857 free(dname); 858 859 while (cstack_pop(stk, (void **)&p_dir_info, 0) == 0) { 860 free(p_dir_info); 861 } 862 863 cstack_delete(stk); 864 return (retval); 865 } 866 867 868 /* 869 * free_paths 870 * 871 * Free the path names 872 */ 873 static void 874 free_paths(ndmp_run_args_t *np) 875 { 876 free(np->nr_chkp_nm); 877 free(np->nr_unchkp_nm); 878 free(np->nr_excls); 879 } 880 881 882 /* 883 * malloc_paths 884 * 885 * Allocate the path names (direct and checkpointed paths) 886 */ 887 static boolean_t 888 malloc_paths(ndmp_run_args_t *np) 889 { 890 boolean_t rv; 891 892 rv = TRUE; 893 np->nr_chkp_nm = ndmp_malloc(TLM_MAX_PATH_NAME); 894 np->nr_unchkp_nm = ndmp_malloc(TLM_MAX_PATH_NAME); 895 if (!np->nr_chkp_nm || !np->nr_unchkp_nm) { 896 free_paths(np); 897 rv = FALSE; 898 } else if ((np->nr_excls = ndmpd_make_exc_list()) == NULL) { 899 free_paths(np); 900 rv = FALSE; 901 } 902 return (rv); 903 } 904 905 906 /* 907 * ndmp_backup_reader 908 * 909 * Backup reader thread which uses backup_work to read and TAR 910 * the files/dirs to be backed up (V2 only) 911 */ 912 static int 913 ndmp_backup_reader(tlm_commands_t *commands, ndmp_lbr_params_t *nlp, 914 char *job_name) 915 { 916 int retval; 917 ndmp_run_args_t np; 918 tlm_job_stats_t *job_stats; 919 tlm_cmd_t *local_commands; 920 921 NDMP_LOG(LOG_DEBUG, "bk_path: \"%s\"", nlp->nlp_backup_path); 922 923 local_commands = commands->tcs_command; 924 (void) memset(&np, 0, sizeof (np)); 925 if (!malloc_paths(&np)) 926 return (-1); 927 local_commands->tc_ref++; 928 commands->tcs_reader_count++; 929 930 job_stats = tlm_ref_job_stats(job_name); 931 932 retval = backup_work(nlp->nlp_backup_path, job_stats, &np, 933 commands, nlp); 934 write_tar_eof(local_commands); 935 936 commands->tcs_reader_count--; 937 local_commands->tc_writer = TLM_STOP; 938 tlm_release_reader_writer_ipc(local_commands); 939 tlm_un_ref_job_stats(job_name); 940 941 free_paths(&np); 942 return (retval); 943 944 } 945 946 947 /* 948 * ndmp_tar_writer 949 * 950 * The backup writer thread that writes the TAR records to the 951 * tape media (V2 only) 952 */ 953 int 954 ndmp_tar_writer(ndmpd_session_t *session, ndmpd_module_params_t *mod_params, 955 tlm_commands_t *cmds) 956 { 957 int bidx, nw; 958 int err; 959 tlm_buffer_t *buf; 960 tlm_buffers_t *bufs; 961 tlm_cmd_t *lcmd; /* Local command */ 962 963 err = 0; 964 if (session == NULL) { 965 NDMP_LOG(LOG_DEBUG, "session == NULL"); 966 err = -1; 967 } else if (mod_params == NULL) { 968 NDMP_LOG(LOG_DEBUG, "mod_params == NULL"); 969 err = -1; 970 } else if (cmds == NULL) { 971 NDMP_LOG(LOG_DEBUG, "cmds == NULL"); 972 err = -1; 973 } 974 975 if (err != 0) 976 return (err); 977 978 lcmd = cmds->tcs_command; 979 bufs = lcmd->tc_buffers; 980 981 lcmd->tc_ref++; 982 cmds->tcs_writer_count++; 983 984 nw = 0; 985 buf = tlm_buffer_out_buf(bufs, &bidx); 986 while (cmds->tcs_writer != (int)TLM_ABORT && 987 lcmd->tc_writer != (int)TLM_ABORT) { 988 if (buf->tb_full) { 989 NDMP_LOG(LOG_DEBUG, "w%d", bidx); 990 991 if (MOD_WRITE(mod_params, buf->tb_buffer_data, 992 buf->tb_buffer_size) != 0) { 993 NDMP_LOG(LOG_DEBUG, 994 "Writing buffer %d, pos: %lld", 995 bidx, session->ns_mover.md_position); 996 err = -1; 997 break; 998 } 999 1000 tlm_buffer_mark_empty(buf); 1001 (void) tlm_buffer_advance_out_idx(bufs); 1002 buf = tlm_buffer_out_buf(bufs, &bidx); 1003 tlm_buffer_release_out_buf(bufs); 1004 nw++; 1005 } else { 1006 if (lcmd->tc_writer != TLM_BACKUP_RUN) { 1007 /* No more data is comming; time to exit. */ 1008 NDMP_LOG(LOG_DEBUG, 1009 "tc_writer!=TLM_BACKUP_RUN; time to exit"); 1010 break; 1011 } else { 1012 NDMP_LOG(LOG_DEBUG, "W%d", bidx); 1013 tlm_buffer_in_buf_timed_wait(bufs, 100); 1014 } 1015 } 1016 } 1017 1018 NDMP_LOG(LOG_DEBUG, "nw: %d", nw); 1019 if (cmds->tcs_writer != (int)TLM_ABORT) { 1020 NDMP_LOG(LOG_DEBUG, "tcs_writer != TLM_ABORT"); 1021 } else { 1022 NDMP_LOG(LOG_DEBUG, "tcs_writer == TLM_ABORT"); 1023 } 1024 1025 if (lcmd->tc_writer != (int)TLM_ABORT) { 1026 NDMP_LOG(LOG_DEBUG, "tc_writer != TLM_ABORT"); 1027 } else { 1028 NDMP_LOG(LOG_DEBUG, "tc_writer == TLM_ABORT"); 1029 } 1030 cmds->tcs_writer_count--; 1031 lcmd->tc_reader = TLM_STOP; 1032 lcmd->tc_ref--; 1033 1034 return (err); 1035 } 1036 1037 1038 /* 1039 * read_one_buf 1040 * 1041 * Read one buffer from the tape 1042 */ 1043 static int 1044 read_one_buf(ndmpd_module_params_t *mod_params, tlm_buffers_t *bufs, 1045 tlm_buffer_t *buf) 1046 { 1047 int rv; 1048 1049 if ((rv = MOD_READ(mod_params, buf->tb_buffer_data, 1050 bufs->tbs_data_transfer_size)) == 0) { 1051 buf->tb_eof = buf->tb_eot = FALSE; 1052 buf->tb_errno = 0; 1053 buf->tb_buffer_size = bufs->tbs_data_transfer_size; 1054 buf->tb_buffer_spot = 0; 1055 buf->tb_full = TRUE; 1056 (void) tlm_buffer_advance_in_idx(bufs); 1057 } 1058 1059 return (rv); 1060 } 1061 1062 1063 /* 1064 * ndmp_tar_reader 1065 * 1066 * NDMP Tar reader thread. This threads keep reading the tar 1067 * file from the tape and wakes up the consumer thread to extract 1068 * it on the disk 1069 */ 1070 int 1071 ndmp_tar_reader(ndmp_tar_reader_arg_t *argp) 1072 { 1073 int bidx; 1074 int err; 1075 tlm_buffer_t *buf; 1076 tlm_buffers_t *bufs; 1077 tlm_cmd_t *lcmd; /* Local command */ 1078 ndmpd_session_t *session; 1079 ndmpd_module_params_t *mod_params; 1080 tlm_commands_t *cmds; 1081 1082 if (!argp) 1083 return (-1); 1084 1085 session = argp->tr_session; 1086 mod_params = argp->tr_mod_params; 1087 cmds = argp->tr_cmds; 1088 1089 err = 0; 1090 if (session == NULL) { 1091 NDMP_LOG(LOG_DEBUG, "session == NULL"); 1092 err = -1; 1093 } else if (cmds == NULL) { 1094 NDMP_LOG(LOG_DEBUG, "cmds == NULL"); 1095 err = -1; 1096 } 1097 1098 if (err != 0) { 1099 tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER); 1100 return (err); 1101 } 1102 1103 lcmd = cmds->tcs_command; 1104 bufs = lcmd->tc_buffers; 1105 1106 lcmd->tc_ref++; 1107 cmds->tcs_reader_count++; 1108 1109 /* 1110 * Synchronize with our parent thread. 1111 */ 1112 tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER); 1113 1114 buf = tlm_buffer_in_buf(bufs, &bidx); 1115 while (cmds->tcs_reader == TLM_RESTORE_RUN && 1116 lcmd->tc_reader == TLM_RESTORE_RUN) { 1117 1118 if (buf->tb_full) { 1119 NDMP_LOG(LOG_DEBUG, "R%d", bidx); 1120 /* 1121 * The buffer is still full, wait for the consumer 1122 * thread to use it. 1123 */ 1124 tlm_buffer_out_buf_timed_wait(bufs, 100); 1125 buf = tlm_buffer_in_buf(bufs, NULL); 1126 } else { 1127 NDMP_LOG(LOG_DEBUG, "r%d", bidx); 1128 1129 err = read_one_buf(mod_params, bufs, buf); 1130 if (err < 0) { 1131 NDMP_LOG(LOG_DEBUG, 1132 "Reading buffer %d, pos: %lld", 1133 bidx, session->ns_mover.md_position); 1134 1135 /* Force the writer to stop. */ 1136 buf->tb_eot = buf->tb_eof = TRUE; 1137 break; 1138 } else if (err == 1) { 1139 NDMP_LOG(LOG_DEBUG, 1140 "operation aborted or session terminated"); 1141 err = 0; 1142 break; 1143 } 1144 1145 buf = tlm_buffer_in_buf(bufs, &bidx); 1146 tlm_buffer_release_in_buf(bufs); 1147 } 1148 } 1149 1150 /* 1151 * If the consumer is waiting for us, wake it up so that it detects 1152 * we're quiting. 1153 */ 1154 lcmd->tc_writer = TLM_STOP; 1155 tlm_buffer_release_in_buf(bufs); 1156 (void) usleep(1000); 1157 1158 /* 1159 * Clean up. 1160 */ 1161 cmds->tcs_reader_count--; 1162 lcmd->tc_ref--; 1163 return (err); 1164 } 1165 1166 1167 /* 1168 * ndmpd_tar_backup 1169 * 1170 * Check must have been done that backup work directory exists, before 1171 * calling this function. 1172 */ 1173 static int 1174 ndmpd_tar_backup(ndmpd_session_t *session, ndmpd_module_params_t *mod_params, 1175 ndmp_lbr_params_t *nlp) 1176 { 1177 char jname[TLM_MAX_BACKUP_JOB_NAME]; 1178 int err; 1179 tlm_commands_t *cmds; 1180 1181 if (mod_params->mp_operation != NDMP_DATA_OP_BACKUP) { 1182 NDMP_LOG(LOG_DEBUG, 1183 "mod_params->mp_operation != NDMP_DATA_OP_BACKUP"); 1184 err = -1; 1185 } else { 1186 if (ndmpd_mark_inodes_v2(session, nlp) != 0) 1187 err = -1; 1188 else if (ndmp_get_bk_dir_ino(nlp)) 1189 err = -1; 1190 else 1191 err = 0; 1192 } 1193 1194 if (err != 0) 1195 return (err); 1196 1197 (void) ndmp_new_job_name(jname); 1198 if (backup_create_structs(session, jname) < 0) 1199 return (-1); 1200 1201 nlp->nlp_jstat->js_start_ltime = time(NULL); 1202 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime; 1203 nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate; 1204 1205 if (!session->ns_data.dd_abort) { 1206 1207 cmds = &nlp->nlp_cmds; 1208 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN; 1209 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN; 1210 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN; 1211 1212 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) { 1213 backup_release_structs(session); 1214 return (-1); 1215 } 1216 1217 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" started.", 1218 nlp->nlp_backup_path); 1219 1220 err = ndmp_backup_reader(cmds, nlp, jname); 1221 if (err != 0) { 1222 backup_release_structs(session); 1223 NDMP_LOG(LOG_DEBUG, "Launch ndmp_backup_reader: %s", 1224 strerror(err)); 1225 return (-1); 1226 } 1227 1228 /* Act as the writer thread. */ 1229 err = ndmp_tar_writer(session, mod_params, cmds); 1230 1231 nlp->nlp_jstat->js_stop_time = time(NULL); 1232 1233 NDMP_LOG(LOG_DEBUG, 1234 "Runtime [%s] %llu bytes (%llu): %d seconds", 1235 nlp->nlp_backup_path, session->ns_mover.md_data_written, 1236 session->ns_mover.md_data_written, 1237 nlp->nlp_jstat->js_stop_time - 1238 nlp->nlp_jstat->js_start_ltime); 1239 MOD_LOG(mod_params, 1240 "Runtime [%s] %llu bytes (%llu): %d seconds", 1241 nlp->nlp_backup_path, session->ns_mover.md_data_written, 1242 session->ns_mover.md_data_written, 1243 nlp->nlp_jstat->js_stop_time - 1244 nlp->nlp_jstat->js_start_ltime); 1245 1246 if (session->ns_data.dd_abort) 1247 err = -1; 1248 1249 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished. (%d)", 1250 nlp->nlp_backup_path, err); 1251 } else { 1252 nlp->nlp_jstat->js_stop_time = time(NULL); 1253 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.", 1254 nlp->nlp_backup_path); 1255 err = 0; 1256 } 1257 1258 backup_release_structs(session); 1259 return (err); 1260 } 1261 1262 1263 /* 1264 * ndmpd_tar_restore 1265 * 1266 * Restore function that launches TAR reader thread to read from the 1267 * tape and writes the extracted files/dirs to the filesystem 1268 */ 1269 static int 1270 ndmpd_tar_restore(ndmpd_session_t *session, ndmpd_module_params_t *mod_params, 1271 ndmp_lbr_params_t *nlp) 1272 { 1273 char jname[TLM_MAX_BACKUP_JOB_NAME]; 1274 char *rspath; 1275 int err; 1276 tlm_commands_t *cmds; 1277 ndmp_tar_reader_arg_t arg; 1278 tlm_backup_restore_arg_t tlm_arg; 1279 ndmp_name *ent; 1280 pthread_t rdtp, wrtp; 1281 int i; 1282 1283 if (mod_params->mp_operation != NDMP_DATA_OP_RECOVER) { 1284 NDMP_LOG(LOG_DEBUG, 1285 "mod_params->mp_operation != NDMP_DATA_OP_RECOVER"); 1286 return (-1); 1287 } 1288 1289 if (nlp->nlp_restore_path[0] != '\0') 1290 rspath = nlp->nlp_restore_path; 1291 else if (nlp->nlp_restore_bk_path[0] != '\0') 1292 rspath = nlp->nlp_restore_bk_path; 1293 else 1294 rspath = ""; 1295 1296 (void) ndmp_new_job_name(jname); 1297 if (restore_create_structs(session, jname) < 0) 1298 return (-1); 1299 1300 nlp->nlp_jstat->js_start_ltime = time(NULL); 1301 nlp->nlp_jstat->js_start_time = time(NULL); 1302 1303 if (!session->ns_data.dd_abort) { 1304 cmds = &nlp->nlp_cmds; 1305 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN; 1306 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN; 1307 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN; 1308 1309 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.", rspath); 1310 NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).", 1311 ndmp_data_get_mover_mode(session)); 1312 1313 arg.tr_session = session; 1314 arg.tr_mod_params = mod_params; 1315 arg.tr_cmds = cmds; 1316 1317 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader, 1318 (void *)&arg); 1319 if (err == 0) { 1320 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER); 1321 } else { 1322 NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m"); 1323 return (-1); 1324 } 1325 1326 if (!ndmp_check_utf8magic(cmds->tcs_command)) { 1327 NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!"); 1328 } else { 1329 NDMP_LOG(LOG_DEBUG, "UTF8Magic found"); 1330 } 1331 1332 (void) memset(&tlm_arg, 0, sizeof (tlm_backup_restore_arg_t)); 1333 (void) pthread_barrier_init(&tlm_arg.ba_barrier, 0, 2); 1334 1335 /* 1336 * Set up restore parameters 1337 */ 1338 tlm_arg.ba_commands = cmds; 1339 tlm_arg.ba_cmd = cmds->tcs_command; 1340 tlm_arg.ba_job = nlp->nlp_jstat->js_job_name; 1341 tlm_arg.ba_dir = nlp->nlp_restore_path; 1342 for (i = 0; i < nlp->nlp_nfiles; i++) { 1343 ent = (ndmp_name *)MOD_GETNAME(mod_params, i); 1344 tlm_arg.ba_sels[i] = ent->name; 1345 } 1346 1347 1348 if (tm_tar_ops.tm_getfile != NULL) { 1349 err = pthread_create(&wrtp, NULL, 1350 (funct_t)tm_tar_ops.tm_getfile, (void *)&tlm_arg); 1351 } else { 1352 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier); 1353 NDMP_LOG(LOG_DEBUG, 1354 "Thread create tm_getfile: ops NULL"); 1355 return (-1); 1356 } 1357 if (err == 0) { 1358 (void) pthread_barrier_wait(&tlm_arg.ba_barrier); 1359 } else { 1360 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier); 1361 NDMP_LOG(LOG_DEBUG, "thread create tm_getfile: %m"); 1362 return (-1); 1363 } 1364 1365 (void) pthread_join(rdtp, NULL); 1366 (void) pthread_join(wrtp, NULL); 1367 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier); 1368 1369 nlp->nlp_jstat->js_stop_time = time(NULL); 1370 1371 /* Send the list of un-recovered files/dirs to the client. */ 1372 (void) send_unrecovered_list(mod_params, nlp); 1373 1374 ndmp_stop_local_reader(session, cmds); 1375 ndmp_wait_for_reader(cmds); 1376 ndmp_stop_remote_reader(session); 1377 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)", 1378 rspath, err); 1379 } else { 1380 nlp->nlp_jstat->js_stop_time = time(NULL); 1381 1382 /* nothing restored. */ 1383 (void) send_unrecovered_list(mod_params, nlp); 1384 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.", 1385 rspath); 1386 err = -1; 1387 } 1388 1389 NDMP_FREE(nlp->nlp_restore_path); 1390 backup_release_structs(session); 1391 1392 return (err); 1393 } 1394 1395 1396 /* 1397 * prefixdir 1398 * 1399 * Extract the path for a given full path entry 1400 */ 1401 static char * 1402 prefixdir(char *dir, char *suffix) 1403 { 1404 static char tmp[TLM_MAX_PATH_NAME]; 1405 char *tend, *send; /* tmp and suffix end */ 1406 1407 if (dir == NULL || suffix == NULL) 1408 return (NULL); 1409 1410 if (*suffix == '\0') 1411 return (dir); 1412 1413 if (*dir == '\0') 1414 return (NULL); 1415 1416 (void) strlcpy(tmp, dir, TLM_MAX_PATH_NAME); 1417 tend = &tmp[strlen(tmp)]; 1418 send = &suffix[strlen(suffix)]; 1419 1420 /* 1421 * Move backward as far as the last part of the dir and 1422 * the suffix match. 1423 */ 1424 while (tend >= tmp && send >= suffix) 1425 if (*tend == *send) 1426 tend--, send--; 1427 else 1428 break; 1429 1430 *++tend = '\0'; 1431 return (tmp); 1432 } 1433 1434 1435 /* 1436 * get_nfiles 1437 * 1438 * Get the count of files to be restored 1439 */ 1440 static int 1441 get_nfiles(ndmpd_session_t *session, ndmpd_module_params_t *params) 1442 { 1443 if (session->ns_data.dd_nlist_len == 0) { 1444 MOD_LOG(params, "Error: nothing specified to be restored.\n"); 1445 return (-1); 1446 } 1447 1448 return (session->ns_data.dd_nlist_len); 1449 } 1450 1451 1452 /* 1453 * get_restore_dest 1454 * 1455 * Get the full pathname of where the entries should be restored to. 1456 */ 1457 static char * 1458 get_restore_dest(ndmpd_module_params_t *params) 1459 { 1460 ndmp_name *ent; 1461 char *cp; 1462 1463 /* 1464 * Destination of restore: 1465 * NetBackup of Veritas(C) sends the entries like this: 1466 * 1467 * ent[i].name: is the relative pathname of what is selected in 1468 * the GUI. 1469 * ent[i].dest: is the full pathname of where the dir/file must 1470 * be restored to. 1471 * ent[i].ssi: 0 1472 * ent[i].fh_info: 0 1473 * 1474 */ 1475 ent = (ndmp_name *)MOD_GETNAME(params, 0); 1476 cp = prefixdir(ent->dest, ent->name); 1477 if (cp == NULL) { 1478 MOD_LOG(params, "Error: empty restore path.\n"); 1479 return (NULL); 1480 } 1481 1482 return (cp); 1483 } 1484 1485 1486 /* 1487 * correct_ents 1488 * 1489 * Correct the entries in the restore list by appending the appropriate 1490 * path to them 1491 */ 1492 static int 1493 correct_ents(ndmpd_module_params_t *params, int n, char *bkpath) 1494 { 1495 char *cp, *pathname; 1496 int i, len, rv; 1497 ndmp_name *ent; 1498 1499 if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) { 1500 MOD_LOG(params, "Error: insufficient memory.\n"); 1501 return (-1); 1502 } 1503 1504 rv = 0; 1505 /* Append the backup path to all the "ent[].name"s. */ 1506 for (i = 0; i < n; i++) { 1507 ent = (ndmp_name *)MOD_GETNAME(params, i); 1508 1509 NDMP_LOG(LOG_DEBUG, 1510 "Old: ent[%d].name: \"%s\"", i, ent->name); 1511 NDMP_LOG(LOG_DEBUG, 1512 "Old: ent[%d].dest: \"%s\"", i, ent->dest); 1513 1514 /* remove trailing slash */ 1515 len = strlen(ent->name); 1516 if (ent->name[len - 1] == '/') 1517 ent->name[len - 1] = '\0'; 1518 1519 if (!tlm_cat_path(pathname, bkpath, ent->name)) { 1520 MOD_LOG(params, "Error: path too long.\n"); 1521 rv = -1; 1522 break; 1523 } 1524 1525 /* Make a copy of the new string and save it in ent->name. */ 1526 cp = strdup(pathname); 1527 if (cp == NULL) { 1528 MOD_LOG(params, "Error: insufficient memory.\n"); 1529 rv = -1; 1530 break; 1531 } 1532 free(ent->name); 1533 ent->name = cp; 1534 1535 NDMP_LOG(LOG_DEBUG, 1536 "New: ent[%d].name: \"%s\"", i, ent->name); 1537 } 1538 1539 free(pathname); 1540 return (rv); 1541 } 1542 1543 1544 /* 1545 * check_restore_paths 1546 * 1547 * Go through the restore list and check the validity of the 1548 * restore path. 1549 */ 1550 static int 1551 check_restore_paths(ndmpd_module_params_t *params, int n, char *rspath) 1552 { 1553 int i, rv; 1554 ndmp_name *ent; 1555 1556 rv = 0; 1557 if (rspath != NULL && *rspath != '\0') { 1558 NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", rspath); 1559 if (!fs_volexist(rspath)) { 1560 MOD_LOG(params, 1561 "Error: Invalid volume name for restore."); 1562 rv = -1; 1563 } 1564 } else { 1565 for (i = 0; i < n; i++) { 1566 ent = (ndmp_name *)MOD_GETNAME(params, i); 1567 NDMP_LOG(LOG_DEBUG, 1568 "ent[%d].name: \"%s\"", i, ent->name); 1569 1570 if (!fs_volexist(ent->name)) { 1571 MOD_LOG(params, 1572 "Error: Invalid volume name for restore.", 1573 ent->name); 1574 rv = -1; 1575 break; 1576 } 1577 } 1578 } 1579 1580 return (rv); 1581 } 1582 1583 1584 /* 1585 * check_backup_dir_validity 1586 * 1587 * Check if the backup directory is valid. Make sure it exists and 1588 * is writable. Check for snapshot and readonly cases. 1589 */ 1590 static int 1591 check_backup_dir_validity(ndmpd_module_params_t *params, char *bkpath) 1592 { 1593 char *msg; 1594 int rv; 1595 struct stat64 st; 1596 1597 rv = NDMP_NO_ERR; 1598 if (stat64(bkpath, &st) < 0) { 1599 msg = strerror(errno); 1600 MOD_LOG(params, "Error: stat(%s): %s.\n", bkpath, msg); 1601 rv = NDMP_ILLEGAL_ARGS_ERR; 1602 } else if (!S_ISDIR(st.st_mode)) { 1603 MOD_LOG(params, "Error: %s is not a directory.\n", bkpath); 1604 rv = NDMP_ILLEGAL_ARGS_ERR; 1605 } else if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) && 1606 fs_is_chkpnt_enabled(bkpath)) { 1607 MOD_LOG(params, "Error: %s is not a checkpointed path.\n", 1608 bkpath); 1609 rv = NDMP_BAD_FILE_ERR; 1610 } 1611 1612 return (rv); 1613 } 1614 1615 1616 /* 1617 * ndmp_backup_extract_params 1618 * 1619 * Go through the backup parameters and check the validity 1620 * for each one. Then set the NLP flags according to the parameters. 1621 */ 1622 int 1623 ndmp_backup_extract_params(ndmpd_session_t *session, 1624 ndmpd_module_params_t *params) 1625 { 1626 char *cp; 1627 int rv; 1628 ndmp_lbr_params_t *nlp; 1629 1630 /* Extract directory to be backed up from env variables */ 1631 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1632 MOD_LOG(params, "Error: Internal error: nlp == NULL.\n"); 1633 return (NDMP_ILLEGAL_ARGS_ERR); 1634 } 1635 if ((nlp->nlp_backup_path = get_backup_path_v2(params)) == NULL) 1636 return (NDMP_FILE_NOT_FOUND_ERR); 1637 1638 if ((rv = check_backup_dir_validity(params, 1639 nlp->nlp_backup_path)) != NDMP_NO_ERR) 1640 return (rv); 1641 1642 /* Should the st_ctime be ignored when backing up? */ 1643 if (ndmp_ignore_ctime) { 1644 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime"); 1645 NLP_SET(nlp, NLPF_IGNCTIME); 1646 } else 1647 NLP_UNSET(nlp, NLPF_IGNCTIME); 1648 1649 /* Should the st_lmtime be ignored when backing up? */ 1650 if (ndmp_include_lmtime) { 1651 NDMP_LOG(LOG_DEBUG, "including st_lmtime"); 1652 NLP_SET(nlp, NLPF_INCLMTIME); 1653 } else 1654 NLP_UNSET(nlp, NLPF_INCLMTIME); 1655 1656 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags); 1657 1658 /* Is backup history requested? */ 1659 cp = MOD_GETENV(params, "HIST"); 1660 if (cp == NULL) { 1661 NDMP_LOG(LOG_DEBUG, "env(HIST) not specified"); 1662 NLP_UNSET(nlp, NLPF_FH); 1663 } else { 1664 NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", cp); 1665 1666 if (strchr("t_ty_y", *cp)) 1667 NLP_SET(nlp, NLPF_FH); 1668 else 1669 NLP_UNSET(nlp, NLPF_FH); 1670 } 1671 1672 nlp->nlp_clevel = 0; 1673 /* Is it an incremental backup? */ 1674 cp = MOD_GETENV(params, "LEVEL"); 1675 if (cp == NULL) { 1676 NDMP_LOG(LOG_DEBUG, 1677 "env(LEVEL) not specified, default to 0"); 1678 } else if (*cp < '0' || *cp > '9' || *(cp+1) != '\0') { 1679 NDMP_LOG(LOG_DEBUG, "Invalid backup level '%s'", cp); 1680 return (NDMP_ILLEGAL_ARGS_ERR); 1681 } else 1682 nlp->nlp_clevel = *cp - '0'; 1683 1684 /* Extract last backup time from the dumpdates file */ 1685 nlp->nlp_llevel = nlp->nlp_clevel; 1686 nlp->nlp_ldate = 0; 1687 if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel, 1688 &nlp->nlp_ldate) < 0) { 1689 MOD_LOG(params, "Error: getting dumpdate for %s level %d\n", 1690 nlp->nlp_backup_path, nlp->nlp_clevel); 1691 return (NDMP_NO_MEM_ERR); 1692 } 1693 1694 NDMP_LOG(LOG_DEBUG, 1695 "Date of this level %d on \"%s\": %s", 1696 nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate)); 1697 NDMP_LOG(LOG_DEBUG, 1698 "Date of last level %d on \"%s\": %s", 1699 nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate)); 1700 1701 /* Should the dumpdate file be updated? */ 1702 cp = MOD_GETENV(params, "UPDATE"); 1703 if (cp == NULL) { 1704 NDMP_LOG(LOG_DEBUG, 1705 "env(UPDATE) not specified, default to TRUE"); 1706 NLP_SET(nlp, NLPF_UPDATE); 1707 } else { 1708 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", cp); 1709 if (strchr("t_ty_y", *cp) != NULL) 1710 NLP_SET(nlp, NLPF_UPDATE); 1711 else 1712 NLP_UNSET(nlp, NLPF_UPDATE); 1713 } 1714 1715 return (NDMP_NO_ERR); 1716 } 1717 1718 1719 1720 /* 1721 * log_bk_params_v2 1722 * 1723 * Dump the value of the parameters in the log file for debugging. 1724 */ 1725 void 1726 log_bk_params_v2(ndmpd_session_t *session, ndmpd_module_params_t *params, 1727 ndmp_lbr_params_t *nlp) 1728 { 1729 MOD_LOG(params, "Date of this level %d on \"%s\": %s\n", 1730 nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate)); 1731 MOD_LOG(params, "Date of last level %d on \"%s\": %s\n", 1732 nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate)); 1733 1734 MOD_LOG(params, "Backing up: \"%s\".\n", nlp->nlp_backup_path); 1735 MOD_LOG(params, "Record size: %d\n", session->ns_mover.md_record_size); 1736 MOD_LOG(params, "File history: %c.\n", 1737 NDMP_YORN(NLP_ISSET(nlp, NLPF_FH))); 1738 MOD_LOG(params, "Update: %s\n", 1739 NLP_ISSET(nlp, NLPF_UPDATE) ? "TRUE" : "FALSE"); 1740 1741 } 1742 1743 1744 /* 1745 * same_path 1746 * 1747 * Find out if the paths are the same regardless of the ending slash 1748 * 1749 * Examples : 1750 * /a/b/c == /a/b/c 1751 * /a/b/c/ == /a/b/c 1752 * /a/b/c == /a/b/c/ 1753 */ 1754 static boolean_t 1755 same_path(char *s, char *t) 1756 { 1757 boolean_t rv; 1758 int slen, tlen; 1759 1760 rv = FALSE; 1761 slen = strlen(s); 1762 tlen = strlen(t); 1763 if (slen == tlen && strcmp(s, t) == 0) { 1764 rv = TRUE; 1765 } else { 1766 if (slen == tlen - 1) { 1767 if (strncmp(s, t, slen) == 0 && t[tlen - 1] == '/') 1768 rv = TRUE; 1769 } else if (tlen == slen -1) { 1770 if (strncmp(s, t, tlen) == 0 && s[slen - 1] == '/') 1771 rv = TRUE; 1772 } 1773 } 1774 1775 NDMP_LOG(LOG_DEBUG, "rv: %d", rv); 1776 return (rv); 1777 } 1778 1779 1780 /* 1781 * ndmp_restore_extract_params 1782 * 1783 * Go through the restore parameters and check them and extract them 1784 * by setting NLP flags and other values. 1785 * 1786 * Parameters: 1787 * 1788 * Returns: 1789 * 0: on success 1790 * -1: otherwise 1791 */ 1792 int 1793 ndmp_restore_extract_params(ndmpd_session_t *session, 1794 ndmpd_module_params_t *params) 1795 { 1796 char *bkpath, *rspath; 1797 ndmp_lbr_params_t *nlp; 1798 1799 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1800 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1801 return (-1); 1802 } 1803 1804 /* Extract directory from where the backup was made. */ 1805 if ((bkpath = get_backup_path_v2(params)) == NULL) 1806 return (NDMP_ILLEGAL_ARGS_ERR); 1807 1808 nlp->nlp_restore_bk_path = bkpath; 1809 1810 /* The number of the selections. */ 1811 if ((nlp->nlp_nfiles = get_nfiles(session, params)) == 0) 1812 return (NDMP_ILLEGAL_ARGS_ERR); 1813 1814 NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles); 1815 1816 if ((rspath = get_restore_dest(params)) == NULL) 1817 return (NDMP_ILLEGAL_ARGS_ERR); 1818 1819 if (fs_is_rdonly(rspath)) { 1820 MOD_LOG(params, 1821 "Error: Can't restore to a read-only volume: \"%s\"\n", 1822 rspath); 1823 return (NDMP_ILLEGAL_ARGS_ERR); 1824 } 1825 if (fs_is_chkpntvol(rspath)) { 1826 MOD_LOG(params, 1827 "Error: Can't restore to a checkpoint: \"%s\"\n", rspath); 1828 return (NDMP_ILLEGAL_ARGS_ERR); 1829 } 1830 1831 if (same_path(bkpath, rspath)) 1832 rspath = ""; 1833 1834 if ((nlp->nlp_restore_path = strdup(rspath)) == NULL) 1835 return (NDMP_NO_MEM_ERR); 1836 1837 bkpath = trim_name(bkpath); 1838 if (correct_ents(params, nlp->nlp_nfiles, bkpath) < 0) { 1839 free(nlp->nlp_restore_path); 1840 return (NDMP_ILLEGAL_ARGS_ERR); 1841 } 1842 1843 if (check_restore_paths(params, nlp->nlp_nfiles, rspath) < 0) { 1844 free(nlp->nlp_restore_path); 1845 return (NDMP_ILLEGAL_ARGS_ERR); 1846 } 1847 1848 MOD_LOG(params, "Restoring %d files.\n", nlp->nlp_nfiles); 1849 MOD_LOG(params, "Restoring to: \"%s\".\n", nlp->nlp_restore_path); 1850 MOD_LOG(params, "Record size: %d\n", session->ns_mover.md_record_size); 1851 1852 return (NDMP_NO_ERR); 1853 } 1854 1855 /* 1856 * ndmpd_tar_backup_starter (V2 only) 1857 * 1858 * The main backup starter function. It creates a snapshot if necessary 1859 * and calls ndmp_tar_backup to perform the actual backup. It does the cleanup 1860 * and release the snapshot at the end. 1861 */ 1862 int 1863 ndmpd_tar_backup_starter(void *arg) 1864 { 1865 ndmpd_module_params_t *mod_params = arg; 1866 int err; 1867 ndmpd_session_t *session; 1868 ndmp_lbr_params_t *nlp; 1869 1870 session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie); 1871 *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session); 1872 ndmp_session_ref(session); 1873 1874 err = 0; 1875 if (fs_is_chkpntvol(nlp->nlp_backup_path) || 1876 fs_is_rdonly(nlp->nlp_backup_path) || 1877 !fs_is_chkpnt_enabled(nlp->nlp_backup_path)) 1878 NLP_SET(nlp, NLPF_CHKPNTED_PATH); 1879 else { 1880 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH); 1881 if (ndmp_create_snapshot(nlp->nlp_backup_path, 1882 nlp->nlp_jstat->js_job_name) < 0) { 1883 MOD_LOG(mod_params, 1884 "Error: creating checkpoint on %s\n", 1885 nlp->nlp_backup_path); 1886 /* -1 causes halt reason to become internal error. */ 1887 err = -1; 1888 } 1889 } 1890 1891 NDMP_LOG(LOG_DEBUG, "NLPF_CHKPNTED_PATH: %c", 1892 NDMP_YORN(NLP_ISCHKPNTED(nlp))); 1893 NDMP_LOG(LOG_DEBUG, "err: %d, update %c", 1894 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp))); 1895 1896 if (err == 0) { 1897 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, 1898 nlp->nlp_jstat->js_job_name); 1899 if (err != 0) { 1900 NDMP_LOG(LOG_DEBUG, "err %d", err); 1901 } else { 1902 log_bk_params_v2(session, mod_params, nlp); 1903 err = ndmpd_tar_backup(session, mod_params, nlp); 1904 } 1905 } 1906 1907 if (nlp->nlp_bkmap >= 0) { 1908 (void) dbm_free(nlp->nlp_bkmap); 1909 nlp->nlp_bkmap = -1; 1910 } 1911 1912 if (!NLP_ISCHKPNTED(nlp)) 1913 (void) ndmp_remove_snapshot(nlp->nlp_backup_path, 1914 nlp->nlp_jstat->js_job_name); 1915 1916 NDMP_LOG(LOG_DEBUG, "err %d, update %c", 1917 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp))); 1918 1919 if (err == 0 && NLP_SHOULD_UPDATE(nlp)) { 1920 if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel, 1921 nlp->nlp_cdate) < 0) { 1922 err = EPERM; 1923 MOD_LOG(mod_params, 1924 "Error: updating the dumpdates file on %s\n", 1925 nlp->nlp_backup_path); 1926 } 1927 } 1928 1929 MOD_DONE(mod_params, err); 1930 1931 /* nlp_params is allocated in start_backup() */ 1932 NDMP_FREE(nlp->nlp_params); 1933 1934 NS_DEC(nbk); 1935 ndmp_session_unref(session); 1936 return (err); 1937 } 1938 1939 1940 /* 1941 * ndmpd_tar_backup_abort 1942 * 1943 * Abort the running backup by stopping the reader thread (V2 only) 1944 */ 1945 int 1946 ndmpd_tar_backup_abort(void *module_cookie) 1947 { 1948 ndmp_lbr_params_t *nlp; 1949 1950 nlp = (ndmp_lbr_params_t *)module_cookie; 1951 if (nlp != NULL && nlp->nlp_session != NULL) { 1952 if (nlp->nlp_session->ns_data.dd_mover.addr_type == 1953 NDMP_ADDR_TCP && nlp->nlp_session->ns_data.dd_sock != -1) { 1954 (void) close(nlp->nlp_session->ns_data.dd_sock); 1955 nlp->nlp_session->ns_data.dd_sock = -1; 1956 } 1957 ndmp_stop_reader_thread(nlp->nlp_session); 1958 } 1959 1960 return (0); 1961 } 1962 1963 /* 1964 * ndmpd_tar_restore_starter 1965 * 1966 * Starts the restore by running ndmpd_tar_restore function (V2 only) 1967 */ 1968 1969 int 1970 ndmpd_tar_restore_starter(void *arg) 1971 { 1972 ndmpd_module_params_t *mod_params = arg; 1973 int err; 1974 ndmpd_session_t *session; 1975 ndmp_lbr_params_t *nlp; 1976 1977 session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie); 1978 *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session); 1979 ndmp_session_ref(session); 1980 1981 err = ndmpd_tar_restore(session, mod_params, nlp); 1982 MOD_DONE(mod_params, err); 1983 1984 /* nlp_params is allocated in start_recover() */ 1985 NDMP_FREE(nlp->nlp_params); 1986 1987 NS_DEC(nrs); 1988 ndmp_session_unref(session); 1989 return (err); 1990 } 1991 1992 1993 /* 1994 * ndmpd_tar_restore_abort 1995 * 1996 * Aborts the restore operation by stopping the writer thread (V2 only) 1997 */ 1998 int 1999 ndmpd_tar_restore_abort(void *module_cookie) 2000 { 2001 ndmp_lbr_params_t *nlp; 2002 2003 nlp = (ndmp_lbr_params_t *)module_cookie; 2004 if (nlp != NULL && nlp->nlp_session != NULL) { 2005 (void) mutex_lock(&nlp->nlp_mtx); 2006 if (nlp->nlp_session->ns_data.dd_mover.addr_type == 2007 NDMP_ADDR_TCP && nlp->nlp_session->ns_data.dd_sock != -1) { 2008 (void) close(nlp->nlp_session->ns_data.dd_sock); 2009 nlp->nlp_session->ns_data.dd_sock = -1; 2010 } 2011 (void) cond_broadcast(&nlp->nlp_cv); 2012 (void) mutex_unlock(&nlp->nlp_mtx); 2013 ndmp_stop_writer_thread(nlp->nlp_session); 2014 } 2015 2016 return (0); 2017 } 2018