1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * BSD 3 Clause License 8 * 9 * Copyright (c) 2007, The Storage Networking Industry Association. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * - Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * - Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 22 * - Neither the name of The Storage Networking Industry Association (SNIA) 23 * nor the names of its contributors may be used to endorse or promote 24 * products derived from this software without specific prior written 25 * permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 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, NULL); 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 NULL); 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_backup_path 1437 * 1438 * Find the backup path from the environment variables 1439 */ 1440 static char * 1441 get_backup_path(ndmpd_module_params_t *params) 1442 { 1443 char *bkpath; 1444 1445 bkpath = MOD_GETENV(params, "PREFIX"); 1446 if (bkpath == NULL) 1447 bkpath = MOD_GETENV(params, "FILESYSTEM"); 1448 1449 if (bkpath == NULL) { 1450 MOD_LOG(params, "Error: restore path not specified.\n"); 1451 return (NULL); 1452 } 1453 1454 if (*bkpath != '/') { 1455 MOD_LOG(params, "Error: relative backup path not allowed.\n"); 1456 return (NULL); 1457 } 1458 1459 return (bkpath); 1460 } 1461 1462 1463 /* 1464 * get_nfiles 1465 * 1466 * Get the count of files to be restored 1467 */ 1468 static int 1469 get_nfiles(ndmpd_session_t *session, ndmpd_module_params_t *params) 1470 { 1471 if (session->ns_data.dd_nlist_len == 0) { 1472 MOD_LOG(params, "Error: nothing specified to be restored.\n"); 1473 return (-1); 1474 } 1475 1476 return (session->ns_data.dd_nlist_len); 1477 } 1478 1479 1480 /* 1481 * get_restore_dest 1482 * 1483 * Get the full pathname of where the entries should be restored to. 1484 */ 1485 static char * 1486 get_restore_dest(ndmpd_module_params_t *params) 1487 { 1488 ndmp_name *ent; 1489 char *cp; 1490 1491 /* 1492 * Destination of restore: 1493 * NetBackup of Veritas(C) sends the entries like this: 1494 * 1495 * ent[i].name: is the relative pathname of what is selected in 1496 * the GUI. 1497 * ent[i].dest: is the full pathname of where the dir/file must 1498 * be restored to. 1499 * ent[i].ssi: 0 1500 * ent[i].fh_info: 0 1501 * 1502 */ 1503 ent = (ndmp_name *)MOD_GETNAME(params, 0); 1504 cp = prefixdir(ent->dest, ent->name); 1505 if (cp == NULL) { 1506 MOD_LOG(params, "Error: empty restore path.\n"); 1507 return (NULL); 1508 } 1509 1510 return (cp); 1511 } 1512 1513 1514 /* 1515 * correct_ents 1516 * 1517 * Correct the entries in the restore list by appending the appropriate 1518 * path to them 1519 */ 1520 static int 1521 correct_ents(ndmpd_module_params_t *params, int n, char *bkpath) 1522 { 1523 char *cp, *pathname; 1524 int i, len, rv; 1525 ndmp_name *ent; 1526 1527 if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) { 1528 MOD_LOG(params, "Error: insufficient memory.\n"); 1529 return (-1); 1530 } 1531 1532 rv = 0; 1533 /* Append the backup path to all the "ent[].name"s. */ 1534 for (i = 0; i < n; i++) { 1535 ent = (ndmp_name *)MOD_GETNAME(params, i); 1536 1537 NDMP_LOG(LOG_DEBUG, 1538 "Old: ent[%d].name: \"%s\"", i, ent->name); 1539 NDMP_LOG(LOG_DEBUG, 1540 "Old: ent[%d].dest: \"%s\"", i, ent->dest); 1541 1542 /* remove trailing slash */ 1543 len = strlen(ent->name); 1544 if (ent->name[len - 1] == '/') 1545 ent->name[len - 1] = '\0'; 1546 1547 if (!tlm_cat_path(pathname, bkpath, ent->name)) { 1548 MOD_LOG(params, "Error: path too long.\n"); 1549 rv = -1; 1550 break; 1551 } 1552 1553 /* Make a copy of the new string and save it in ent->name. */ 1554 cp = strdup(pathname); 1555 if (cp == NULL) { 1556 MOD_LOG(params, "Error: insufficient memory.\n"); 1557 rv = -1; 1558 break; 1559 } 1560 free(ent->name); 1561 ent->name = cp; 1562 1563 NDMP_LOG(LOG_DEBUG, 1564 "New: ent[%d].name: \"%s\"", i, ent->name); 1565 } 1566 1567 free(pathname); 1568 return (rv); 1569 } 1570 1571 1572 /* 1573 * check_restore_paths 1574 * 1575 * Go through the restore list and check the validity of the 1576 * restore path. 1577 */ 1578 static int 1579 check_restore_paths(ndmpd_module_params_t *params, int n, char *rspath) 1580 { 1581 int i, rv; 1582 ndmp_name *ent; 1583 1584 rv = 0; 1585 if (rspath != NULL && *rspath != '\0') { 1586 NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", rspath); 1587 if (!fs_volexist(rspath)) { 1588 MOD_LOG(params, 1589 "Error: Invalid volume name for restore."); 1590 rv = -1; 1591 } 1592 } else { 1593 for (i = 0; i < n; i++) { 1594 ent = (ndmp_name *)MOD_GETNAME(params, i); 1595 NDMP_LOG(LOG_DEBUG, 1596 "ent[%d].name: \"%s\"", i, ent->name); 1597 1598 if (!fs_volexist(ent->name)) { 1599 MOD_LOG(params, 1600 "Error: Invalid volume name for restore.", 1601 ent->name); 1602 rv = -1; 1603 break; 1604 } 1605 } 1606 } 1607 1608 return (rv); 1609 } 1610 1611 1612 /* 1613 * check_backup_dir_validity 1614 * 1615 * Check if the backup directory is valid. Make sure it exists and 1616 * is writable. Check for snapshot and readonly cases. 1617 */ 1618 static int 1619 check_backup_dir_validity(ndmpd_module_params_t *params, char *bkpath) 1620 { 1621 char *msg; 1622 int rv; 1623 struct stat64 st; 1624 1625 rv = NDMP_NO_ERR; 1626 if (stat64(bkpath, &st) < 0) { 1627 msg = strerror(errno); 1628 MOD_LOG(params, "Error: stat(%s): %s.\n", bkpath, msg); 1629 rv = NDMP_ILLEGAL_ARGS_ERR; 1630 } else if (!S_ISDIR(st.st_mode)) { 1631 MOD_LOG(params, "Error: %s is not a directory.\n", bkpath); 1632 rv = NDMP_ILLEGAL_ARGS_ERR; 1633 } else if (ndmp_is_chkpnt_root(bkpath)) { 1634 /* It's a .chkpnt directory */ 1635 MOD_LOG(params, "Error: %s is a checkpoint root directory.\n", 1636 bkpath); 1637 rv = NDMP_BAD_FILE_ERR; 1638 } else if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) && 1639 fs_is_chkpnt_enabled(bkpath)) { 1640 MOD_LOG(params, "Error: %s is not a checkpointed path.\n", 1641 bkpath); 1642 rv = NDMP_BAD_FILE_ERR; 1643 } 1644 1645 return (rv); 1646 } 1647 1648 1649 /* 1650 * ndmp_backup_extract_params 1651 * 1652 * Go through the backup parameters and check the validity 1653 * for each one. Then set the NLP flags according to the parameters. 1654 */ 1655 int 1656 ndmp_backup_extract_params(ndmpd_session_t *session, 1657 ndmpd_module_params_t *params) 1658 { 1659 char *cp; 1660 int rv; 1661 ndmp_lbr_params_t *nlp; 1662 1663 /* Extract directory to be backed up from env variables */ 1664 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1665 MOD_LOG(params, "Error: Internal error: nlp == NULL.\n"); 1666 return (NDMP_ILLEGAL_ARGS_ERR); 1667 } 1668 if ((nlp->nlp_backup_path = get_backup_path(params)) == NULL) 1669 return (NDMP_FILE_NOT_FOUND_ERR); 1670 1671 if ((rv = check_backup_dir_validity(params, 1672 nlp->nlp_backup_path)) != NDMP_NO_ERR) 1673 return (rv); 1674 1675 /* Should the st_ctime be ignored when backing up? */ 1676 if (ndmp_ignore_ctime) { 1677 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime"); 1678 NLP_SET(nlp, NLPF_IGNCTIME); 1679 } else 1680 NLP_UNSET(nlp, NLPF_IGNCTIME); 1681 1682 /* Should the st_lmtime be ignored when backing up? */ 1683 if (ndmp_include_lmtime) { 1684 NDMP_LOG(LOG_DEBUG, "including st_lmtime"); 1685 NLP_SET(nlp, NLPF_INCLMTIME); 1686 } else 1687 NLP_UNSET(nlp, NLPF_INCLMTIME); 1688 1689 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags); 1690 1691 /* Is backup history requested? */ 1692 cp = MOD_GETENV(params, "HIST"); 1693 if (cp == NULL) { 1694 NDMP_LOG(LOG_DEBUG, "env(HIST) not specified"); 1695 NLP_UNSET(nlp, NLPF_FH); 1696 } else { 1697 NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", cp); 1698 1699 if (strchr("t_ty_y", *cp)) 1700 NLP_SET(nlp, NLPF_FH); 1701 else 1702 NLP_UNSET(nlp, NLPF_FH); 1703 } 1704 1705 nlp->nlp_clevel = 0; 1706 /* Is it an incremental backup? */ 1707 cp = MOD_GETENV(params, "LEVEL"); 1708 if (cp == NULL) { 1709 NDMP_LOG(LOG_DEBUG, 1710 "env(LEVEL) not specified, default to 0"); 1711 } else if (*cp < '0' || *cp > '9' || *(cp+1) != '\0') { 1712 NDMP_LOG(LOG_DEBUG, "Invalid backup level '%s'", cp); 1713 return (NDMP_ILLEGAL_ARGS_ERR); 1714 } else 1715 nlp->nlp_clevel = *cp - '0'; 1716 1717 /* Extract last backup time from the dumpdates file */ 1718 nlp->nlp_llevel = nlp->nlp_clevel; 1719 nlp->nlp_ldate = 0; 1720 if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel, 1721 &nlp->nlp_ldate) < 0) { 1722 MOD_LOG(params, "Error: getting dumpdate for %s level %d\n", 1723 nlp->nlp_backup_path, nlp->nlp_clevel); 1724 return (NDMP_NO_MEM_ERR); 1725 } 1726 1727 NDMP_LOG(LOG_DEBUG, 1728 "Date of this level %d on \"%s\": %s", 1729 nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate)); 1730 NDMP_LOG(LOG_DEBUG, 1731 "Date of last level %d on \"%s\": %s", 1732 nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate)); 1733 1734 /* Should the dumpdate file be updated? */ 1735 cp = MOD_GETENV(params, "UPDATE"); 1736 if (cp == NULL) { 1737 NDMP_LOG(LOG_DEBUG, 1738 "env(UPDATE) not specified, default to TRUE"); 1739 NLP_SET(nlp, NLPF_UPDATE); 1740 } else { 1741 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", cp); 1742 if (strchr("t_ty_y", *cp) != NULL) 1743 NLP_SET(nlp, NLPF_UPDATE); 1744 else 1745 NLP_UNSET(nlp, NLPF_UPDATE); 1746 } 1747 1748 return (NDMP_NO_ERR); 1749 } 1750 1751 1752 1753 /* 1754 * log_bk_params_v2 1755 * 1756 * Dump the value of the parameters in the log file for debugging. 1757 */ 1758 void 1759 log_bk_params_v2(ndmpd_session_t *session, ndmpd_module_params_t *params, 1760 ndmp_lbr_params_t *nlp) 1761 { 1762 MOD_LOG(params, "Date of this level %d on \"%s\": %s\n", 1763 nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate)); 1764 MOD_LOG(params, "Date of last level %d on \"%s\": %s\n", 1765 nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate)); 1766 1767 MOD_LOG(params, "Backing up: \"%s\".\n", nlp->nlp_backup_path); 1768 MOD_LOG(params, "Record size: %d\n", session->ns_mover.md_record_size); 1769 MOD_LOG(params, "File history: %c.\n", 1770 NDMP_YORN(NLP_ISSET(nlp, NLPF_FH))); 1771 MOD_LOG(params, "Update: %s\n", 1772 NLP_ISSET(nlp, NLPF_UPDATE) ? "TRUE" : "FALSE"); 1773 1774 } 1775 1776 1777 /* 1778 * same_path 1779 * 1780 * Find out if the paths are the same regardless of the ending slash 1781 * 1782 * Examples : 1783 * /a/b/c == /a/b/c 1784 * /a/b/c/ == /a/b/c 1785 * /a/b/c == /a/b/c/ 1786 */ 1787 static boolean_t 1788 same_path(char *s, char *t) 1789 { 1790 boolean_t rv; 1791 int slen, tlen; 1792 1793 rv = FALSE; 1794 slen = strlen(s); 1795 tlen = strlen(t); 1796 if (slen == tlen && strcmp(s, t) == 0) { 1797 rv = TRUE; 1798 } else { 1799 if (slen == tlen - 1) { 1800 if (strncmp(s, t, slen) == 0 && t[tlen - 1] == '/') 1801 rv = TRUE; 1802 } else if (tlen == slen -1) { 1803 if (strncmp(s, t, tlen) == 0 && s[slen - 1] == '/') 1804 rv = TRUE; 1805 } 1806 } 1807 1808 NDMP_LOG(LOG_DEBUG, "rv: %d", rv); 1809 return (rv); 1810 } 1811 1812 1813 /* 1814 * ndmp_restore_extract_params 1815 * 1816 * Go through the restore parameters and check them and extract them 1817 * by setting NLP flags and other values. 1818 * 1819 * Parameters: 1820 * 1821 * Returns: 1822 * 0: on success 1823 * -1: otherwise 1824 */ 1825 int 1826 ndmp_restore_extract_params(ndmpd_session_t *session, 1827 ndmpd_module_params_t *params) 1828 { 1829 char *bkpath, *rspath; 1830 ndmp_lbr_params_t *nlp; 1831 1832 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1833 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1834 return (-1); 1835 } 1836 1837 /* Extract directory from where the backup was made. */ 1838 if ((bkpath = get_backup_path(params)) == NULL) 1839 return (NDMP_ILLEGAL_ARGS_ERR); 1840 1841 nlp->nlp_restore_bk_path = bkpath; 1842 1843 /* The number of the selections. */ 1844 if ((nlp->nlp_nfiles = get_nfiles(session, params)) == 0) 1845 return (NDMP_ILLEGAL_ARGS_ERR); 1846 1847 NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles); 1848 1849 if ((rspath = get_restore_dest(params)) == NULL) 1850 return (NDMP_ILLEGAL_ARGS_ERR); 1851 1852 if (fs_is_rdonly(rspath)) { 1853 MOD_LOG(params, 1854 "Error: Can't restore to a read-only volume: \"%s\"\n", 1855 rspath); 1856 return (NDMP_ILLEGAL_ARGS_ERR); 1857 } 1858 if (fs_is_chkpntvol(rspath)) { 1859 MOD_LOG(params, 1860 "Error: Can't restore to a checkpoint: \"%s\"\n", rspath); 1861 return (NDMP_ILLEGAL_ARGS_ERR); 1862 } 1863 1864 if (same_path(bkpath, rspath)) 1865 rspath = ""; 1866 1867 if ((nlp->nlp_restore_path = strdup(rspath)) == NULL) 1868 return (NDMP_NO_MEM_ERR); 1869 1870 bkpath = trim_name(bkpath); 1871 if (correct_ents(params, nlp->nlp_nfiles, bkpath) < 0) { 1872 free(nlp->nlp_restore_path); 1873 return (NDMP_ILLEGAL_ARGS_ERR); 1874 } 1875 1876 if (check_restore_paths(params, nlp->nlp_nfiles, rspath) < 0) { 1877 free(nlp->nlp_restore_path); 1878 return (NDMP_ILLEGAL_ARGS_ERR); 1879 } 1880 1881 MOD_LOG(params, "Restoring %d files.\n", nlp->nlp_nfiles); 1882 MOD_LOG(params, "Restoring to: \"%s\".\n", nlp->nlp_restore_path); 1883 MOD_LOG(params, "Record size: %d\n", session->ns_mover.md_record_size); 1884 1885 return (NDMP_NO_ERR); 1886 } 1887 1888 /* 1889 * ndmpd_tar_backup_starter (V2 only) 1890 * 1891 * The main backup starter function. It creates a snapshot if necessary 1892 * and calls ndmp_tar_backup to perform the actual backup. It does the cleanup 1893 * and release the snapshot at the end. 1894 */ 1895 int 1896 ndmpd_tar_backup_starter(ndmpd_module_params_t *mod_params) 1897 { 1898 int err; 1899 ndmpd_session_t *session; 1900 ndmp_lbr_params_t *nlp; 1901 1902 session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie); 1903 *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session); 1904 ndmp_session_ref(session); 1905 1906 err = 0; 1907 if (fs_is_chkpntvol(nlp->nlp_backup_path) || 1908 fs_is_rdonly(nlp->nlp_backup_path) || 1909 !fs_is_chkpnt_enabled(nlp->nlp_backup_path)) 1910 NLP_SET(nlp, NLPF_CHKPNTED_PATH); 1911 else { 1912 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH); 1913 if (ndmp_start_check_point(nlp->nlp_backup_path, 1914 nlp->nlp_jstat->js_job_name) < 0) { 1915 MOD_LOG(mod_params, 1916 "Error: creating checkpoint on %s\n", 1917 nlp->nlp_backup_path); 1918 /* -1 causes halt reason to become internal error. */ 1919 err = -1; 1920 } 1921 } 1922 1923 NDMP_LOG(LOG_DEBUG, "NLPF_CHKPNTED_PATH: %c", 1924 NDMP_YORN(NLP_ISCHKPNTED(nlp))); 1925 NDMP_LOG(LOG_DEBUG, "err: %d, update %c", 1926 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp))); 1927 1928 if (err == 0) { 1929 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, 1930 nlp->nlp_jstat->js_job_name); 1931 if (err != 0) { 1932 NDMP_LOG(LOG_DEBUG, "err %d", err); 1933 } else { 1934 log_bk_params_v2(session, mod_params, nlp); 1935 err = ndmpd_tar_backup(session, mod_params, nlp); 1936 } 1937 } 1938 1939 if (nlp->nlp_bkmap >= 0) { 1940 (void) dbm_free(nlp->nlp_bkmap); 1941 nlp->nlp_bkmap = -1; 1942 } 1943 1944 if (!NLP_ISCHKPNTED(nlp)) 1945 (void) ndmp_release_check_point(nlp->nlp_backup_path, 1946 nlp->nlp_jstat->js_job_name); 1947 1948 NDMP_LOG(LOG_DEBUG, "err %d, update %c", 1949 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp))); 1950 1951 if (err == 0 && NLP_SHOULD_UPDATE(nlp)) { 1952 if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel, 1953 nlp->nlp_cdate) < 0) { 1954 err = EPERM; 1955 MOD_LOG(mod_params, 1956 "Error: updating the dumpdates file on %s\n", 1957 nlp->nlp_backup_path); 1958 } 1959 } 1960 1961 MOD_DONE(mod_params, err); 1962 1963 /* nlp_params is allocated in start_backup() */ 1964 NDMP_FREE(nlp->nlp_params); 1965 1966 NS_DEC(nbk); 1967 ndmp_session_unref(session); 1968 return (err); 1969 } 1970 1971 1972 /* 1973 * ndmpd_tar_backup_abort 1974 * 1975 * Abort the running backup by stopping the reader thread (V2 only) 1976 */ 1977 int 1978 ndmpd_tar_backup_abort(void *module_cookie) 1979 { 1980 ndmp_lbr_params_t *nlp; 1981 1982 nlp = (ndmp_lbr_params_t *)module_cookie; 1983 if (nlp != NULL && nlp->nlp_session != NULL) { 1984 if (nlp->nlp_session->ns_data.dd_mover.addr_type == 1985 NDMP_ADDR_TCP && nlp->nlp_session->ns_data.dd_sock != -1) { 1986 (void) close(nlp->nlp_session->ns_data.dd_sock); 1987 nlp->nlp_session->ns_data.dd_sock = -1; 1988 } 1989 ndmp_stop_reader_thread(nlp->nlp_session); 1990 } 1991 1992 return (0); 1993 } 1994 1995 /* 1996 * ndmpd_tar_restore_starter 1997 * 1998 * Starts the restore by running ndmpd_tar_restore function (V2 only) 1999 */ 2000 2001 int 2002 ndmpd_tar_restore_starter(ndmpd_module_params_t *mod_params) 2003 { 2004 int err; 2005 ndmpd_session_t *session; 2006 ndmp_lbr_params_t *nlp; 2007 2008 session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie); 2009 *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session); 2010 ndmp_session_ref(session); 2011 2012 err = ndmpd_tar_restore(session, mod_params, nlp); 2013 MOD_DONE(mod_params, err); 2014 2015 /* nlp_params is allocated in start_recover() */ 2016 NDMP_FREE(nlp->nlp_params); 2017 2018 NS_DEC(nrs); 2019 ndmp_session_unref(session); 2020 return (err); 2021 } 2022 2023 2024 /* 2025 * ndmpd_tar_restore_abort 2026 * 2027 * Aborts the restore operation by stopping the writer thread (V2 only) 2028 */ 2029 int 2030 ndmpd_tar_restore_abort(void *module_cookie) 2031 { 2032 ndmp_lbr_params_t *nlp; 2033 2034 nlp = (ndmp_lbr_params_t *)module_cookie; 2035 if (nlp != NULL && nlp->nlp_session != NULL) { 2036 if (nlp->nlp_session->ns_data.dd_mover.addr_type == 2037 NDMP_ADDR_TCP && nlp->nlp_session->ns_data.dd_sock != -1) { 2038 (void) close(nlp->nlp_session->ns_data.dd_sock); 2039 nlp->nlp_session->ns_data.dd_sock = -1; 2040 } 2041 nlp_event_nw(nlp->nlp_session); 2042 ndmp_stop_writer_thread(nlp->nlp_session); 2043 } 2044 2045 return (0); 2046 } 2047