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