1 /* 2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 3 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 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) 2007, The Storage Networking Industry Association. */ 40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ 41 #include <sys/stat.h> 42 #include <sys/types.h> 43 #include <sys/time.h> 44 #include <ctype.h> 45 #include <sys/socket.h> 46 #include <sys/acl.h> 47 #include <netinet/in.h> 48 #include <arpa/inet.h> 49 #include <errno.h> 50 #include <stdio.h> 51 #include <string.h> 52 #include <time.h> 53 #include <cstack.h> 54 #include "ndmp.h" 55 #include "ndmpd.h" 56 #include <bitmap.h> 57 #include <traverse.h> 58 59 60 /* 61 * Maximum length of the string-representation of u_longlong_t type. 62 */ 63 #define QUAD_DECIMAL_LEN 20 64 65 66 /* Is Y=yes or T=true */ 67 #define IS_YORT(c) (strchr("YT", toupper(c))) 68 69 /* Is F=file format (vs D=node-dir format) */ 70 #define IS_F(c) (toupper(c) == 'F') 71 72 /* 73 * If path is defined. 74 */ 75 #define ISDEFINED(cp) ((cp) && *(cp)) 76 #define SHOULD_LBRBK(bpp) (!((bpp)->bp_opr & TLM_OP_CHOOSE_ARCHIVE)) 77 78 /* 79 * Component boundary means end of path or on a '/'. At this 80 * point both paths should be on component boundary. 81 */ 82 #define COMPBNDRY(p) (!*(p) || (*p) == '/') 83 84 typedef struct bk_param_v3 { 85 ndmpd_session_t *bp_session; 86 ndmp_lbr_params_t *bp_nlp; 87 tlm_job_stats_t *bp_js; 88 tlm_cmd_t *bp_lcmd; 89 tlm_commands_t *bp_cmds; 90 tlm_acls_t *bp_tlmacl; 91 int bp_opr; 92 char *bp_tmp; 93 char *bp_chkpnm; 94 char **bp_excls; 95 char *bp_unchkpnm; 96 } bk_param_v3_t; 97 98 99 /* 100 * Multiple destination restore mode 101 */ 102 #define MULTIPLE_DEST_DIRS 128 103 104 int multiple_dest_restore = 0; 105 106 /* 107 * Plug-in module ops 108 */ 109 ndmp_plugin_t *ndmp_pl; 110 111 /* 112 * NDMP exclusion list 113 */ 114 char **ndmp_excl_list = NULL; 115 116 /* 117 * split_env 118 * 119 * Splits the string into list of sections separated by the 120 * sep character. 121 * 122 * Parameters: 123 * envp (input) - the environment variable that should be broken 124 * sep (input) - the separator character 125 * 126 * Returns: 127 * Array of character pointers: On success. The array is allocated 128 * as well as all its entries. They all should be freed by the 129 * caller. 130 * NULL: on error 131 */ 132 static char ** 133 split_env(char *envp, char sep) 134 { 135 char *bp, *cp, *ep; 136 char *save; 137 char **cpp; 138 int n; 139 140 if (!envp) 141 return (NULL); 142 143 while (isspace(*envp)) 144 envp++; 145 146 if (!*envp) 147 return (NULL); 148 149 bp = save = strdup(envp); 150 if (!bp) 151 return (NULL); 152 153 /* 154 * Since the env variable is not empty, it contains at least one 155 * component 156 */ 157 n = 1; 158 while ((cp = strchr(bp, sep))) { 159 if (cp > save && *(cp-1) != '\\') 160 n++; 161 162 bp = cp + 1; 163 } 164 165 n++; /* for the terminating NULL pointer */ 166 cpp = ndmp_malloc(sizeof (char *) * n); 167 if (!cpp) { 168 free(save); 169 return (NULL); 170 } 171 172 (void) memset(cpp, 0, n * sizeof (char *)); 173 n = 0; 174 cp = bp = ep = save; 175 while (*cp) 176 if (*cp == sep) { 177 *ep = '\0'; 178 if (strlen(bp) > 0) { 179 cpp[n] = strdup(bp); 180 if (!cpp[n++]) { 181 tlm_release_list(cpp); 182 cpp = NULL; 183 break; 184 } 185 } 186 ep = bp = ++cp; 187 } else if (*cp == '\\') { 188 ++cp; 189 if (*cp == 'n') { /* "\n" */ 190 *ep++ = '\n'; 191 cp++; 192 } else if (*cp == 't') { /* "\t" */ 193 *ep++ = '\t'; 194 cp++; 195 } else 196 *ep++ = *cp++; 197 } else 198 *ep++ = *cp++; 199 200 *ep = '\0'; 201 if (cpp) { 202 if (strlen(bp) > 0) { 203 cpp[n] = strdup(bp); 204 if (!cpp[n++]) { 205 tlm_release_list(cpp); 206 cpp = NULL; 207 } else 208 cpp[n] = NULL; 209 } 210 211 if (n == 0 && cpp != NULL) { 212 tlm_release_list(cpp); 213 cpp = NULL; 214 } 215 } 216 217 free(save); 218 return (cpp); 219 } 220 221 222 /* 223 * prl 224 * 225 * Print the array of character pointers passed to it. This is 226 * used for debugging purpose. 227 * 228 * Parameters: 229 * lpp (input) - pointer to the array of strings 230 * 231 * Returns: 232 * void 233 */ 234 static void 235 prl(char **lpp) 236 { 237 if (!lpp) { 238 NDMP_LOG(LOG_DEBUG, "empty"); 239 return; 240 } 241 242 while (*lpp) 243 NDMP_LOG(LOG_DEBUG, "\"%s\"", *lpp++); 244 } 245 246 247 /* 248 * inlist 249 * 250 * Looks through all the strings of the array to see if the ent 251 * matches any of the strings. The strings are patterns. 252 * 253 * Parameters: 254 * lpp (input) - pointer to the array of strings 255 * ent (input) - the entry to be matched 256 * 257 * Returns: 258 * TRUE: if there is a match 259 * FALSE: invalid argument or no match 260 */ 261 static boolean_t 262 inlist(char **lpp, char *ent) 263 { 264 if (!lpp || !ent) { 265 NDMP_LOG(LOG_DEBUG, "empty list"); 266 return (FALSE); 267 } 268 269 while (*lpp) { 270 /* 271 * Fixing the sync_sort NDMPV3 problem, it sends the inclusion 272 * like "./" which we should skip the "./" 273 */ 274 char *pattern = *lpp; 275 if (strncmp(pattern, "./", 2) == 0) 276 pattern += 2; 277 278 NDMP_LOG(LOG_DEBUG, "pattern %s, ent %s", pattern, ent); 279 280 if (match(pattern, ent)) { 281 NDMP_LOG(LOG_DEBUG, "match(%s,%s)", pattern, ent); 282 return (TRUE); 283 } 284 lpp++; 285 } 286 287 NDMP_LOG(LOG_DEBUG, "no match"); 288 return (FALSE); 289 } 290 291 292 /* 293 * inexl 294 * 295 * Checks if the entry is in the list. This is used for exclusion 296 * list. If the exclusion list is empty, FALSE should be returned 297 * showing that nothing should be excluded by default. 298 * 299 * Parameters: 300 * lpp (input) - pointer to the array of strings 301 * ent (input) - the entry to be matched 302 * 303 * Returns: 304 * TRUE: if there is a match 305 * FALSE: invalid argument or no match 306 * 307 */ 308 static boolean_t 309 inexl(char **lpp, char *ent) 310 { 311 if (!lpp || !ent) 312 return (FALSE); 313 314 return (inlist(lpp, ent)); 315 } 316 317 318 /* 319 * ininc 320 * 321 * Checks if the entry is in the list. This is used for inclusion 322 * list. If the inclusion list is empty, TRUE should be returned 323 * showing that everything should be included by default. 324 * 325 * Parameters: 326 * lpp (input) - pointer to the array of strings 327 * ent (input) - the entry to be matched 328 * 329 * Returns: 330 * TRUE: if there is a match or the list is empty 331 * FALSE: no match 332 */ 333 static boolean_t 334 ininc(char **lpp, char *ent) 335 { 336 if (!lpp || !ent || !*ent) 337 return (TRUE); 338 339 return (inlist(lpp, ent)); 340 } 341 342 343 /* 344 * setupsels 345 * 346 * Set up the selection list for Local B/R functions. A new array of 347 * "char *" is created and the pointers point to the original paths of 348 * the Nlist. 349 * 350 * Parameters: 351 * session (input) - pointer to the session 352 * params (input) - pointer to the parameters structure 353 * nlp (input) - pointer to the nlp structure 354 * index(input) - If not zero is the DAR entry position 355 * 356 * Returns: 357 * list pointer: on success 358 * NULL: on error 359 */ 360 /*ARGSUSED*/ 361 char ** 362 setupsels(ndmpd_session_t *session, ndmpd_module_params_t *params, 363 ndmp_lbr_params_t *nlp, int index) 364 { 365 char **lpp, **save; 366 int i, n; 367 int len; 368 int start, end; 369 mem_ndmp_name_v3_t *ep; 370 371 n = session->ns_data.dd_nlist_len; 372 373 save = lpp = ndmp_malloc(sizeof (char *) * (n + 1)); 374 if (!lpp) { 375 MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n"); 376 return (NULL); 377 } 378 379 if (index) { /* DAR, just one entry */ 380 /* 381 * We have to setup a list of strings that will not match any 382 * file. One DAR entry will be added in the right position later 383 * in this function. 384 * When the match is called from tar_getdir the 385 * location of the selection that matches the entry is 386 * important 387 */ 388 for (i = 0; i < n; ++i) 389 *(lpp+i) = " "; 390 n = 1; 391 start = index-1; 392 end = start+1; 393 lpp += start; /* Next selection entry will be in lpp[start] */ 394 } else { 395 start = 0; 396 end = n; 397 } 398 399 for (i = start; i < end; i++) { 400 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i); 401 if (!ep) 402 continue; 403 404 /* 405 * Check for clients that send original path as "."(like 406 * CA products). In this situation opath is something like 407 * "/v1/." and we should change it to "/v1/" 408 */ 409 len = strlen(ep->nm3_opath); 410 if (len > 1 && ep->nm3_opath[len-2] == '/' && 411 ep->nm3_opath[len-1] == '.') { 412 ep->nm3_opath[len-1] = '\0'; 413 NDMP_LOG(LOG_DEBUG, 414 "nm3_opath changed from %s. to %s", 415 ep->nm3_opath, ep->nm3_opath); 416 } 417 *lpp++ = ep->nm3_opath; 418 } 419 420 /* list termination indicator is a null pointer */ 421 *lpp = NULL; 422 423 return (save); 424 } 425 426 427 /* 428 * mkrsp 429 * 430 * Make Restore Path. 431 * It gets a path, a selection (with which the path has matched) a new 432 * name and makes a new name for the path. 433 * All the components of the path and the selection are skipped as long 434 * as they are the same. If either of the path or selection are not on 435 * a component boundary, the match was reported falsefully and no new name 436 * is generated(Except the situation in which both path and selection 437 * end with trailing '/' and selection is the prefix of the path). 438 * Otherwise, the remaining of the path is appended to the 439 * new name. The result is saved in the buffer passed. 440 * 441 * Parameters: 442 * bp (output) - pointer to the result buffer 443 * pp (input) - pointer to the path 444 * sp (input) - pointer to the selection 445 * np (input) - pointer to the new name 446 * 447 * Returns: 448 * pointer to the bp: on success 449 * NULL: otherwise 450 */ 451 char * 452 mkrsp(char *bp, char *pp, char *sp, char *np) 453 { 454 if (!bp || !pp) 455 return (NULL); 456 457 458 pp += strspn(pp, "/"); 459 if (sp) { 460 sp += strspn(sp, "/"); 461 462 /* skip as much as match */ 463 while (*sp && *pp && *sp == *pp) { 464 sp++; 465 pp++; 466 } 467 468 if (!COMPBNDRY(pp) || !COMPBNDRY(sp)) 469 /* An exception to the boundary rule */ 470 /* (!(!*sp && (*(pp - 1)) == '/')) */ 471 if (*sp || (*(pp - 1)) != '/') 472 return (NULL); 473 474 /* if pp shorter than sp, it should not be restored */ 475 if (!*pp && *sp) { 476 sp += strspn(sp, "/"); 477 if (strlen(sp) > 0) 478 return (NULL); 479 } 480 } 481 482 if (np) 483 np += strspn(np, "/"); 484 else 485 np = ""; 486 487 if (!tlm_cat_path(bp, np, pp)) { 488 NDMP_LOG(LOG_ERR, "Restore path too long %s/%s.", np, pp); 489 return (NULL); 490 } 491 492 return (bp); 493 } 494 495 496 /* 497 * mknewname 498 * 499 * This is used as callback for creating the restore path. This function 500 * can handle both single destination and multiple restore paths. 501 * 502 * Make up the restore destination path for a particular file/directory, path, 503 * based on nm3_opath and nm3_dpath. path should have matched nm3_opath 504 * in some way. 505 */ 506 char * 507 mknewname(struct rs_name_maker *rnp, char *buf, int idx, char *path) 508 { 509 char *rv; 510 ndmp_lbr_params_t *nlp; 511 mem_ndmp_name_v3_t *ep; 512 513 rv = NULL; 514 if (!buf) { 515 NDMP_LOG(LOG_DEBUG, "buf is NULL"); 516 } else if (!path) { 517 NDMP_LOG(LOG_DEBUG, "path is NULL"); 518 } else if ((nlp = rnp->rn_nlp) == 0) { 519 NDMP_LOG(LOG_DEBUG, "rnp->rn_nlp is NULL"); 520 } else if (!nlp->nlp_params) { 521 NDMP_LOG(LOG_DEBUG, "nlp->nlp_params is NULL"); 522 } else 523 if (!ndmp_full_restore_path) { 524 if (idx < 0 || idx >= (int)nlp->nlp_nfiles) { 525 NDMP_LOG(LOG_DEBUG, 526 "Invalid idx %d range (0, %d)", 527 idx, nlp->nlp_nfiles); 528 } else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME( 529 nlp->nlp_params, idx))) { 530 NDMP_LOG(LOG_DEBUG, 531 "nlist entry %d is NULL", idx); 532 } else { 533 rv = mkrsp(buf, path, ep->nm3_opath, 534 ep->nm3_dpath); 535 536 NDMP_LOG(LOG_DEBUG, 537 "idx %d org \"%s\" dst \"%s\"", 538 idx, ep->nm3_opath, ep->nm3_dpath); 539 if (rv) { 540 NDMP_LOG(LOG_DEBUG, 541 "path \"%s\": \"%s\"", path, rv); 542 } else { 543 NDMP_LOG(LOG_DEBUG, 544 "path \"%s\": NULL", path); 545 } 546 } 547 } else { 548 if (!tlm_cat_path(buf, nlp->nlp_restore_path, path)) { 549 NDMP_LOG(LOG_ERR, "Path too long %s/%s.", 550 nlp->nlp_restore_path, path); 551 rv = NULL; 552 } else { 553 rv = buf; 554 NDMP_LOG(LOG_DEBUG, 555 "path \"%s\": \"%s\"", path, rv); 556 } 557 } 558 559 return (rv); 560 } 561 562 563 /* 564 * chopslash 565 * 566 * Remove the slash from the end of the given path 567 */ 568 static void 569 chopslash(char *cp) 570 { 571 int ln; 572 573 if (!cp || !*cp) 574 return; 575 576 ln = strlen(cp); 577 cp += ln - 1; /* end of the string */ 578 while (ln > 0 && *cp == '/') { 579 *cp-- = '\0'; 580 ln--; 581 } 582 } 583 584 585 /* 586 * joinpath 587 * 588 * Join two given paths 589 */ 590 static char * 591 joinpath(char *bp, char *pp, char *np) 592 { 593 if (pp && *pp) { 594 if (np && *np) 595 (void) tlm_cat_path(bp, pp, np); 596 else 597 (void) strlcpy(bp, pp, TLM_MAX_PATH_NAME); 598 } else { 599 if (np && *np) 600 (void) strlcpy(bp, np, TLM_MAX_PATH_NAME); 601 else 602 bp = NULL; 603 } 604 605 return (bp); 606 } 607 608 609 /* 610 * voliswr 611 * 612 * Is the volume writable? 613 */ 614 static int 615 voliswr(char *path) 616 { 617 int rv; 618 619 if (!path) 620 return (0); 621 622 rv = !fs_is_rdonly(path) && !fs_is_chkpntvol(path); 623 NDMP_LOG(LOG_DEBUG, "%d path \"%s\"", rv, path); 624 return (rv); 625 626 } 627 628 629 /* 630 * is_valid_backup_dir_v3 631 * 632 * Checks the validity of the backup path. Backup path should 633 * have the following characteristics to be valid: 634 * 1) It should be an absolute path. 635 * 2) It should be a directory. 636 * 3) It should not be checkpoint root directory 637 * 4) If the file system is read-only, the backup path 638 * should be a checkpointed path. Checkpoint cannot 639 * be created on a read-only file system. 640 * 641 * Parameters: 642 * params (input) - pointer to the parameters structure. 643 * bkpath (input) - the backup path 644 * 645 * Returns: 646 * TRUE: if everything's OK 647 * FALSE: otherwise. 648 */ 649 static boolean_t 650 is_valid_backup_dir_v3(ndmpd_module_params_t *params, char *bkpath) 651 { 652 char *msg; 653 struct stat64 st; 654 655 if (*bkpath != '/') { 656 MOD_LOGV3(params, NDMP_LOG_ERROR, 657 "Relative backup path not allowed \"%s\".\n", bkpath); 658 return (FALSE); 659 } 660 if (stat64(bkpath, &st) < 0) { 661 msg = strerror(errno); 662 MOD_LOGV3(params, NDMP_LOG_ERROR, "\"%s\" %s.\n", 663 bkpath, msg); 664 return (FALSE); 665 } 666 if (!S_ISDIR(st.st_mode)) { 667 /* only directories can be specified as the backup path */ 668 MOD_LOGV3(params, NDMP_LOG_ERROR, 669 "\"%s\" is not a directory.\n", bkpath); 670 return (FALSE); 671 } 672 if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) && 673 fs_is_chkpnt_enabled(bkpath)) { 674 /* it is not a chkpnted path */ 675 MOD_LOGV3(params, NDMP_LOG_ERROR, 676 "\"%s\" is not a checkpointed path.\n", bkpath); 677 return (FALSE); 678 } 679 680 return (TRUE); 681 } 682 683 684 /* 685 * log_date_token_v3 686 * 687 * Log the token sequence number and also the date of the 688 * last backup for token-based backup in the system log 689 * and also send them as normal log to the client. 690 * 691 * Parameters: 692 * params (input) - pointer to the parameters structure 693 * nlp (input) - pointer to the nlp structure 694 * 695 * Returns: 696 * void 697 */ 698 static void 699 log_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 700 { 701 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Token sequence counter: %d.\n", 702 nlp->nlp_tokseq); 703 704 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Date of the last backup: %s.\n", 705 cctime(&nlp->nlp_tokdate)); 706 707 if (nlp->nlp_dmpnm) { 708 MOD_LOGV3(params, NDMP_LOG_NORMAL, 709 "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm); 710 } 711 } 712 713 714 /* 715 * log_lbr_bk_v3 716 * 717 * Log the backup level and data of the backup for LBR-type 718 * backup in the system log and also send them as normal log 719 * to the client. 720 * 721 * Parameters: 722 * params (input) - pointer to the parameters structure 723 * nlp (input) - pointer to the nlp structure 724 * 725 * Returns: 726 * void 727 */ 728 static void 729 log_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 730 { 731 MOD_LOGV3(params, NDMP_LOG_NORMAL, 732 "Date of this level '%c': %s.\n", nlp->nlp_clevel, 733 cctime(&nlp->nlp_cdate)); 734 735 if (nlp->nlp_dmpnm) { 736 MOD_LOGV3(params, NDMP_LOG_NORMAL, 737 "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm); 738 } 739 } 740 741 742 /* 743 * log_level_v3 744 * 745 * Log the backup level and date of the last and the current 746 * backup for level-type backup in the system log and also 747 * send them as normal log to the client. 748 * 749 * Parameters: 750 * params (input) - pointer to the parameters structure 751 * nlp (input) - pointer to the nlp structure 752 * 753 * Returns: 754 * void 755 */ 756 static void 757 log_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 758 { 759 MOD_LOGV3(params, NDMP_LOG_NORMAL, 760 "Date of the last level '%u': %s.\n", nlp->nlp_llevel, 761 cctime(&nlp->nlp_ldate)); 762 763 MOD_LOGV3(params, NDMP_LOG_NORMAL, 764 "Date of this level '%u': %s.\n", nlp->nlp_clevel, 765 cctime(&nlp->nlp_cdate)); 766 767 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Update: %s.\n", 768 NDMP_TORF(NLP_ISSET(nlp, NLPF_UPDATE))); 769 } 770 771 772 /* 773 * log_bk_params_v3 774 * 775 * Dispatcher function which calls the appropriate function 776 * for logging the backup date and level in the system log 777 * and also send them as normal log message to the client. 778 * 779 * Parameters: 780 * session (input) - pointer to the session 781 * params (input) - pointer to the parameters structure 782 * nlp (input) - pointer to the nlp structure 783 * 784 * Returns: 785 * void 786 */ 787 static void 788 log_bk_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 789 ndmp_lbr_params_t *nlp) 790 { 791 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Backing up \"%s\".\n", 792 nlp->nlp_backup_path); 793 794 if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_LOCAL) 795 MOD_LOGV3(params, NDMP_LOG_NORMAL, 796 "Tape record size: %d.\n", 797 session->ns_mover.md_record_size); 798 799 MOD_LOGV3(params, NDMP_LOG_NORMAL, "File history: %c.\n", 800 NDMP_YORN(NLP_ISSET(nlp, NLPF_FH))); 801 802 if (NLP_ISSET(nlp, NLPF_TOKENBK)) 803 log_date_token_v3(params, nlp); 804 else if (NLP_ISSET(nlp, NLPF_LBRBK)) 805 log_lbr_bk_v3(params, nlp); 806 else if (NLP_ISSET(nlp, NLPF_LEVELBK)) 807 log_level_v3(params, nlp); 808 else { 809 MOD_LOGV3(params, NDMP_LOG_ERROR, 810 "Internal error: backup level not defined for \"%s\".\n", 811 nlp->nlp_backup_path); 812 } 813 } 814 815 816 /* 817 * get_update_env_v3 818 * 819 * Is the UPDATE environment variable specified? If it is 820 * the corresponding flag is set in the flags field of the 821 * nlp structure, otherwise the flag is cleared. 822 * 823 * Parameters: 824 * params (input) - pointer to the parameters structure 825 * nlp (input) - pointer to the nlp structure 826 * 827 * Returns: 828 * void 829 */ 830 static void 831 get_update_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 832 { 833 char *envp; 834 835 envp = MOD_GETENV(params, "UPDATE"); 836 if (!envp) { 837 NLP_SET(nlp, NLPF_UPDATE); 838 NDMP_LOG(LOG_DEBUG, 839 "env(UPDATE) not defined, default to TRUE"); 840 } else { 841 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp); 842 if (IS_YORT(*envp)) 843 NLP_SET(nlp, NLPF_UPDATE); 844 else 845 NLP_UNSET(nlp, NLPF_UPDATE); 846 } 847 } 848 849 850 /* 851 * get_hist_env_v3 852 * 853 * Is backup history requested? If it is, the corresponding 854 * flag is set in the flags field of the nlp structure, otherwise 855 * the flag is cleared. 856 * 857 * Parameters: 858 * params (input) - pointer to the parameters structure 859 * nlp (input) - pointer to the nlp structure 860 * 861 * Returns: 862 * void 863 */ 864 static void 865 get_hist_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 866 { 867 char *envp; 868 869 envp = MOD_GETENV(params, "HIST"); 870 if (!envp) { 871 NDMP_LOG(LOG_DEBUG, "env(HIST) not defined"); 872 NLP_UNSET(nlp, NLPF_FH); 873 } else { 874 NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", envp); 875 if (IS_YORT(*envp) || IS_F(*envp)) 876 NLP_SET(nlp, NLPF_FH); 877 else 878 NLP_UNSET(nlp, NLPF_FH); 879 880 /* Force file format if specified */ 881 if (IS_F(*envp)) { 882 params->mp_file_history_path_func = 883 ndmpd_api_file_history_file_v3; 884 params->mp_file_history_dir_func = 0; 885 params->mp_file_history_node_func = 0; 886 } 887 } 888 } 889 890 891 /* 892 * get_exc_env_v3 893 * 894 * Gets the EXCLUDE environment variable and breaks it 895 * into strings. The separator of the EXCLUDE environment 896 * variable is the ',' character. 897 * 898 * Parameters: 899 * params (input) - pointer to the parameters structure 900 * nlp (input) - pointer to the nlp structure 901 * 902 * Returns: 903 * void 904 */ 905 static void 906 get_exc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 907 { 908 char *envp; 909 910 envp = MOD_GETENV(params, "EXCLUDE"); 911 if (!envp) { 912 NDMP_LOG(LOG_DEBUG, "env(EXCLUDE) not defined"); 913 nlp->nlp_exl = NULL; 914 } else { 915 NDMP_LOG(LOG_DEBUG, "env(EXCLUDE): \"%s\"", envp); 916 nlp->nlp_exl = split_env(envp, ','); 917 prl(nlp->nlp_exl); 918 } 919 } 920 921 922 /* 923 * get_inc_env_v3 924 * 925 * Gets the FILES environment variable that shows which files 926 * should be backed up, and breaks it into strings. The 927 * separator of the FILES environment variable is the space 928 * character. 929 * 930 * Parameters: 931 * params (input) - pointer to the parameters structure 932 * nlp (input) - pointer to the nlp structure 933 * 934 * Returns: 935 * void 936 */ 937 static void 938 get_inc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 939 { 940 char *envp; 941 942 envp = MOD_GETENV(params, "FILES"); 943 if (!envp) { 944 NDMP_LOG(LOG_DEBUG, "env(FILES) not defined"); 945 nlp->nlp_inc = NULL; 946 } else { 947 NDMP_LOG(LOG_DEBUG, "env(FILES): \"%s\"", envp); 948 nlp->nlp_inc = split_env(envp, ' '); 949 prl(nlp->nlp_inc); 950 } 951 } 952 953 954 /* 955 * get_direct_env_v3 956 * 957 * Gets the DIRECT environment variable that shows if the fh_info should 958 * be sent to the client or not. 959 * 960 * Parameters: 961 * params (input) - pointer to the parameters structure 962 * nlp (input) - pointer to the nlp structure 963 * 964 * Returns: 965 * void 966 */ 967 static void 968 get_direct_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 969 { 970 char *envp; 971 972 /* 973 * We should send the fh_info to the DMA, unless it is specified 974 * in the request that we should not send fh_info. 975 * At the moment we do not support DAR on directories, so if the user 976 * needs to restore a directory they should disable the DAR. 977 */ 978 if (params->mp_operation == NDMP_DATA_OP_RECOVER && !ndmp_dar_support) { 979 NDMP_LOG(LOG_DEBUG, "Direct Access Restore Disabled"); 980 NLP_UNSET(nlp, NLPF_DIRECT); 981 MOD_LOGV3(params, NDMP_LOG_NORMAL, 982 "DAR is disabled. Running Restore without DAR"); 983 return; 984 } 985 986 /* 987 * Regardless of whether DIRECT is defined at backup time we send 988 * back the fh_info, for some clients do not use get_backup_attrs. 989 * If operation is restore we have to unset the DIRECT, for 990 * some clients do not set the MOVER window. 991 */ 992 if (params->mp_operation == NDMP_DATA_OP_BACKUP) { 993 NDMP_LOG(LOG_DEBUG, "backup default env(DIRECT): YES"); 994 NLP_SET(nlp, NLPF_DIRECT); 995 } else { 996 997 envp = MOD_GETENV(params, "DIRECT"); 998 if (!envp) { 999 NDMP_LOG(LOG_DEBUG, "env(DIRECT) not defined"); 1000 NLP_UNSET(nlp, NLPF_DIRECT); 1001 } else { 1002 NDMP_LOG(LOG_DEBUG, "env(DIRECT): \"%s\"", envp); 1003 if (IS_YORT(*envp)) { 1004 NLP_SET(nlp, NLPF_DIRECT); 1005 NDMP_LOG(LOG_DEBUG, 1006 "Direct Access Restore Enabled"); 1007 } else { 1008 NLP_UNSET(nlp, NLPF_DIRECT); 1009 NDMP_LOG(LOG_DEBUG, 1010 "Direct Access Restore Disabled"); 1011 } 1012 } 1013 } 1014 1015 if (NLP_ISSET(nlp, NLPF_DIRECT)) { 1016 if (params->mp_operation == NDMP_DATA_OP_BACKUP) 1017 MOD_LOGV3(params, NDMP_LOG_NORMAL, 1018 "Direct Access Restore information is supported"); 1019 else 1020 MOD_LOGV3(params, NDMP_LOG_NORMAL, 1021 "Running Restore with Direct Access Restore"); 1022 } else { 1023 if (params->mp_operation == NDMP_DATA_OP_BACKUP) 1024 MOD_LOGV3(params, NDMP_LOG_NORMAL, 1025 "Direct Access Restore is not supported"); 1026 else 1027 MOD_LOGV3(params, NDMP_LOG_NORMAL, 1028 "Running Restore without Direct Access Restore"); 1029 } 1030 } 1031 1032 1033 /* 1034 * get_date_token_v3 1035 * 1036 * Parse the token passed as the argument. Evaluate it and 1037 * issue any warning or error if needed. Save the date and 1038 * token sequence in the nlp structure fields. The sequence 1039 * number in the token should be less than hard-limit. If 1040 * it's between soft and hard limit, a warning is issued. 1041 * There is a configurable limit which should be less than 1042 * the soft-limit saved in ndmp_max_tok_seq variable. 1043 * 1044 * The NLPF_TOKENBK flag is set in the nlp flags field to 1045 * show that the backup type is token-based. 1046 * 1047 * Parameters: 1048 * params (input) - pointer to the parameters structure 1049 * nlp (input) - pointer to the nlp structure 1050 * basedate (input) - the value of the BASE_DATE environment 1051 * variable. 1052 * 1053 * Returns: 1054 * NDMP_NO_ERR: on success 1055 * != NDMP_NO_ERR: Otherwise 1056 * 1057 */ 1058 static ndmp_error 1059 get_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, 1060 char *basedate) 1061 { 1062 char *endp; 1063 uint_t seq; 1064 ndmp_error rv; 1065 time_t tstamp; 1066 u_longlong_t tok; 1067 1068 if (!params || !nlp || !basedate || !*basedate) 1069 return (NDMP_ILLEGAL_ARGS_ERR); 1070 1071 if (MOD_GETENV(params, "LEVEL")) { 1072 MOD_LOGV3(params, NDMP_LOG_WARNING, 1073 "Both BASE_DATE and LEVEL environment variables " 1074 "defined.\n"); 1075 MOD_LOGCONTV3(params, NDMP_LOG_WARNING, 1076 "BASE_DATE is being used for this backup.\n"); 1077 } 1078 1079 tok = strtoll(basedate, &endp, 10); 1080 if (endp == basedate) { 1081 MOD_LOGV3(params, NDMP_LOG_ERROR, 1082 "Invalid BASE_DATE environment variable: \"%s\".\n", 1083 basedate); 1084 return (NDMP_ILLEGAL_ARGS_ERR); 1085 } 1086 1087 tstamp = tok & 0xffffffff; 1088 seq = (tok >> 32) & 0xffffffff; 1089 NDMP_LOG(LOG_DEBUG, "basedate \"%s\" %lld seq %u tstamp %u", 1090 basedate, tok, seq, tstamp); 1091 1092 if ((int)seq > ndmp_get_max_tok_seq()) { 1093 rv = NDMP_ILLEGAL_ARGS_ERR; 1094 MOD_LOGV3(params, NDMP_LOG_ERROR, 1095 "The sequence counter of the token exceeds the " 1096 "maximum permitted value.\n"); 1097 MOD_LOGCONTV3(params, NDMP_LOG_ERROR, 1098 "Token sequence: %u, maxiumum value: %u.\n", 1099 seq, ndmp_get_max_tok_seq()); 1100 } else if (seq >= NDMP_TOKSEQ_HLIMIT) { 1101 rv = NDMP_ILLEGAL_ARGS_ERR; 1102 MOD_LOGV3(params, NDMP_LOG_ERROR, 1103 "The sequence counter the of token exceeds the " 1104 "hard-limit.\n"); 1105 MOD_LOGCONTV3(params, NDMP_LOG_ERROR, 1106 "Token sequence: %u, hard-limit: %u.\n", 1107 seq, NDMP_TOKSEQ_HLIMIT); 1108 } else { 1109 rv = NDMP_NO_ERR; 1110 /* 1111 * Issue a warning if the seq is equal to the maximum 1112 * permitted seq number or equal to the soft-limit. 1113 */ 1114 if (seq == NDMP_TOKSEQ_SLIMIT) { 1115 MOD_LOGV3(params, NDMP_LOG_WARNING, 1116 "The sequence counter of the token has reached " 1117 "the soft-limit.\n"); 1118 MOD_LOGCONTV3(params, NDMP_LOG_WARNING, 1119 "Token sequence: %u, soft-limit: %u.\n", 1120 seq, NDMP_TOKSEQ_SLIMIT); 1121 } else if ((int)seq == ndmp_get_max_tok_seq()) { 1122 MOD_LOGV3(params, NDMP_LOG_WARNING, 1123 "The sequence counter of the token has reached " 1124 "the maximum permitted value.\n"); 1125 MOD_LOGCONTV3(params, NDMP_LOG_WARNING, 1126 "Token sequence: %u, maxiumum value: %u.\n", 1127 seq, ndmp_get_max_tok_seq()); 1128 } 1129 1130 /* 1131 * The current seq is equal to the seq field of the 1132 * token. It will be increased after successful backup 1133 * before setting the DUMP_DATE environment variable. 1134 */ 1135 nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME"); 1136 NLP_SET(nlp, NLPF_TOKENBK); 1137 NLP_UNSET(nlp, NLPF_LEVELBK); 1138 NLP_UNSET(nlp, NLPF_LBRBK); 1139 nlp->nlp_tokseq = seq; 1140 nlp->nlp_tokdate = tstamp; 1141 /* 1142 * The value of nlp_cdate will be set to the checkpoint 1143 * creation time after it is created. 1144 */ 1145 } 1146 1147 return (rv); 1148 } 1149 1150 1151 /* 1152 * get_lbr_bk_v3 1153 * 1154 * Sets the level fields of the nlp structures for 1155 * LBR-type backup. The NLPF_LBRBK flag of the 1156 * nlp flags is also set to show the backup type. 1157 * 1158 * Parameters: 1159 * params (input) - pointer to the parameters structure 1160 * nlp (input) - pointer to the nlp structure 1161 * type (input) - the backup level: 'F', 'A', 'I', 'D' or 1162 * their lower-case values. 1163 * 1164 * Returns: 1165 * NDMP_NO_ERR: on success 1166 * != NDMP_NO_ERR: Otherwise 1167 */ 1168 static ndmp_error 1169 get_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *type) 1170 { 1171 if (!params || !nlp || !type || !*type) 1172 return (NDMP_ILLEGAL_ARGS_ERR); 1173 1174 NLP_SET(nlp, NLPF_LBRBK); 1175 NLP_UNSET(nlp, NLPF_TOKENBK); 1176 NLP_UNSET(nlp, NLPF_LEVELBK); 1177 nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME"); 1178 nlp->nlp_llevel = toupper(*type); 1179 nlp->nlp_ldate = (time_t)0; 1180 nlp->nlp_clevel = nlp->nlp_llevel; 1181 (void) time(&nlp->nlp_cdate); 1182 1183 return (NDMP_NO_ERR); 1184 } 1185 1186 1187 /* 1188 * get_backup_level_v3 1189 * 1190 * Gets the backup level from the environment variables. If 1191 * BASE_DATE is specified, it will be used, otherwise LEVEL 1192 * will be used. If neither is specified, LEVEL = '0' is 1193 * assumed. 1194 * 1195 * Parameters: 1196 * params (input) - pointer to the parameters structure 1197 * nlp (input) - pointer to the nlp structure 1198 * 1199 * Returns: 1200 * NDMP_NO_ERR: on success 1201 * != NDMP_NO_ERR: Otherwise 1202 */ 1203 static ndmp_error 1204 get_backup_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 1205 { 1206 char *envp; 1207 ndmp_error rv; 1208 1209 /* 1210 * If the BASE_DATE env variable is specified use it, otherwise 1211 * look to see if LEVEL is specified. If LEVEL is not 1212 * specified either, backup level '0' must be made. Level backup 1213 * does not clear the archive bit. 1214 * 1215 * If LEVEL environment varaible is specified, values for 1216 * 'F', 'D', 'I' and 'A' (for 'Full', 'Differential', 1217 * 'Incremental', and 'Archive' is checked first. Then 1218 * level '0' to '9' will be checked. 1219 * 1220 * LEVEL environment variable can hold only one character. 1221 * If its length is longer than 1, an error is returned. 1222 */ 1223 envp = MOD_GETENV(params, "BASE_DATE"); 1224 if (envp) 1225 return (get_date_token_v3(params, nlp, envp)); 1226 1227 1228 envp = MOD_GETENV(params, "LEVEL"); 1229 if (!envp) { 1230 NDMP_LOG(LOG_DEBUG, "env(LEVEL) not defined, default to 0"); 1231 NLP_SET(nlp, NLPF_LEVELBK); 1232 NLP_UNSET(nlp, NLPF_LBRBK); 1233 NLP_UNSET(nlp, NLPF_TOKENBK); 1234 nlp->nlp_llevel = 0; 1235 nlp->nlp_ldate = 0; 1236 nlp->nlp_clevel = 0; 1237 /* 1238 * The value of nlp_cdate will be set to the checkpoint 1239 * creation time after it is created. 1240 */ 1241 return (NDMP_NO_ERR); 1242 } 1243 1244 if (*(envp+1) != '\0') { 1245 MOD_LOGV3(params, NDMP_LOG_ERROR, 1246 "Invalid backup level \"%s\".\n", envp); 1247 return (NDMP_ILLEGAL_ARGS_ERR); 1248 } 1249 1250 if (IS_LBR_BKTYPE(*envp)) 1251 return (get_lbr_bk_v3(params, nlp, envp)); 1252 1253 if (!isdigit(*envp)) { 1254 MOD_LOGV3(params, NDMP_LOG_ERROR, 1255 "Invalid backup level \"%s\".\n", envp); 1256 return (NDMP_ILLEGAL_ARGS_ERR); 1257 } 1258 1259 NLP_SET(nlp, NLPF_LEVELBK); 1260 NLP_UNSET(nlp, NLPF_LBRBK); 1261 NLP_UNSET(nlp, NLPF_TOKENBK); 1262 nlp->nlp_llevel = *envp - '0'; 1263 nlp->nlp_ldate = 0; 1264 nlp->nlp_clevel = nlp->nlp_llevel; 1265 /* 1266 * The value of nlp_cdate will be set to the checkpoint 1267 * creation time after it is created. 1268 */ 1269 if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel, 1270 &nlp->nlp_ldate) < 0) { 1271 MOD_LOGV3(params, NDMP_LOG_ERROR, 1272 "Getting dumpdates for %s level '%c'.\n", 1273 nlp->nlp_backup_path, *envp); 1274 return (NDMP_NO_MEM_ERR); 1275 } else { 1276 get_update_env_v3(params, nlp); 1277 rv = NDMP_NO_ERR; 1278 } 1279 1280 return (rv); 1281 } 1282 1283 1284 /* 1285 * save_date_token_v3 1286 * 1287 * Make the value of DUMP_DATE env variable and append the values 1288 * of the current backup in the file specified with the DMP_NAME 1289 * env variable if any file is specified. The file will be 1290 * relative name in the backup directory path. 1291 * 1292 * Parameters: 1293 * params (input) - pointer to the parameters structure 1294 * nlp (input) - pointer to the nlp structure 1295 * 1296 * Returns: 1297 * void 1298 */ 1299 static void 1300 save_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 1301 { 1302 char val[QUAD_DECIMAL_LEN]; 1303 u_longlong_t tok; 1304 1305 if (!params || !nlp) 1306 return; 1307 1308 nlp->nlp_tokseq++; 1309 tok = ((u_longlong_t)nlp->nlp_tokseq << 32) | nlp->nlp_cdate; 1310 (void) snprintf(val, sizeof (val), "%llu", tok); 1311 1312 NDMP_LOG(LOG_DEBUG, "tok: %lld %s", tok, val); 1313 1314 if (MOD_SETENV(params, "DUMP_DATE", val) != 0) { 1315 MOD_LOGV3(params, NDMP_LOG_ERROR, 1316 "Could not set DUMP_DATE to %s", val); 1317 } else if (!nlp->nlp_dmpnm) { 1318 NDMP_LOG(LOG_DEBUG, "No log file defined"); 1319 } else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path, 1320 nlp->nlp_tokseq, nlp->nlp_tokdate) < 0) { 1321 MOD_LOGV3(params, NDMP_LOG_ERROR, 1322 "Saving backup date for \"%s\" in \"%s\".\n", 1323 nlp->nlp_backup_path, nlp->nlp_dmpnm); 1324 } 1325 } 1326 1327 1328 /* 1329 * save_lbr_bk_v3 1330 * 1331 * Append the backup type and date in the DMP_NAME file for 1332 * LBR-type backup if any file is specified. 1333 * 1334 * Parameters: 1335 * params (input) - pointer to the parameters structure 1336 * nlp (input) - pointer to the nlp structure 1337 * 1338 * Returns: 1339 * void 1340 */ 1341 static void 1342 save_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 1343 { 1344 if (!params || !nlp) 1345 return; 1346 1347 if (!nlp->nlp_dmpnm) { 1348 NDMP_LOG(LOG_DEBUG, "No log file defined"); 1349 } else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path, 1350 nlp->nlp_clevel, nlp->nlp_cdate) < 0) { 1351 MOD_LOGV3(params, NDMP_LOG_ERROR, 1352 "Saving backup date for \"%s\" in \"%s\".\n", 1353 nlp->nlp_backup_path, nlp->nlp_dmpnm); 1354 } 1355 } 1356 1357 1358 /* 1359 * save_level_v3 1360 * 1361 * Save the date and level of the current backup in the dumpdates 1362 * file. 1363 * 1364 * Parameters: 1365 * params (input) - pointer to the parameters structure 1366 * nlp (input) - pointer to the nlp structure 1367 * 1368 * Returns: 1369 * void 1370 */ 1371 static void 1372 save_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 1373 { 1374 if (!params || !nlp) 1375 return; 1376 1377 if (!NLP_SHOULD_UPDATE(nlp)) { 1378 NDMP_LOG(LOG_DEBUG, "update not requested"); 1379 } else if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel, 1380 nlp->nlp_cdate) < 0) { 1381 MOD_LOGV3(params, NDMP_LOG_ERROR, "Logging backup date.\n"); 1382 } 1383 } 1384 1385 1386 /* 1387 * save_backup_date_v3 1388 * 1389 * A dispatcher function to call the corresponding save function 1390 * based on the backup type. 1391 * 1392 * Parameters: 1393 * params (input) - pointer to the parameters structure 1394 * nlp (input) - pointer to the nlp structure 1395 * 1396 * Returns: 1397 * void 1398 */ 1399 static void 1400 save_backup_date_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 1401 { 1402 if (!params || !nlp) 1403 return; 1404 1405 if (NLP_ISSET(nlp, NLPF_TOKENBK)) 1406 save_date_token_v3(params, nlp); 1407 else if (NLP_ISSET(nlp, NLPF_LBRBK)) 1408 save_lbr_bk_v3(params, nlp); 1409 else if (NLP_ISSET(nlp, NLPF_LEVELBK)) 1410 save_level_v3(params, nlp); 1411 else { 1412 MOD_LOGV3(params, NDMP_LOG_ERROR, 1413 "Internal error: lost backup level type for \"%s\".\n", 1414 nlp->nlp_backup_path); 1415 } 1416 } 1417 1418 1419 /* 1420 * backup_alloc_structs_v3 1421 * 1422 * Create the structures for V3 backup. This includes: 1423 * Job stats 1424 * Reader writer IPC 1425 * File history callback structure 1426 * 1427 * Parameters: 1428 * session (input) - pointer to the session 1429 * jname (input) - name assigned to the current backup for 1430 * job stats strucure 1431 * 1432 * Returns: 1433 * 0: on success 1434 * -1: otherwise 1435 */ 1436 static int 1437 backup_alloc_structs_v3(ndmpd_session_t *session, char *jname) 1438 { 1439 int n; 1440 long xfer_size; 1441 ndmp_lbr_params_t *nlp; 1442 tlm_commands_t *cmds; 1443 1444 nlp = ndmp_get_nlp(session); 1445 if (!nlp) { 1446 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1447 return (-1); 1448 } 1449 1450 nlp->nlp_jstat = tlm_new_job_stats(jname); 1451 if (!nlp->nlp_jstat) { 1452 NDMP_LOG(LOG_DEBUG, "Creating job stats"); 1453 return (-1); 1454 } 1455 1456 cmds = &nlp->nlp_cmds; 1457 (void) memset(cmds, 0, sizeof (*cmds)); 1458 1459 xfer_size = ndmp_buffer_get_size(session); 1460 if (xfer_size < 512*KILOBYTE) { 1461 /* 1462 * Read multiple of mover_record_size near to 512K. This 1463 * will prevent the data being copied in the mover buffer 1464 * when we write the data. 1465 */ 1466 n = 512 * KILOBYTE / xfer_size; 1467 if (n <= 0) 1468 n = 1; 1469 xfer_size *= n; 1470 NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d", 1471 xfer_size); 1472 } 1473 1474 cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size); 1475 if (!cmds->tcs_command) { 1476 tlm_un_ref_job_stats(jname); 1477 return (-1); 1478 } 1479 1480 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session, 1481 ndmpd_fhpath_v3_cb, ndmpd_fhdir_v3_cb, ndmpd_fhnode_v3_cb); 1482 if (!nlp->nlp_logcallbacks) { 1483 tlm_release_reader_writer_ipc(cmds->tcs_command); 1484 tlm_un_ref_job_stats(jname); 1485 return (-1); 1486 } 1487 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks); 1488 nlp->nlp_restored = NULL; 1489 1490 return (0); 1491 } 1492 1493 1494 /* 1495 * restore_alloc_structs_v3 1496 * 1497 * Create the structures for V3 Restore. This includes: 1498 * Job stats 1499 * Reader writer IPC 1500 * File recovery callback structure 1501 * 1502 * Parameters: 1503 * session (input) - pointer to the session 1504 * jname (input) - name assigned to the current backup for 1505 * job stats strucure 1506 * 1507 * Returns: 1508 * 0: on success 1509 * -1: otherwise 1510 */ 1511 int 1512 restore_alloc_structs_v3(ndmpd_session_t *session, char *jname) 1513 { 1514 long xfer_size; 1515 ndmp_lbr_params_t *nlp; 1516 tlm_commands_t *cmds; 1517 1518 nlp = ndmp_get_nlp(session); 1519 if (!nlp) { 1520 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1521 return (-1); 1522 } 1523 1524 /* this is used in ndmpd_path_restored_v3() */ 1525 nlp->nlp_lastidx = -1; 1526 1527 nlp->nlp_jstat = tlm_new_job_stats(jname); 1528 if (!nlp->nlp_jstat) { 1529 NDMP_LOG(LOG_DEBUG, "Creating job stats"); 1530 return (-1); 1531 } 1532 1533 cmds = &nlp->nlp_cmds; 1534 (void) memset(cmds, 0, sizeof (*cmds)); 1535 1536 xfer_size = ndmp_buffer_get_size(session); 1537 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size); 1538 if (!cmds->tcs_command) { 1539 tlm_un_ref_job_stats(jname); 1540 return (-1); 1541 } 1542 1543 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session, 1544 ndmpd_path_restored_v3, NULL, NULL); 1545 if (!nlp->nlp_logcallbacks) { 1546 tlm_release_reader_writer_ipc(cmds->tcs_command); 1547 tlm_un_ref_job_stats(jname); 1548 return (-1); 1549 } 1550 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks); 1551 1552 nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0); 1553 if (nlp->nlp_rsbm < 0) { 1554 NDMP_LOG(LOG_ERR, "Out of memory."); 1555 lbrlog_callbacks_done(nlp->nlp_logcallbacks); 1556 tlm_release_reader_writer_ipc(cmds->tcs_command); 1557 tlm_un_ref_job_stats(jname); 1558 return (-1); 1559 } 1560 1561 return (0); 1562 } 1563 1564 1565 /* 1566 * free_structs_v3 1567 * 1568 * Release the resources allocated by backup_alloc_structs_v3 1569 * function. 1570 * 1571 * Parameters: 1572 * session (input) - pointer to the session 1573 * jname (input) - name assigned to the current backup for 1574 * job stats strucure 1575 * 1576 * Returns: 1577 * void 1578 */ 1579 /*ARGSUSED*/ 1580 static void 1581 free_structs_v3(ndmpd_session_t *session, char *jname) 1582 { 1583 ndmp_lbr_params_t *nlp; 1584 tlm_commands_t *cmds; 1585 1586 nlp = ndmp_get_nlp(session); 1587 if (!nlp) { 1588 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1589 return; 1590 } 1591 cmds = &nlp->nlp_cmds; 1592 if (!cmds) { 1593 NDMP_LOG(LOG_DEBUG, "cmds == NULL"); 1594 return; 1595 } 1596 1597 if (nlp->nlp_logcallbacks) { 1598 lbrlog_callbacks_done(nlp->nlp_logcallbacks); 1599 nlp->nlp_logcallbacks = NULL; 1600 } else 1601 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL"); 1602 1603 if (cmds->tcs_command) { 1604 if (cmds->tcs_command->tc_buffers != NULL) 1605 tlm_release_reader_writer_ipc(cmds->tcs_command); 1606 else 1607 NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL"); 1608 cmds->tcs_command = NULL; 1609 } else 1610 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL"); 1611 1612 if (nlp->nlp_bkmap >= 0) { 1613 (void) dbm_free(nlp->nlp_bkmap); 1614 nlp->nlp_bkmap = -1; 1615 } 1616 1617 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) { 1618 if (nlp->nlp_rsbm < 0) { 1619 NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm); 1620 } else { 1621 (void) bm_free(nlp->nlp_rsbm); 1622 nlp->nlp_rsbm = -1; 1623 } 1624 } 1625 } 1626 1627 1628 /* 1629 * backup_dirv3 1630 * 1631 * Backup a directory and update the bytes processed field of the 1632 * data server. 1633 * 1634 * Parameters: 1635 * bpp (input) - pointer to the backup parameters structure 1636 * pnp (input) - pointer to the path node 1637 * enp (input) - pointer to the entry node 1638 * 1639 * Returns: 1640 * 0: on success 1641 * != 0: otherwise 1642 */ 1643 static int 1644 backup_dirv3(bk_param_v3_t *bpp, fst_node_t *pnp, 1645 fst_node_t *enp) 1646 { 1647 longlong_t apos, bpos; 1648 acl_t *aclp = NULL; 1649 char *acltp; 1650 struct stat64 st; 1651 char fullpath[TLM_MAX_PATH_NAME]; 1652 char *p; 1653 1654 if (!bpp || !pnp || !enp) { 1655 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1656 return (-1); 1657 } 1658 1659 NDMP_LOG(LOG_DEBUG, "d(%s)", bpp->bp_tmp); 1660 1661 if (lstat64(bpp->bp_tmp, &st) != 0) 1662 return (0); 1663 1664 if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) { 1665 NDMP_LOG(LOG_DEBUG, "acl_get error errno=%d", errno); 1666 return (-1); 1667 } 1668 if (aclp && (acltp = acl_totext(aclp, 1669 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) { 1670 (void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info, 1671 acltp, TLM_MAX_ACL_TXT); 1672 acl_free(aclp); 1673 free(acltp); 1674 } else { 1675 *bpp->bp_tlmacl->acl_info.attr_info = '\0'; 1676 } 1677 1678 bpos = tlm_get_data_offset(bpp->bp_lcmd); 1679 1680 p = bpp->bp_tmp + strlen(bpp->bp_chkpnm); 1681 if (*p == '/') 1682 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s", 1683 bpp->bp_unchkpnm, p); 1684 else 1685 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s", 1686 bpp->bp_unchkpnm, p); 1687 1688 if (tm_tar_ops.tm_putdir != NULL) 1689 (void) (tm_tar_ops.tm_putdir)(fullpath, bpp->bp_tlmacl, 1690 bpp->bp_lcmd, bpp->bp_js); 1691 1692 apos = tlm_get_data_offset(bpp->bp_lcmd); 1693 bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed += 1694 apos - bpos; 1695 1696 return (0); 1697 } 1698 1699 1700 /* 1701 * backup_filev3 1702 * 1703 * Backup a file and update the bytes processed field of the 1704 * data server. 1705 * 1706 * Parameters: 1707 * bpp (input) - pointer to the backup parameters structure 1708 * pnp (input) - pointer to the path node 1709 * enp (input) - pointer to the entry node 1710 * 1711 * Returns: 1712 * 0: on success 1713 * != 0: otherwise 1714 */ 1715 static int 1716 backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp, 1717 fst_node_t *enp) 1718 { 1719 char *ent; 1720 longlong_t rv; 1721 longlong_t apos, bpos; 1722 acl_t *aclp = NULL; 1723 char *acltp; 1724 struct stat64 st; 1725 char fullpath[TLM_MAX_PATH_NAME]; 1726 char *p; 1727 1728 if (!bpp || !pnp || !enp) { 1729 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1730 return (-1); 1731 } 1732 1733 NDMP_LOG(LOG_DEBUG, "f(%s)", bpp->bp_tmp); 1734 1735 if (lstat64(bpp->bp_tmp, &st) != 0) 1736 return (0); 1737 1738 if (!S_ISLNK(bpp->bp_tlmacl->acl_attr.st_mode)) { 1739 if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) { 1740 NDMP_LOG(LOG_DEBUG, "acl_get error"); 1741 return (-1); 1742 } 1743 1744 if (aclp && 1745 (acltp = acl_totext(aclp, 1746 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) { 1747 (void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info, 1748 acltp, TLM_MAX_ACL_TXT); 1749 acl_free(aclp); 1750 free(acltp); 1751 } else { 1752 *bpp->bp_tlmacl->acl_info.attr_info = '\0'; 1753 } 1754 } 1755 1756 bpos = tlm_get_data_offset(bpp->bp_lcmd); 1757 ent = enp->tn_path ? enp->tn_path : ""; 1758 1759 p = pnp->tn_path + strlen(bpp->bp_chkpnm); 1760 if (*p == '/') 1761 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s", 1762 bpp->bp_unchkpnm, p); 1763 else 1764 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s", 1765 bpp->bp_unchkpnm, p); 1766 1767 if (tm_tar_ops.tm_putfile != NULL) 1768 rv = (tm_tar_ops.tm_putfile)(fullpath, ent, pnp->tn_path, 1769 bpp->bp_tlmacl, bpp->bp_cmds, bpp->bp_lcmd, bpp->bp_js, 1770 bpp->bp_session->hardlink_q); 1771 1772 apos = tlm_get_data_offset(bpp->bp_lcmd); 1773 bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed += 1774 apos - bpos; 1775 1776 return (rv < 0 ? rv : 0); 1777 } 1778 1779 1780 /* 1781 * check_bk_args 1782 * 1783 * Check the argument of the bpp. This is shared function between 1784 * timebk_v3 and lbrbk_v3 functions. The checks include: 1785 * - The bpp itself. 1786 * - If the session pointer of the bpp is valid. 1787 * - If the session connection to the DMA is closed. 1788 * - If the nlp pointer of the bpp is valid. 1789 * - If the backup is aborted. 1790 * 1791 * Parameters: 1792 * bpp (input) - pointer to the backup parameters structure 1793 * 1794 * Returns: 1795 * 0: if everything's OK 1796 * != 0: otherwise 1797 */ 1798 static int 1799 check_bk_args(bk_param_v3_t *bpp) 1800 { 1801 int rv; 1802 1803 if (!bpp) { 1804 rv = -1; 1805 NDMP_LOG(LOG_DEBUG, "Lost bpp"); 1806 } else if (!bpp->bp_session) { 1807 rv = -1; 1808 NDMP_LOG(LOG_DEBUG, "Session is NULL"); 1809 } else if (bpp->bp_session->ns_eof) { 1810 rv = -1; 1811 NDMP_LOG(LOG_INFO, 1812 "Connection client is closed for backup \"%s\"", 1813 bpp->bp_nlp->nlp_backup_path); 1814 } else if (!bpp->bp_nlp) { 1815 NDMP_LOG(LOG_DEBUG, "Lost nlp"); 1816 return (-1); 1817 } else if (bpp->bp_session->ns_data.dd_abort) { 1818 rv = -1; 1819 NDMP_LOG(LOG_INFO, "Backup aborted \"%s\"", 1820 bpp->bp_nlp->nlp_backup_path); 1821 } else 1822 rv = 0; 1823 1824 return (rv); 1825 } 1826 1827 1828 /* 1829 * shouldskip 1830 * 1831 * Determines if the current entry should be skipped or it 1832 * should be backed up. 1833 * 1834 * Parameters: 1835 * bpp (input) - pointer to the backup parameters structure 1836 * pnp (input) - pointer to the path node 1837 * enp (input) - pointer to the entry node 1838 * errp (output) - pointer to the error value that should be 1839 * returned by the caller 1840 * 1841 * Returns: 1842 * TRUE: if the entry should not be backed up 1843 * FALSE: otherwise 1844 */ 1845 static boolean_t 1846 shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp, 1847 fst_node_t *enp, int *errp) 1848 { 1849 char *ent; 1850 boolean_t rv; 1851 struct stat64 *estp; 1852 1853 if (!bpp || !pnp || !enp || !errp) { 1854 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1855 return (TRUE); 1856 } 1857 1858 if (!enp->tn_path) { 1859 ent = ""; 1860 estp = pnp->tn_st; 1861 } else { 1862 ent = enp->tn_path; 1863 estp = enp->tn_st; 1864 } 1865 1866 /* 1867 * When excluding or skipping entries, FST_SKIP should be 1868 * returned, otherwise, 0 should be returned to 1869 * get other entries in the directory of this entry. 1870 */ 1871 if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) { 1872 rv = TRUE; 1873 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0; 1874 NDMP_LOG(LOG_DEBUG, "Skipping %d %s/%s", 1875 *errp, pnp->tn_path, ent); 1876 } else if (tlm_is_excluded(pnp->tn_path, ent, bpp->bp_excls)) { 1877 rv = TRUE; 1878 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0; 1879 NDMP_LOG(LOG_DEBUG, "excl %d \"%s/%s\"", 1880 *errp, pnp->tn_path, ent); 1881 } else if (inexl(bpp->bp_nlp->nlp_exl, ent)) { 1882 rv = TRUE; 1883 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0; 1884 NDMP_LOG(LOG_DEBUG, "out %d \"%s/%s\"", 1885 *errp, pnp->tn_path, ent); 1886 } else if (!S_ISDIR(estp->st_mode) && 1887 !ininc(bpp->bp_nlp->nlp_inc, ent)) { 1888 rv = TRUE; 1889 *errp = 0; 1890 NDMP_LOG(LOG_DEBUG, "!in \"%s/%s\"", pnp->tn_path, ent); 1891 } else 1892 rv = FALSE; 1893 1894 return (rv); 1895 } 1896 1897 1898 /* 1899 * ischngd 1900 * 1901 * Check if the object specified should be backed up or not. 1902 * If stp belongs to a directory and if it is marked in the 1903 * bitmap vector, it shows that either the directory itself is 1904 * modified or there is something below it that will be backed 1905 * up. 1906 * 1907 * By setting ndmp_force_bk_dirs global variable to a non-zero 1908 * value, directories are backed up anyways. 1909 * 1910 * Backing up the directories unconditionally helps 1911 * restoring the metadata of directories as well, when one 1912 * of the objects below them are being restored. 1913 * 1914 * For non-directory objects, if the modification or change 1915 * time of the object is after the date specified by the 1916 * bk_selector_t, the the object must be backed up. 1917 */ 1918 static boolean_t 1919 ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp) 1920 { 1921 boolean_t rv; 1922 1923 if (!stp) { 1924 rv = FALSE; 1925 NDMP_LOG(LOG_DEBUG, "stp is NULL"); 1926 } else if (!nlp) { 1927 rv = FALSE; 1928 NDMP_LOG(LOG_DEBUG, "nlp is NULL"); 1929 } else if (t == 0) { 1930 /* 1931 * if we are doing base backup then we do not need to 1932 * check the time, for we should backup everything. 1933 */ 1934 rv = TRUE; 1935 NDMP_LOG(LOG_DEBUG, "Base Backup"); 1936 } else if (S_ISDIR(stp->st_mode) && ndmp_force_bk_dirs) { 1937 rv = TRUE; 1938 NDMP_LOG(LOG_DEBUG, "d(%lu)", (uint_t)stp->st_ino); 1939 } else if (S_ISDIR(stp->st_mode) && 1940 dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino) && 1941 ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) || 1942 (NLP_ISTAR(nlp) && ndmp_tar_path_node))) { 1943 /* 1944 * If the object is a directory and it leads to a modified 1945 * object (that should be backed up) and for that type of 1946 * backup the path nodes should be backed up, then return 1947 * TRUE. 1948 * 1949 * This is required by some DMAs like Backup Express, which 1950 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar) 1951 * for the intermediate directories of a modified object. 1952 * Other DMAs, like net_backup and net_worker, do not have such 1953 * requirement. This requirement makes sense for dump format 1954 * but for 'tar' format, it does not. In provision to the 1955 * NDMP-v4 spec, for 'tar' format the intermediate directories 1956 * need not to be reported. 1957 */ 1958 rv = TRUE; 1959 NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)stp->st_ino); 1960 } else if (stp->st_mtime > t) { 1961 rv = TRUE; 1962 NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu", 1963 (uint_t)stp->st_ino, (uint_t)stp->st_mtime, (uint_t)t); 1964 } else if (stp->st_ctime > t) { 1965 if (NLP_IGNCTIME(nlp)) { 1966 rv = FALSE; 1967 NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu", 1968 (uint_t)stp->st_ino, (uint_t)stp->st_ctime, 1969 (uint_t)t); 1970 } else { 1971 rv = TRUE; 1972 NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu", 1973 (uint_t)stp->st_ino, (uint_t)stp->st_ctime, 1974 (uint_t)t); 1975 } 1976 } else { 1977 rv = FALSE; 1978 NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu", 1979 (uint_t)stp->st_ino, (uint_t)stp->st_mtime, 1980 (uint_t)stp->st_ctime, (uint_t)t); 1981 } 1982 1983 return (rv); 1984 } 1985 1986 1987 /* 1988 * iscreated 1989 * 1990 * This function is used to check last mtime (currently inside the ACL 1991 * structure) instead of ctime for checking if the file is to be backed up 1992 * or not. See option "inc.lmtime" for more details 1993 */ 1994 /*ARGSUSED*/ 1995 int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl, 1996 time_t t) 1997 { 1998 int ret; 1999 acl_t *aclp = NULL; 2000 char *acltp; 2001 2002 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags); 2003 if (NLP_INCLMTIME(nlp) == FALSE) 2004 return (0); 2005 2006 ret = acl_get(name, ACL_NO_TRIVIAL, &aclp); 2007 if (ret != 0) { 2008 NDMP_LOG(LOG_DEBUG, 2009 "Error getting the acl information: err %d", ret); 2010 return (0); 2011 } 2012 if (aclp && (acltp = acl_totext(aclp, 2013 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) { 2014 (void) strlcpy(tacl->acl_info.attr_info, acltp, 2015 TLM_MAX_ACL_TXT); 2016 acl_free(aclp); 2017 free(acltp); 2018 } 2019 2020 /* Need to add support for last mtime */ 2021 2022 return (0); 2023 } 2024 2025 /* 2026 * size_cb 2027 * 2028 * The callback function for calculating the size of 2029 * the backup path. This is used to get an estimate 2030 * of the progress of backup during NDMP backup 2031 */ 2032 static int 2033 size_cb(void *arg, fst_node_t *pnp, fst_node_t *enp) 2034 { 2035 struct stat64 *stp; 2036 2037 stp = enp->tn_path ? enp->tn_st : pnp->tn_st; 2038 *((u_longlong_t *)arg) += stp->st_size; 2039 2040 return (0); 2041 } 2042 2043 /* 2044 * timebk_v3 2045 * 2046 * The callback function for backing up objects based on 2047 * their time stamp. This is shared between token-based 2048 * and level-based backup, which look at the time stamps 2049 * of the objects to determine if they should be backed 2050 * up. 2051 * 2052 * Parameters: 2053 * arg (input) - pointer to the backup parameters structure 2054 * pnp (input) - pointer to the path node 2055 * enp (input) - pointer to the entry node 2056 * 2057 * Returns: 2058 * 0: if backup should continue 2059 * -1: if the backup should be stopped 2060 * FST_SKIP: if backing up the current directory is enough 2061 */ 2062 static int 2063 timebk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp) 2064 { 2065 char *ent; 2066 int rv; 2067 time_t t; 2068 bk_param_v3_t *bpp; 2069 struct stat64 *stp; 2070 fs_fhandle_t *fhp; 2071 2072 bpp = (bk_param_v3_t *)arg; 2073 2074 rv = check_bk_args(bpp); 2075 if (rv != 0) 2076 return (rv); 2077 2078 stp = enp->tn_path ? enp->tn_st : pnp->tn_st; 2079 if (shouldskip(bpp, pnp, enp, &rv)) 2080 return (rv); 2081 2082 if (enp->tn_path) { 2083 ent = enp->tn_path; 2084 stp = enp->tn_st; 2085 fhp = enp->tn_fh; 2086 } else { 2087 ent = ""; 2088 stp = pnp->tn_st; 2089 fhp = pnp->tn_fh; 2090 } 2091 2092 2093 if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) { 2094 NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent); 2095 return (FST_SKIP); 2096 } 2097 if (NLP_ISSET(bpp->bp_nlp, NLPF_TOKENBK)) 2098 t = bpp->bp_nlp->nlp_tokdate; 2099 else if (NLP_ISSET(bpp->bp_nlp, NLPF_LEVELBK)) { 2100 t = bpp->bp_nlp->nlp_ldate; 2101 } else { 2102 NDMP_LOG(LOG_DEBUG, "Unknown backup type on \"%s/%s\"", 2103 pnp->tn_path, ent); 2104 return (-1); 2105 } 2106 2107 if (S_ISDIR(stp->st_mode)) { 2108 bpp->bp_tlmacl->acl_dir_fh = *fhp; 2109 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks, 2110 bpp->bp_tmp, stp); 2111 2112 if (ischngd(stp, t, bpp->bp_nlp)) { 2113 (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp, 2114 sizeof (struct stat64)); 2115 rv = backup_dirv3(bpp, pnp, enp); 2116 } 2117 } else { 2118 if (ischngd(stp, t, bpp->bp_nlp) || 2119 iscreated(bpp->bp_nlp, bpp->bp_tmp, bpp->bp_tlmacl, t)) { 2120 rv = 0; 2121 (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp, 2122 sizeof (struct stat64)); 2123 bpp->bp_tlmacl->acl_fil_fh = *fhp; 2124 (void) backup_filev3(bpp, pnp, enp); 2125 } 2126 } 2127 2128 return (rv); 2129 } 2130 2131 2132 /* 2133 * lbrbk_v3 2134 * 2135 * The callback function for backing up objects based on 2136 * their archive directory bit. This is used in LBR-type 2137 * backup. In which the objects are backed up if their 2138 * archive bit is set. 2139 * 2140 * Parameters: 2141 * arg (input) - pointer to the backup parameters structure 2142 * pnp (input) - pointer to the path node 2143 * enp (input) - pointer to the entry node 2144 * 2145 * Returns: 2146 * 0: if backup should continue 2147 * -1: if the backup should be stopped 2148 * FST_SKIP: if backing up the current directory is enough 2149 */ 2150 static int 2151 lbrbk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp) 2152 { 2153 char *ent; 2154 int rv; 2155 bk_param_v3_t *bpp; 2156 struct stat64 *stp; 2157 fs_fhandle_t *fhp; 2158 2159 bpp = (bk_param_v3_t *)arg; 2160 rv = check_bk_args(bpp); 2161 if (rv != 0) 2162 return (rv); 2163 2164 stp = enp->tn_path ? enp->tn_st : pnp->tn_st; 2165 if (shouldskip(bpp, pnp, enp, &rv)) 2166 return (rv); 2167 2168 if (enp->tn_path) { 2169 ent = enp->tn_path; 2170 stp = enp->tn_st; 2171 fhp = enp->tn_fh; 2172 } else { 2173 ent = ""; 2174 stp = pnp->tn_st; 2175 fhp = pnp->tn_fh; 2176 } 2177 2178 if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) { 2179 NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent); 2180 return (FST_SKIP); 2181 } 2182 if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) { 2183 NDMP_LOG(LOG_DEBUG, "!NLPF_LBRBK"); 2184 return (-1); 2185 } 2186 2187 if (S_ISDIR(stp->st_mode)) { 2188 bpp->bp_tlmacl->acl_dir_fh = *fhp; 2189 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks, 2190 bpp->bp_tmp, stp); 2191 2192 if (SHOULD_LBRBK(bpp)) { 2193 bpp->bp_tlmacl->acl_attr = *stp; 2194 rv = backup_dirv3(bpp, pnp, enp); 2195 } 2196 } else if (SHOULD_LBRBK(bpp)) { 2197 rv = 0; 2198 bpp->bp_tlmacl->acl_attr = *stp; 2199 bpp->bp_tlmacl->acl_fil_fh = *fhp; 2200 (void) backup_filev3(bpp, pnp, enp); 2201 } 2202 2203 return (rv); 2204 } 2205 2206 2207 /* 2208 * backup_reader_v3 2209 * 2210 * The reader thread for the backup. It sets up the callback 2211 * parameters and traverses the backup hierarchy in level-order 2212 * way. 2213 * 2214 * Parameters: 2215 * jname (input) - name assigned to the current backup for 2216 * job stats strucure 2217 * nlp (input) - pointer to the nlp structure 2218 * cmds (input) - pointer to the tlm_commands_t structure 2219 * 2220 * Returns: 2221 * 0: on success 2222 * != 0: otherwise 2223 */ 2224 static int 2225 backup_reader_v3(backup_reader_arg_t *argp) 2226 { 2227 int rv; 2228 tlm_cmd_t *lcmd; 2229 tlm_acls_t tlm_acls; 2230 longlong_t bpos, n; 2231 bk_param_v3_t bp; 2232 fs_traverse_t ft; 2233 char *jname; 2234 ndmp_lbr_params_t *nlp; 2235 tlm_commands_t *cmds; 2236 2237 if (!argp) 2238 return (-1); 2239 2240 jname = argp->br_jname; 2241 nlp = argp->br_nlp; 2242 cmds = argp->br_cmds; 2243 2244 rv = 0; 2245 lcmd = cmds->tcs_command; 2246 lcmd->tc_ref++; 2247 cmds->tcs_reader_count++; 2248 2249 (void) memset(&tlm_acls, 0, sizeof (tlm_acls)); 2250 2251 /* NDMP parameters */ 2252 bp.bp_session = nlp->nlp_session; 2253 bp.bp_nlp = nlp; 2254 2255 /* LBR-related parameters */ 2256 bp.bp_js = tlm_ref_job_stats(jname); 2257 bp.bp_cmds = cmds; 2258 bp.bp_lcmd = lcmd; 2259 bp.bp_tlmacl = &tlm_acls; 2260 bp.bp_opr = 0; 2261 2262 /* release the parent thread, after referencing the job stats */ 2263 (void) pthread_barrier_wait(&argp->br_barrier); 2264 2265 bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME); 2266 if (!bp.bp_tmp) 2267 return (-1); 2268 2269 /* 2270 * Make the checkpointed paths for traversing the 2271 * backup hierarchy, if we make the checkpoint. 2272 */ 2273 bp.bp_unchkpnm = nlp->nlp_backup_path; 2274 if (!NLP_ISCHKPNTED(nlp)) { 2275 tlm_acls.acl_checkpointed = TRUE; 2276 bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME); 2277 if (!bp.bp_chkpnm) { 2278 NDMP_FREE(bp.bp_tmp); 2279 return (-1); 2280 } 2281 (void) tlm_build_snapshot_name(nlp->nlp_backup_path, 2282 bp.bp_chkpnm, nlp->nlp_jstat->js_job_name); 2283 } else { 2284 tlm_acls.acl_checkpointed = FALSE; 2285 bp.bp_chkpnm = nlp->nlp_backup_path; 2286 } 2287 bp.bp_excls = ndmpd_make_exc_list(); 2288 2289 /* set traversing arguments */ 2290 ft.ft_path = nlp->nlp_backup_path; 2291 ft.ft_lpath = bp.bp_chkpnm; 2292 2293 NDMP_LOG(LOG_DEBUG, "path %s lpath %s", ft.ft_path, ft.ft_lpath); 2294 if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) { 2295 ft.ft_callbk = timebk_v3; 2296 tlm_acls.acl_clear_archive = FALSE; 2297 } else if (NLP_ISSET(nlp, NLPF_LBRBK)) { 2298 ft.ft_callbk = lbrbk_v3; 2299 tlm_acls.acl_clear_archive = FALSE; 2300 2301 NDMP_LOG(LOG_DEBUG, "bp_opr %x clr_arc %c", 2302 bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive)); 2303 } else { 2304 rv = -1; 2305 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR, 2306 "Unknow backup type.\n"); 2307 } 2308 ft.ft_arg = &bp; 2309 ft.ft_logfp = (ft_log_t)ndmp_log; 2310 ft.ft_flags = FST_VERBOSE | FST_STOP_ONERR; 2311 2312 /* take into account the header written to the stream so far */ 2313 n = tlm_get_data_offset(lcmd); 2314 nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n; 2315 2316 if (rv == 0) { 2317 /* start traversing the hierarchy and actual backup */ 2318 rv = traverse_level(&ft); 2319 if (rv == 0) { 2320 /* write the trailer and update the bytes processed */ 2321 bpos = tlm_get_data_offset(lcmd); 2322 (void) write_tar_eof(lcmd); 2323 n = tlm_get_data_offset(lcmd) - bpos; 2324 nlp->nlp_session-> 2325 ns_data.dd_module.dm_stats.ms_bytes_processed += n; 2326 } else { 2327 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR, 2328 "Filesystem traverse error.\n"); 2329 ndmpd_data_error(nlp->nlp_session, 2330 NDMP_DATA_HALT_INTERNAL_ERROR); 2331 } 2332 } 2333 2334 if (!NLP_ISCHKPNTED(nlp)) 2335 NDMP_FREE(bp.bp_chkpnm); 2336 NDMP_FREE(bp.bp_tmp); 2337 NDMP_FREE(bp.bp_excls); 2338 2339 cmds->tcs_reader_count--; 2340 lcmd->tc_writer = TLM_STOP; 2341 tlm_release_reader_writer_ipc(lcmd); 2342 tlm_un_ref_job_stats(jname); 2343 return (rv); 2344 2345 } 2346 2347 2348 /* 2349 * tar_backup_v3 2350 * 2351 * Traverse the backup hierarchy if needed and make the bitmap. 2352 * Then launch reader and writer threads to do the actual backup. 2353 * 2354 * Parameters: 2355 * session (input) - pointer to the session 2356 * params (input) - pointer to the parameters structure 2357 * nlp (input) - pointer to the nlp structure 2358 * jname (input) - job name 2359 * 2360 * Returns: 2361 * 0: on success 2362 * != 0: otherwise 2363 */ 2364 static int 2365 tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 2366 ndmp_lbr_params_t *nlp, char *jname) 2367 { 2368 tlm_commands_t *cmds; 2369 backup_reader_arg_t arg; 2370 pthread_t rdtp; 2371 char info[256]; 2372 int result; 2373 ndmp_context_t nctx; 2374 int err; 2375 2376 if (ndmp_get_bk_dir_ino(nlp)) 2377 return (-1); 2378 2379 result = err = 0; 2380 2381 /* exit as if there was an internal error */ 2382 if (session->ns_eof) 2383 return (-1); 2384 2385 if (!session->ns_data.dd_abort) { 2386 if (backup_alloc_structs_v3(session, jname) < 0) { 2387 nlp->nlp_bkmap = -1; 2388 return (-1); 2389 } 2390 2391 if (ndmpd_mark_inodes_v3(session, nlp) != 0) { 2392 if (nlp->nlp_bkmap != -1) { 2393 (void) dbm_free(nlp->nlp_bkmap); 2394 nlp->nlp_bkmap = -1; 2395 } 2396 free_structs_v3(session, jname); 2397 return (-1); 2398 } 2399 2400 nlp->nlp_jstat->js_start_ltime = time(NULL); 2401 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime; 2402 nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate; 2403 2404 cmds = &nlp->nlp_cmds; 2405 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN; 2406 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN; 2407 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN; 2408 2409 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) { 2410 free_structs_v3(session, jname); 2411 return (-1); 2412 } 2413 2414 NDMP_LOG(LOG_DEBUG, 2415 "Backing up \"%s\" started.", nlp->nlp_backup_path); 2416 2417 /* Plug-in module */ 2418 if (ndmp_pl != NULL && 2419 ndmp_pl->np_pre_backup != NULL) { 2420 (void) memset(&nctx, 0, sizeof (ndmp_context_t)); 2421 nctx.nc_plversion = ndmp_pl->np_plversion; 2422 nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH); 2423 nctx.nc_cmds = cmds; 2424 nctx.nc_params = params; 2425 nctx.nc_ddata = (void *) session; 2426 if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx, 2427 nlp->nlp_backup_path)) != 0) { 2428 NDMP_LOG(LOG_ERR, "Pre-backup plug-in: %m"); 2429 goto backup_out; 2430 } 2431 } 2432 2433 (void) memset(&arg, 0, sizeof (backup_reader_arg_t)); 2434 arg.br_jname = jname; 2435 arg.br_nlp = nlp; 2436 arg.br_cmds = cmds; 2437 2438 (void) pthread_barrier_init(&arg.br_barrier, 0, 2); 2439 2440 err = pthread_create(&rdtp, NULL, (funct_t)backup_reader_v3, 2441 (void *)&arg); 2442 if (err == 0) { 2443 (void) pthread_barrier_wait(&arg.br_barrier); 2444 (void) pthread_barrier_destroy(&arg.br_barrier); 2445 } else { 2446 (void) pthread_barrier_destroy(&arg.br_barrier); 2447 free_structs_v3(session, jname); 2448 NDMP_LOG(LOG_DEBUG, "Launch backup_reader_v3: %m"); 2449 return (-1); 2450 } 2451 2452 if ((err = ndmp_tar_writer(session, params, cmds)) != 0) 2453 result = EIO; 2454 2455 nlp->nlp_jstat->js_stop_time = time(NULL); 2456 2457 (void) snprintf(info, sizeof (info), 2458 "Runtime [%s] %llu bytes (%llu): %d seconds\n", 2459 nlp->nlp_backup_path, 2460 session->ns_data.dd_module.dm_stats.ms_bytes_processed, 2461 session->ns_data.dd_module.dm_stats.ms_bytes_processed, 2462 nlp->nlp_jstat->js_stop_time - 2463 nlp->nlp_jstat->js_start_ltime); 2464 MOD_LOGV3(params, NDMP_LOG_NORMAL, info); 2465 2466 ndmp_wait_for_reader(cmds); 2467 (void) pthread_join(rdtp, NULL); 2468 2469 /* exit as if there was an internal error */ 2470 if (session->ns_eof) { 2471 result = EPIPE; 2472 err = -1; 2473 } 2474 if (!session->ns_data.dd_abort) { 2475 ndmpd_audit_backup(session->ns_connection, 2476 nlp->nlp_backup_path, 2477 session->ns_data.dd_data_addr.addr_type, 2478 session->ns_tape.td_adapter_name, result); 2479 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" Finished.", 2480 nlp->nlp_backup_path); 2481 } 2482 } 2483 2484 if (session->ns_data.dd_abort) { 2485 ndmpd_audit_backup(session->ns_connection, 2486 nlp->nlp_backup_path, 2487 session->ns_data.dd_data_addr.addr_type, 2488 session->ns_tape.td_adapter_name, EINTR); 2489 NDMP_LOG(LOG_DEBUG, 2490 "Backing up \"%s\" aborted.", nlp->nlp_backup_path); 2491 err = -1; 2492 } else { 2493 2494 backup_out: 2495 /* Plug-in module */ 2496 if (ndmp_pl != NULL && 2497 ndmp_pl->np_post_backup != NULL && 2498 ndmp_pl->np_post_backup(ndmp_pl, &nctx, err) == -1) { 2499 NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m"); 2500 return (-1); 2501 } 2502 } 2503 2504 free_structs_v3(session, jname); 2505 return (err); 2506 } 2507 2508 /* 2509 * get_backup_size 2510 * 2511 * Find the estimate of backup size. This is used to get an estimate 2512 * of the progress of backup during NDMP backup. 2513 */ 2514 void 2515 get_backup_size(ndmp_bkup_size_arg_t *sarg) 2516 { 2517 fs_traverse_t ft; 2518 u_longlong_t bk_size; 2519 char spath[PATH_MAX]; 2520 int rv; 2521 2522 bk_size = 0; 2523 if (fs_is_chkpntvol(sarg->bs_path)) { 2524 ft.ft_path = sarg->bs_path; 2525 } else { 2526 (void) tlm_build_snapshot_name(sarg->bs_path, 2527 spath, sarg->bs_jname); 2528 ft.ft_path = spath; 2529 } 2530 2531 ft.ft_lpath = ft.ft_path; 2532 ft.ft_callbk = size_cb; 2533 ft.ft_arg = &bk_size; 2534 ft.ft_logfp = (ft_log_t)ndmp_log; 2535 ft.ft_flags = FST_VERBOSE; 2536 2537 if ((rv = traverse_level(&ft)) != 0) { 2538 NDMP_LOG(LOG_DEBUG, "bksize err=%d", rv); 2539 bk_size = 0; 2540 } else { 2541 NDMP_LOG(LOG_DEBUG, "bksize %lld, %lldKB, %lldMB\n", 2542 bk_size, bk_size / 1024, bk_size /(1024 * 1024)); 2543 } 2544 sarg->bs_session->ns_data.dd_data_size = bk_size; 2545 } 2546 2547 /* 2548 * get_rs_path_v3 2549 * 2550 * Find the restore path 2551 */ 2552 ndmp_error 2553 get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 2554 { 2555 char *dp; 2556 ndmp_error rv; 2557 mem_ndmp_name_v3_t *ep; 2558 int i, nm_cnt; 2559 char *nm_dpath_list[MULTIPLE_DEST_DIRS]; 2560 static char mdest_buf[256]; 2561 2562 *mdest_buf = 0; 2563 *nm_dpath_list = ""; 2564 for (i = 0, nm_cnt = 0; i < (int)nlp->nlp_nfiles; i++) { 2565 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i); 2566 if (!ep) { 2567 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[%d]", i); 2568 return (NDMP_ILLEGAL_ARGS_ERR); 2569 } 2570 if (strcmp(nm_dpath_list[nm_cnt], ep->nm3_dpath) != 0 && 2571 nm_cnt < MULTIPLE_DEST_DIRS - 1) 2572 nm_dpath_list[++nm_cnt] = ep->nm3_dpath; 2573 } 2574 2575 multiple_dest_restore = (nm_cnt > 1); 2576 nlp->nlp_restore_path = mdest_buf; 2577 2578 for (i = 1; i < nm_cnt + 1; i++) { 2579 if (ISDEFINED(nm_dpath_list[i])) 2580 dp = nm_dpath_list[i]; 2581 else 2582 /* the default destination path is backup directory */ 2583 dp = nlp->nlp_backup_path; 2584 2585 /* check the destination directory exists and is writable */ 2586 if (!fs_volexist(dp)) { 2587 rv = NDMP_ILLEGAL_ARGS_ERR; 2588 MOD_LOGV3(params, NDMP_LOG_ERROR, 2589 "Invalid destination path volume \"%s\".\n", dp); 2590 } else if (!voliswr(dp)) { 2591 rv = NDMP_ILLEGAL_ARGS_ERR; 2592 MOD_LOGV3(params, NDMP_LOG_ERROR, 2593 "The destination path volume" 2594 " is not writable \"%s\".\n", dp); 2595 } else { 2596 rv = NDMP_NO_ERR; 2597 (void) strlcat(nlp->nlp_restore_path, dp, 2598 sizeof (mdest_buf)); 2599 NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", dp); 2600 } 2601 2602 /* 2603 * Exit if there is an error or it is not a multiple 2604 * destination restore mode 2605 */ 2606 if (rv != NDMP_NO_ERR || !multiple_dest_restore) 2607 break; 2608 2609 if (i < nm_cnt) 2610 (void) strlcat(nlp->nlp_restore_path, ", ", 2611 sizeof (mdest_buf)); 2612 } 2613 2614 return (rv); 2615 } 2616 2617 2618 /* 2619 * fix_nlist_v3 2620 * 2621 * Check if the recovery list is valid and fix it if there are some 2622 * unspecified entries in it. It checks for original, destination 2623 * and new path for all NDMP names provided inside the list. 2624 * 2625 * V3: dpath is the destination directory. If newnm is not NULL, the 2626 * destination path is dpath/newnm. Otherwise the destination path is 2627 * dpath/opath_last_node, where opath_last_node is the last node in opath. 2628 * 2629 * V4: If newnm is not NULL, dpath is the destination directory, and 2630 * dpath/newnm is the destination path. If newnm is NULL, dpath is 2631 * the destination path (opath is not involved in forming destination path). 2632 */ 2633 ndmp_error 2634 fix_nlist_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 2635 ndmp_lbr_params_t *nlp) 2636 { 2637 char *cp, *buf, *bp; 2638 int i, n; 2639 int iswrbk; 2640 int bvexists; 2641 ndmp_error rv; 2642 mem_ndmp_name_v3_t *ep; 2643 char *dp; 2644 char *nm; 2645 int existsvol; 2646 int isrwdst; 2647 2648 buf = ndmp_malloc(TLM_MAX_PATH_NAME); 2649 if (!buf) { 2650 MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n"); 2651 return (NDMP_NO_MEM_ERR); 2652 } 2653 2654 bvexists = fs_volexist(nlp->nlp_backup_path); 2655 iswrbk = voliswr(nlp->nlp_backup_path); 2656 2657 rv = NDMP_NO_ERR; 2658 n = session->ns_data.dd_nlist_len; 2659 for (i = 0; i < n; i++) { 2660 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i); 2661 if (!ep) 2662 continue; 2663 2664 /* chop off the trailing slashes */ 2665 chopslash(ep->nm3_opath); 2666 2667 chopslash(ep->nm3_dpath); 2668 chopslash(ep->nm3_newnm); 2669 2670 /* existing and non-empty destination path */ 2671 if (ISDEFINED(ep->nm3_dpath)) { 2672 dp = ep->nm3_dpath; 2673 existsvol = fs_volexist(dp); 2674 isrwdst = voliswr(dp); 2675 } else { 2676 /* the default destination path is backup directory */ 2677 dp = nlp->nlp_backup_path; 2678 existsvol = bvexists; 2679 isrwdst = iswrbk; 2680 } 2681 2682 /* check the destination directory exists and is writable */ 2683 if (!existsvol) { 2684 rv = NDMP_ILLEGAL_ARGS_ERR; 2685 MOD_LOGV3(params, NDMP_LOG_ERROR, 2686 "Invalid destination path volume " 2687 "\"%s\".\n", dp); 2688 break; 2689 } 2690 if (!isrwdst) { 2691 rv = NDMP_ILLEGAL_ARGS_ERR; 2692 MOD_LOGV3(params, NDMP_LOG_ERROR, 2693 "The destination path volume is not " 2694 "writable \"%s\".\n", dp); 2695 break; 2696 } 2697 2698 /* 2699 * If new name is not specified, the default new name is 2700 * the last component of the original path, if any 2701 * (except in V4). 2702 */ 2703 if (ISDEFINED(ep->nm3_newnm)) { 2704 nm = ep->nm3_newnm; 2705 } else { 2706 char *p, *q; 2707 2708 /* 2709 * Find the last component of nm3_opath. 2710 * nm3_opath has no trailing '/'. 2711 */ 2712 p = strrchr(ep->nm3_opath, '/'); 2713 nm = p ? p + 1 : ep->nm3_opath; 2714 2715 /* 2716 * In DDAR the last component could 2717 * be repeated in nm3_dpath 2718 */ 2719 q = strrchr(ep->nm3_dpath, '/'); 2720 q = q ? q + 1 : ep->nm3_dpath; 2721 if (strcmp(nm, q) == 0) 2722 nm = NULL; 2723 2724 } 2725 2726 bp = joinpath(buf, dp, nm); 2727 if (!bp) { 2728 /* 2729 * Note: What should be done with this entry? 2730 * We leave it untouched for now, hence no path in 2731 * the backup image matches with this entry and will 2732 * be reported as not found. 2733 */ 2734 MOD_LOGV3(params, NDMP_LOG_ERROR, 2735 "Destination path too long(%s/%s)", dp, nm); 2736 continue; 2737 } 2738 cp = strdup(bp); 2739 if (!cp) { 2740 MOD_LOGV3(params, NDMP_LOG_ERROR, 2741 "Insufficient memory.\n"); 2742 rv = NDMP_NO_MEM_ERR; 2743 break; 2744 } 2745 free(ep->nm3_dpath); 2746 ep->nm3_dpath = cp; 2747 NDMP_FREE(ep->nm3_newnm); 2748 2749 bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath); 2750 if (!bp) { 2751 /* 2752 * Note: The same problem of above with long path. 2753 */ 2754 MOD_LOGV3(params, NDMP_LOG_ERROR, 2755 "Path too long(%s/%s)", 2756 nlp->nlp_backup_path, ep->nm3_opath); 2757 continue; 2758 } 2759 cp = strdup(bp); 2760 if (!cp) { 2761 MOD_LOGV3(params, NDMP_LOG_ERROR, 2762 "Insufficient memory.\n"); 2763 rv = NDMP_NO_MEM_ERR; 2764 break; 2765 } 2766 NDMP_FREE(ep->nm3_opath); 2767 ep->nm3_opath = cp; 2768 2769 NDMP_LOG(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath); 2770 if (ep->nm3_dpath) { 2771 NDMP_LOG(LOG_DEBUG, 2772 "dest[%d]: \"%s\"", i, ep->nm3_dpath); 2773 } else { 2774 NDMP_LOG(LOG_DEBUG, "dest[%d]: \"%s\"", i, "NULL"); 2775 } 2776 } 2777 2778 free(buf); 2779 2780 return (rv); 2781 } 2782 2783 2784 /* 2785 * allvalidfh 2786 * 2787 * Run a sanity check on the file history info. The file history 2788 * info is the offset of the record starting the entry on the tape 2789 * and is used in DAR (direct access restore mode). 2790 */ 2791 static boolean_t 2792 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params) 2793 { 2794 int i, n; 2795 boolean_t rv; 2796 mem_ndmp_name_v3_t *ep; 2797 2798 rv = TRUE; 2799 n = session->ns_data.dd_nlist_len; 2800 for (i = 0; i < n; i++) { 2801 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i); 2802 if (!ep) 2803 continue; 2804 /* 2805 * The fh_info's sent from the client are multiples 2806 * of RECORDSIZE which is 512 bytes. 2807 * 2808 * All our fh_info's are at the RECORDSIZE boundary. If there 2809 * is any fh_info that is less than RECORDSIZE (this covers 0 2810 * and -1 values too), then the result is that DAR cannot be 2811 * done. 2812 */ 2813 if (ep->nm3_fh_info < RECORDSIZE || 2814 ep->nm3_fh_info % RECORDSIZE != 0) { 2815 rv = FALSE; 2816 break; 2817 } 2818 } 2819 2820 return (rv); 2821 } 2822 2823 2824 /* 2825 * log_rs_params_v3 2826 * 2827 * Log a copy of all values of the restore parameters 2828 */ 2829 void 2830 log_rs_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 2831 ndmp_lbr_params_t *nlp) 2832 { 2833 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Restoring to \"%s\".\n", 2834 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL"); 2835 2836 if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) { 2837 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Tape server: local.\n"); 2838 MOD_LOGV3(params, NDMP_LOG_NORMAL, 2839 "Tape record size: %d.\n", 2840 session->ns_mover.md_record_size); 2841 } else if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP) 2842 MOD_LOGV3(params, NDMP_LOG_NORMAL, 2843 "Tape server: remote at %s:%d.\n", 2844 inet_ntoa(IN_ADDR(session->ns_data.dd_data_addr.tcp_ip_v3)), 2845 session->ns_data.dd_data_addr.tcp_port_v3); 2846 else 2847 MOD_LOGV3(params, NDMP_LOG_ERROR, 2848 "Unknown tape server address type.\n"); 2849 2850 if (NLP_ISSET(nlp, NLPF_DIRECT)) 2851 MOD_LOGV3(params, NDMP_LOG_NORMAL, 2852 "Direct Access Restore.\n"); 2853 } 2854 2855 2856 /* 2857 * send_unrecovered_list_v3 2858 * 2859 * Create the list of files that were in restore list but 2860 * not recovered due to some errors. 2861 */ 2862 int 2863 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 2864 { 2865 int i, rv; 2866 int err; 2867 2868 if (!params) { 2869 NDMP_LOG(LOG_DEBUG, "params == NULL"); 2870 return (-1); 2871 } 2872 if (!nlp) { 2873 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 2874 return (-1); 2875 } 2876 2877 if (nlp->nlp_lastidx != -1) { 2878 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx)) 2879 err = ENOENT; 2880 else 2881 err = 0; 2882 (void) ndmp_send_recovery_stat_v3(params, nlp, 2883 nlp->nlp_lastidx, err); 2884 nlp->nlp_lastidx = -1; 2885 } 2886 2887 rv = 0; 2888 for (i = 0; i < (int)nlp->nlp_nfiles; i++) { 2889 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)i)) { 2890 rv = ndmp_send_recovery_stat_v3(params, nlp, i, ENOENT); 2891 if (rv < 0) 2892 break; 2893 } 2894 } 2895 2896 return (rv); 2897 } 2898 2899 2900 2901 /* 2902 * restore_dar_alloc_structs_v3 2903 * 2904 * Allocates the necessary structures for running DAR restore. 2905 * It just creates the reader writer IPC. 2906 * This function is called for each entry in the restore entry list. 2907 * 2908 * Parameters: 2909 * session (input) - pointer to the session 2910 * jname (input) - Job name 2911 * 2912 * Returns: 2913 * 0: on success 2914 * -1: on error 2915 */ 2916 int 2917 restore_dar_alloc_structs_v3(ndmpd_session_t *session, char *jname) 2918 { 2919 long xfer_size; 2920 ndmp_lbr_params_t *nlp; 2921 tlm_commands_t *cmds; 2922 2923 nlp = ndmp_get_nlp(session); 2924 if (!nlp) { 2925 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 2926 return (-1); 2927 } 2928 2929 cmds = &nlp->nlp_cmds; 2930 (void) memset(cmds, 0, sizeof (*cmds)); 2931 2932 xfer_size = ndmp_buffer_get_size(session); 2933 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size); 2934 if (!cmds->tcs_command) { 2935 tlm_un_ref_job_stats(jname); 2936 return (-1); 2937 } 2938 2939 return (0); 2940 } 2941 2942 2943 /* 2944 * free_dar_structs_v3 2945 * 2946 * To free the structures were created by restore_dar_alloc_structs_v3. 2947 * This funnction is called for each entry in restore entry list. 2948 * 2949 * Parameters: 2950 * session (input) - pointer to the session 2951 * jname (input) - job name 2952 * 2953 * Returns: 2954 * NONE 2955 */ 2956 /*ARGSUSED*/ 2957 static void 2958 free_dar_structs_v3(ndmpd_session_t *session, char *jname) 2959 { 2960 ndmp_lbr_params_t *nlp; 2961 tlm_commands_t *cmds; 2962 2963 nlp = ndmp_get_nlp(session); 2964 if (!nlp) { 2965 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 2966 return; 2967 } 2968 cmds = &nlp->nlp_cmds; 2969 if (!cmds) { 2970 NDMP_LOG(LOG_DEBUG, "cmds == NULL"); 2971 return; 2972 } 2973 2974 if (cmds->tcs_command) { 2975 if (cmds->tcs_command->tc_buffers != NULL) 2976 tlm_release_reader_writer_ipc(cmds->tcs_command); 2977 else 2978 NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL"); 2979 cmds->tcs_command = NULL; 2980 } else 2981 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL"); 2982 } 2983 2984 2985 /* 2986 * ndmp_dar_tar_init_v3 2987 * 2988 * Constructor for the DAR restore. Creates job name, allocates structures 2989 * needed for keeping the statistics, and reports the start of restore action. 2990 * It is called once for each DAR restore request. 2991 * 2992 * Parameters: 2993 * session (input) - pointer to the session 2994 * nlp (input) - pointer to the nlp structure 2995 * 2996 * Returns: 2997 * char pointer: on success 2998 * NULL: on error 2999 */ 3000 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session, 3001 ndmp_lbr_params_t *nlp) 3002 { 3003 char *jname; 3004 3005 jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME); 3006 3007 if (!jname) 3008 return (NULL); 3009 3010 (void) ndmp_new_job_name(jname); 3011 3012 if (!nlp) { 3013 free(jname); 3014 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 3015 return (NULL); 3016 } 3017 3018 nlp->nlp_jstat = tlm_new_job_stats(jname); 3019 if (!nlp->nlp_jstat) { 3020 free(jname); 3021 NDMP_LOG(LOG_DEBUG, "Creating job stats"); 3022 return (NULL); 3023 } 3024 3025 nlp->nlp_jstat->js_start_ltime = time(NULL); 3026 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime; 3027 3028 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session, 3029 ndmpd_path_restored_v3, NULL, NULL); 3030 if (!nlp->nlp_logcallbacks) { 3031 tlm_un_ref_job_stats(jname); 3032 free(jname); 3033 return (NULL); 3034 } 3035 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks); 3036 3037 nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0); 3038 if (nlp->nlp_rsbm < 0) { 3039 NDMP_LOG(LOG_ERR, "Out of memory."); 3040 lbrlog_callbacks_done(nlp->nlp_logcallbacks); 3041 tlm_un_ref_job_stats(jname); 3042 free(jname); 3043 return (NULL); 3044 } 3045 3046 /* this is used in ndmpd_path_restored_v3() */ 3047 nlp->nlp_lastidx = -1; 3048 3049 NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).", 3050 ndmp_data_get_mover_mode(session)); 3051 3052 return (jname); 3053 } 3054 3055 /* 3056 * ndmpd_dar_tar_end_v3 3057 * 3058 * Deconstructor for the DAR restore. This function is called once per 3059 * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3. 3060 * 3061 * Parameters: 3062 * session (input) - pointer to the session 3063 * params (input) - pointer to the parameters structure 3064 * nlp (input) - pointer to the nlp structure 3065 * jname(input) - job name 3066 * 3067 * Returns: 3068 * 0: on success 3069 * -1: on error 3070 */ 3071 static int ndmpd_dar_tar_end_v3(ndmpd_session_t *session, 3072 ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *jname) 3073 { 3074 int err = 0; 3075 3076 3077 NDMP_LOG(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx); 3078 3079 /* nothing restored. */ 3080 (void) send_unrecovered_list_v3(params, nlp); 3081 3082 if (nlp->nlp_jstat) { 3083 nlp->nlp_bytes_total = 3084 (u_longlong_t)nlp->nlp_jstat->js_bytes_total; 3085 tlm_un_ref_job_stats(jname); 3086 nlp->nlp_jstat = NULL; 3087 } else { 3088 NDMP_LOG(LOG_DEBUG, "JSTAT == NULL"); 3089 } 3090 3091 if (nlp->nlp_logcallbacks) { 3092 lbrlog_callbacks_done(nlp->nlp_logcallbacks); 3093 nlp->nlp_logcallbacks = NULL; 3094 } else { 3095 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL"); 3096 } 3097 3098 if (session->ns_data.dd_abort) { 3099 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.", 3100 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL"); 3101 err = EINTR; 3102 } else { 3103 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)", 3104 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : 3105 "NULL", err); 3106 } 3107 3108 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) { 3109 if (nlp->nlp_rsbm < 0) { 3110 NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm); 3111 } else { 3112 (void) bm_free(nlp->nlp_rsbm); 3113 nlp->nlp_rsbm = -1; 3114 } 3115 } 3116 3117 free(jname); 3118 3119 return (err); 3120 } 3121 3122 3123 /* 3124 * ndmpd_dar_tar_v3 3125 * 3126 * This function is called for each entry in DAR entry list. The window 3127 * is already located and we should be in the right position to read 3128 * the data from the tape. 3129 * For each entry we setup selection list; so that, if the file name from 3130 * tape is not as the name client asked for, error be returned. 3131 * 3132 * Parameters: 3133 * session (input) - pointer to the session 3134 * params (input) - pointer to the parameters structure 3135 * nlp (input) - pointer to the nlp structure 3136 * jname (input) - job name 3137 * dar_index(input) - Index of this entry in the restore list 3138 * 3139 * Returns: 3140 * 0: on success 3141 * -1: on error 3142 */ 3143 static int 3144 ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 3145 ndmp_lbr_params_t *nlp, char *jname, int dar_index) 3146 { 3147 char *excl; 3148 char **sels; 3149 int flags; 3150 int err; 3151 tlm_commands_t *cmds; 3152 struct rs_name_maker rn; 3153 int data_addr_type = session->ns_data.dd_data_addr.addr_type; 3154 ndmp_tar_reader_arg_t arg; 3155 pthread_t rdtp; 3156 ndmp_context_t nctx; 3157 mem_ndmp_name_v3_t *ep; 3158 3159 err = 0; 3160 3161 /* 3162 * We have to allocate and deallocate buffers every time we 3163 * run the restore, for we need to flush the buffers. 3164 */ 3165 if (restore_dar_alloc_structs_v3(session, jname) < 0) 3166 return (-1); 3167 3168 sels = setupsels(session, params, nlp, dar_index); 3169 if (!sels) { 3170 free_dar_structs_v3(session, jname); 3171 return (-1); 3172 } 3173 excl = NULL; 3174 flags = RSFLG_OVR_ALWAYS; 3175 rn.rn_nlp = nlp; 3176 rn.rn_fp = mknewname; 3177 3178 if (!session->ns_data.dd_abort) { 3179 cmds = &nlp->nlp_cmds; 3180 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN; 3181 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN; 3182 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN; 3183 3184 arg.tr_session = session; 3185 arg.tr_mod_params = params; 3186 arg.tr_cmds = cmds; 3187 3188 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader, 3189 (void *)&arg); 3190 if (err == 0) { 3191 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER); 3192 } else { 3193 NDMP_LOG(LOG_DEBUG, "launch ndmp_tar_reader: %m"); 3194 return (-1); 3195 } 3196 3197 cmds->tcs_command->tc_ref++; 3198 cmds->tcs_writer_count++; 3199 3200 /* Plug-in module */ 3201 if (ndmp_pl != NULL && 3202 ndmp_pl->np_pre_restore != NULL) { 3203 (void) memset(&nctx, 0, sizeof (ndmp_context_t)); 3204 nctx.nc_cmds = cmds; 3205 nctx.nc_params = params; 3206 nctx.nc_ddata = (void *) session; 3207 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, 3208 dar_index - 1); 3209 3210 if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx, 3211 ep->nm3_opath, ep->nm3_dpath)) 3212 != 0) { 3213 NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m"); 3214 cmds->tcs_command->tc_reader = TLM_STOP; 3215 ndmp_stop_local_reader(session, cmds); 3216 ndmp_wait_for_reader(cmds); 3217 (void) pthread_join(rdtp, NULL); 3218 ndmp_stop_remote_reader(session); 3219 goto restore_out; 3220 } 3221 } 3222 3223 if (tm_tar_ops.tm_getdir != NULL) { 3224 char errbuf[256]; 3225 3226 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command, 3227 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 3228 dar_index, nlp->nlp_backup_path, 3229 session->hardlink_q); 3230 /* 3231 * If the fatal error from tm_getdir looks like an 3232 * errno code, we send the error description to DMA. 3233 */ 3234 if (err > 0 && strerror_r(err, errbuf, 3235 sizeof (errbuf)) == 0) { 3236 MOD_LOGV3(params, NDMP_LOG_ERROR, 3237 "Fatal error during the restore: %s\n", 3238 errbuf); 3239 } 3240 } 3241 3242 cmds->tcs_writer_count--; 3243 cmds->tcs_command->tc_ref--; 3244 cmds->tcs_command->tc_reader = TLM_STOP; 3245 3246 3247 /* 3248 * If it is a two-way restore then we stop the reader. 3249 */ 3250 NDMP_LOG(LOG_DEBUG, "stop local reader."); 3251 ndmp_stop_local_reader(session, cmds); 3252 3253 ndmp_wait_for_reader(cmds); 3254 (void) pthread_join(rdtp, NULL); 3255 3256 /* 3257 * If this is the last DAR entry and it is a three-way 3258 * restore then we should close the connection. 3259 */ 3260 if ((data_addr_type == NDMP_ADDR_TCP) && 3261 (dar_index == (int)session->ns_data.dd_nlist_len)) { 3262 NDMP_LOG(LOG_DEBUG, "stop remote reader."); 3263 ndmp_stop_remote_reader(session); 3264 } 3265 3266 /* exit as if there was an internal error */ 3267 if (session->ns_eof) 3268 err = -1; 3269 restore_out: 3270 /* Plug-in module */ 3271 if (ndmp_pl != NULL && 3272 ndmp_pl->np_post_restore != NULL && 3273 ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) { 3274 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m"); 3275 err = -1; 3276 } 3277 } 3278 3279 NDMP_FREE(sels); 3280 3281 free_dar_structs_v3(session, jname); 3282 3283 return (err); 3284 } 3285 3286 /* 3287 * ndmpd_dar_locate_windwos_v3 3288 * 3289 * Locating the right window in which the requested file is backed up. 3290 * We should go through windows to find the exact location, for the 3291 * file can be located in for example 10th window after the current window. 3292 * 3293 * Parameters: 3294 * session (input) - pointer to the session 3295 * params (input) - pointer to the parameters structure 3296 * fh_info (input) - index from the beginning of the backup stream 3297 * len (input) - Length of the mover window 3298 * 3299 * Returns: 3300 * 0: on success 3301 * -1: on error 3302 */ 3303 static int 3304 ndmpd_dar_locate_window_v3(ndmpd_session_t *session, 3305 ndmpd_module_params_t *params, u_longlong_t fh_info, u_longlong_t len) 3306 { 3307 int ret = 0; 3308 3309 3310 for (; ; ) { 3311 ret = (*params->mp_seek_func)(session, fh_info, len); 3312 3313 NDMP_LOG(LOG_DEBUG, "ret %d", ret); 3314 if (ret == 0) /* Seek was done successfully */ 3315 break; 3316 else if (ret < 0) { 3317 NDMP_LOG(LOG_DEBUG, "Seek error"); 3318 break; 3319 } 3320 3321 /* 3322 * DMA moved to a new window. 3323 * If we are reading the remainig of the file from 3324 * new window, seek is handled by ndmpd_local_read_v3. 3325 * Here we should continue the seek inside the new 3326 * window. 3327 */ 3328 continue; 3329 } 3330 return (ret); 3331 } 3332 3333 /* 3334 * ndmpd_rs_dar_tar_v3 3335 * 3336 * Main DAR function. It calls the constructor, then for each entry it 3337 * calls the locate_window_v3 to find the exact position of the file. Then 3338 * it restores the file. 3339 * When all restore requests are done it calls the deconstructor to clean 3340 * everything up. 3341 * 3342 * Parameters: 3343 * session (input) - pointer to the session 3344 * params (input) - pointer to the parameters structure 3345 * nlp (input) - pointer to the nlp structure 3346 * 3347 * Returns: 3348 * 0: on success 3349 * -1: on error 3350 */ 3351 static int 3352 ndmpd_rs_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 3353 ndmp_lbr_params_t *nlp) 3354 { 3355 mem_ndmp_name_v3_t *ep; 3356 u_longlong_t len; 3357 char *jname; 3358 int n = session->ns_data.dd_nlist_len; 3359 int i, ret = 0; 3360 int result = 0; 3361 3362 jname = ndmpd_dar_tar_init_v3(session, nlp); 3363 3364 if (!jname) 3365 return (-1); 3366 3367 /* 3368 * We set the length = sizeof (tlm_tar_hdr_t) 3369 * This is important for three-way DAR restore, for we should 3370 * read the header first (If we ask for more data then we have 3371 * to read and discard the remaining data in the socket) 3372 */ 3373 len = tlm_tarhdr_size(); 3374 3375 for (i = 0; i < n; ++i) { 3376 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i); 3377 if (!ep) { 3378 NDMP_LOG(LOG_DEBUG, "ep NULL, i %d", i); 3379 continue; 3380 } 3381 NDMP_LOG(LOG_DEBUG, 3382 "restoring opath %s, dpath %s, fh_info %lld", 3383 ep->nm3_opath ? ep->nm3_opath : "NULL", 3384 ep->nm3_dpath ? ep->nm3_dpath : "NULL", 3385 ep->nm3_fh_info); 3386 3387 /* 3388 * We should seek till finding the window in which file 3389 * is located. 3390 */ 3391 ret = ndmpd_dar_locate_window_v3(session, params, 3392 ep->nm3_fh_info, len); 3393 3394 if (ret < 0) /* If seek fails, restore should be aborted */ 3395 break; 3396 /* 3397 * We are inside the target window. 3398 * for each restore we will use one entry as selection list 3399 */ 3400 if ((ret = ndmpd_dar_tar_v3(session, params, nlp, jname, i+1)) 3401 != 0) 3402 result = EIO; 3403 ndmpd_audit_restore(session->ns_connection, 3404 ep->nm3_opath ? ep->nm3_opath : "NULL", 3405 session->ns_data.dd_data_addr.addr_type, 3406 session->ns_tape.td_adapter_name, result); 3407 } 3408 3409 NDMP_LOG(LOG_DEBUG, "End of restore list"); 3410 3411 (void) ndmpd_dar_tar_end_v3(session, params, nlp, jname); 3412 3413 return (ret); 3414 } 3415 3416 /* 3417 * ndmp_plugin_pre_restore 3418 * 3419 * Wrapper for pre-restore callback with multiple path 3420 */ 3421 static int 3422 ndmp_plugin_pre_restore(ndmp_context_t *ctxp, ndmpd_module_params_t *params, 3423 int ncount) 3424 { 3425 mem_ndmp_name_v3_t *ep; 3426 int err; 3427 int i; 3428 3429 for (i = 0; i < ncount; i++) { 3430 if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i))) 3431 continue; 3432 if ((err = ndmp_pl->np_pre_restore(ndmp_pl, ctxp, 3433 ep->nm3_opath, ep->nm3_dpath)) != 0) 3434 return (err); 3435 } 3436 3437 return (0); 3438 } 3439 3440 /* 3441 * get_absolute_path 3442 * 3443 * Get resolved path name which does not involve ".", ".." or extra 3444 * "/" or symbolic links. 3445 * 3446 * e.g. 3447 * 3448 * /backup/path/ -> /backup/path 3449 * /backup/path/. -> /backup/path 3450 * /backup/path/../path/ -> /backup/path 3451 * /link-to-backup-path -> /backup/path 3452 * 3453 * Returns: 3454 * Pointer to the new path (allocated) 3455 * NULL if the path doesnt exist 3456 */ 3457 static char * 3458 get_absolute_path(const char *bkpath) 3459 { 3460 char *pbuf; 3461 char *rv; 3462 3463 if (!(pbuf = ndmp_malloc(TLM_MAX_PATH_NAME))) 3464 return (NULL); 3465 3466 if ((rv = realpath(bkpath, pbuf)) == NULL) { 3467 NDMP_LOG(LOG_DEBUG, "Invalid path [%s] err=%d", 3468 bkpath, errno); 3469 } 3470 return (rv); 3471 } 3472 3473 /* 3474 * Expands the format string and logs the resulting message to the 3475 * remote DMA 3476 */ 3477 void 3478 ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...) 3479 { 3480 va_list ap; 3481 char buf[256]; 3482 ndmpd_module_params_t *params; 3483 3484 if (nctx == NULL || 3485 (params = (ndmpd_module_params_t *)nctx->nc_params) == NULL) 3486 return; 3487 3488 va_start(ap, fmt); 3489 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 3490 va_end(ap); 3491 3492 MOD_LOGV3(params, (ndmp_log_type)lt, "%s", buf); 3493 } 3494 3495 3496 /* 3497 * ndmpd_rs_sar_tar_v3 3498 * 3499 * Main non-DAR restore function. It will try to restore all the entries 3500 * that have been backed up. 3501 * 3502 * Parameters: 3503 * session (input) - pointer to the session 3504 * params (input) - pointer to the parameters structure 3505 * nlp (input) - pointer to the nlp structure 3506 * 3507 * Returns: 3508 * 0: on success 3509 * -1: on error 3510 */ 3511 static int 3512 ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 3513 ndmp_lbr_params_t *nlp) 3514 { 3515 char jname[TLM_MAX_BACKUP_JOB_NAME]; 3516 char *excl; 3517 char **sels; 3518 int flags; 3519 int err; 3520 tlm_commands_t *cmds; 3521 struct rs_name_maker rn; 3522 ndmp_tar_reader_arg_t arg; 3523 pthread_t rdtp; 3524 int result; 3525 ndmp_context_t nctx; 3526 3527 result = err = 0; 3528 (void) ndmp_new_job_name(jname); 3529 if (restore_alloc_structs_v3(session, jname) < 0) 3530 return (-1); 3531 3532 sels = setupsels(session, params, nlp, 0); 3533 if (!sels) { 3534 free_structs_v3(session, jname); 3535 return (-1); 3536 } 3537 excl = NULL; 3538 flags = RSFLG_OVR_ALWAYS; 3539 rn.rn_nlp = nlp; 3540 rn.rn_fp = mknewname; 3541 3542 nlp->nlp_jstat->js_start_ltime = time(NULL); 3543 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime; 3544 3545 if (!session->ns_data.dd_abort && !session->ns_data.dd_abort) { 3546 cmds = &nlp->nlp_cmds; 3547 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN; 3548 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN; 3549 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN; 3550 3551 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.", 3552 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL"); 3553 3554 arg.tr_session = session; 3555 arg.tr_mod_params = params; 3556 arg.tr_cmds = cmds; 3557 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader, 3558 (void *)&arg); 3559 if (err == 0) { 3560 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER); 3561 } else { 3562 NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m"); 3563 free_structs_v3(session, jname); 3564 return (-1); 3565 } 3566 3567 if (!ndmp_check_utf8magic(cmds->tcs_command)) { 3568 NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!"); 3569 } else { 3570 NDMP_LOG(LOG_DEBUG, "UTF8Magic found"); 3571 } 3572 3573 /* Plug-in module */ 3574 if (ndmp_pl != NULL && 3575 ndmp_pl->np_pre_restore != NULL) { 3576 (void) memset(&nctx, 0, sizeof (ndmp_context_t)); 3577 nctx.nc_cmds = cmds; 3578 nctx.nc_params = params; 3579 nctx.nc_ddata = (void *) session; 3580 if ((err = ndmp_plugin_pre_restore(&nctx, params, 3581 nlp->nlp_nfiles)) 3582 != 0) { 3583 NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m"); 3584 cmds->tcs_command->tc_reader = TLM_STOP; 3585 ndmp_stop_local_reader(session, cmds); 3586 ndmp_wait_for_reader(cmds); 3587 (void) pthread_join(rdtp, NULL); 3588 ndmp_stop_remote_reader(session); 3589 goto restore_out; 3590 } 3591 } 3592 3593 cmds->tcs_command->tc_ref++; 3594 cmds->tcs_writer_count++; 3595 3596 if (tm_tar_ops.tm_getdir != NULL) { 3597 char errbuf[256]; 3598 3599 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command, 3600 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0, 3601 nlp->nlp_backup_path, session->hardlink_q); 3602 /* 3603 * If the fatal error from tm_getdir looks like an 3604 * errno code, we send the error description to DMA. 3605 */ 3606 if (err > 0 && strerror_r(err, errbuf, 3607 sizeof (errbuf)) == 0) { 3608 MOD_LOGV3(params, NDMP_LOG_ERROR, 3609 "Fatal error during the restore: %s\n", 3610 errbuf); 3611 } 3612 } 3613 3614 cmds->tcs_writer_count--; 3615 cmds->tcs_command->tc_ref--; 3616 cmds->tcs_command->tc_reader = TLM_STOP; 3617 nlp->nlp_jstat->js_stop_time = time(NULL); 3618 3619 /* Send the list of un-recovered files/dirs to the client. */ 3620 (void) send_unrecovered_list_v3(params, nlp); 3621 3622 ndmp_stop_local_reader(session, cmds); 3623 ndmp_wait_for_reader(cmds); 3624 (void) pthread_join(rdtp, NULL); 3625 3626 ndmp_stop_remote_reader(session); 3627 3628 /* exit as if there was an internal error */ 3629 if (session->ns_eof) 3630 err = -1; 3631 if (err == -1) 3632 result = EIO; 3633 } 3634 3635 (void) send_unrecovered_list_v3(params, nlp); /* nothing restored. */ 3636 if (session->ns_data.dd_abort) { 3637 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.", 3638 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL"); 3639 result = EINTR; 3640 ndmpd_audit_restore(session->ns_connection, 3641 nlp->nlp_restore_path, 3642 session->ns_data.dd_data_addr.addr_type, 3643 session->ns_tape.td_adapter_name, result); 3644 err = -1; 3645 } else { 3646 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)", 3647 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL", 3648 err); 3649 ndmpd_audit_restore(session->ns_connection, 3650 nlp->nlp_restore_path, 3651 session->ns_data.dd_data_addr.addr_type, 3652 session->ns_tape.td_adapter_name, result); 3653 3654 restore_out: 3655 /* Plug-in module */ 3656 if (ndmp_pl != NULL && 3657 ndmp_pl->np_post_restore != NULL && 3658 ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) { 3659 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m"); 3660 err = -1; 3661 } 3662 } 3663 3664 NDMP_FREE(sels); 3665 free_structs_v3(session, jname); 3666 3667 return (err); 3668 } 3669 3670 3671 /* 3672 * ndmp_backup_get_params_v3 3673 * 3674 * Get the backup parameters from the NDMP env variables 3675 * and log them in the system log and as normal messages 3676 * to the DMA. 3677 * 3678 * Parameters: 3679 * session (input) - pointer to the session 3680 * params (input) - pointer to the parameters structure 3681 * 3682 * Returns: 3683 * NDMP_NO_ERR: on success 3684 * != NDMP_NO_ERR: otherwise 3685 */ 3686 ndmp_error 3687 ndmp_backup_get_params_v3(ndmpd_session_t *session, 3688 ndmpd_module_params_t *params) 3689 { 3690 ndmp_lbr_params_t *nlp; 3691 3692 if (!session || !params) 3693 return (NDMP_ILLEGAL_ARGS_ERR); 3694 3695 nlp = ndmp_get_nlp(session); 3696 if (!nlp) { 3697 MOD_LOGV3(params, NDMP_LOG_ERROR, 3698 "Internal error: NULL nlp.\n"); 3699 return (NDMP_ILLEGAL_ARGS_ERR); 3700 } else { 3701 if (!(nlp->nlp_backup_path = get_backup_path_v3(params)) || 3702 !is_valid_backup_dir_v3(params, nlp->nlp_backup_path)) 3703 return (NDMP_ILLEGAL_ARGS_ERR); 3704 } 3705 3706 nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path); 3707 if (!nlp->nlp_backup_path) 3708 return (NDMP_ILLEGAL_ARGS_ERR); 3709 3710 if (fs_is_chkpntvol(nlp->nlp_backup_path) || 3711 fs_is_rdonly(nlp->nlp_backup_path) || 3712 !fs_is_chkpnt_enabled(nlp->nlp_backup_path)) 3713 NLP_SET(nlp, NLPF_CHKPNTED_PATH); 3714 else 3715 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH); 3716 3717 /* Should the st_ctime be ignored when backing up? */ 3718 if (ndmp_ignore_ctime) { 3719 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime"); 3720 NLP_SET(nlp, NLPF_IGNCTIME); 3721 } else { 3722 NLP_UNSET(nlp, NLPF_IGNCTIME); 3723 } 3724 3725 if (ndmp_include_lmtime == TRUE) { 3726 NDMP_LOG(LOG_DEBUG, "including st_lmtime"); 3727 NLP_SET(nlp, NLPF_INCLMTIME); 3728 } else { 3729 NLP_UNSET(nlp, NLPF_INCLMTIME); 3730 } 3731 3732 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags); 3733 3734 get_hist_env_v3(params, nlp); 3735 get_exc_env_v3(params, nlp); 3736 get_inc_env_v3(params, nlp); 3737 get_direct_env_v3(params, nlp); 3738 return (get_backup_level_v3(params, nlp)); 3739 } 3740 3741 3742 /* 3743 * ndmpd_tar_backup_starter_v3 3744 * 3745 * Create the checkpoint for the backup and do the backup, 3746 * then remove the backup checkpoint if we created it. 3747 * Save the backup time information based on the backup 3748 * type and stop the data server. 3749 * 3750 * Parameters: 3751 * params (input) - pointer to the parameters structure 3752 * 3753 * Returns: 3754 * 0: on success 3755 * != 0: otherwise 3756 */ 3757 int 3758 ndmpd_tar_backup_starter_v3(void *arg) 3759 { 3760 ndmpd_module_params_t *params = arg; 3761 int err; 3762 ndmpd_session_t *session; 3763 ndmp_lbr_params_t *nlp; 3764 char jname[TLM_MAX_BACKUP_JOB_NAME]; 3765 ndmp_bkup_size_arg_t sarg; 3766 pthread_t tid; 3767 3768 session = (ndmpd_session_t *)(params->mp_daemon_cookie); 3769 *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session); 3770 ndmp_session_ref(session); 3771 (void) ndmp_new_job_name(jname); 3772 3773 err = 0; 3774 if (!NLP_ISCHKPNTED(nlp) && 3775 ndmp_create_snapshot(nlp->nlp_backup_path, jname) < 0) { 3776 MOD_LOGV3(params, NDMP_LOG_ERROR, 3777 "Creating checkpoint on \"%s\".\n", 3778 nlp->nlp_backup_path); 3779 err = -1; 3780 } 3781 3782 NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c", 3783 err, NDMP_YORN(NLP_ISCHKPNTED(nlp))); 3784 3785 if (err == 0) { 3786 sarg.bs_session = session; 3787 sarg.bs_jname = jname; 3788 sarg.bs_path = nlp->nlp_backup_path; 3789 3790 /* Get an estimate of the data size */ 3791 if (pthread_create(&tid, NULL, (funct_t)get_backup_size, 3792 (void *)&sarg) == 0) 3793 (void) pthread_detach(tid); 3794 3795 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname); 3796 if (err != 0) { 3797 NDMP_LOG(LOG_DEBUG, "err %d", err); 3798 } else { 3799 log_bk_params_v3(session, params, nlp); 3800 err = tar_backup_v3(session, params, nlp, jname); 3801 } 3802 } 3803 3804 if (!NLP_ISCHKPNTED(nlp)) 3805 (void) ndmp_remove_snapshot(nlp->nlp_backup_path, jname); 3806 3807 NDMP_LOG(LOG_DEBUG, "err %d, update %c", 3808 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp))); 3809 3810 if (err == 0) 3811 save_backup_date_v3(params, nlp); 3812 3813 MOD_DONE(params, err); 3814 3815 /* nlp_params is allocated in start_backup_v3() */ 3816 NDMP_FREE(nlp->nlp_params); 3817 NDMP_FREE(nlp->nlp_backup_path); 3818 3819 NS_DEC(nbk); 3820 ndmp_session_unref(session); 3821 return (err); 3822 3823 } 3824 3825 3826 /* 3827 * ndmpd_tar_backup_abort_v3 3828 * 3829 * Abort the backup operation and stop the reader thread. 3830 * 3831 * Parameters: 3832 * module_cookie (input) - pointer to the nlp structure 3833 * 3834 * Returns: 3835 * 0: always 3836 */ 3837 int 3838 ndmpd_tar_backup_abort_v3(void *module_cookie) 3839 { 3840 ndmp_lbr_params_t *nlp; 3841 3842 nlp = (ndmp_lbr_params_t *)module_cookie; 3843 if (nlp && nlp->nlp_session) { 3844 if (nlp->nlp_session->ns_data.dd_data_addr.addr_type == 3845 NDMP_ADDR_TCP && 3846 nlp->nlp_session->ns_data.dd_sock != -1) { 3847 (void) close(nlp->nlp_session->ns_data.dd_sock); 3848 nlp->nlp_session->ns_data.dd_sock = -1; 3849 } 3850 ndmp_stop_reader_thread(nlp->nlp_session); 3851 } 3852 3853 return (0); 3854 } 3855 3856 3857 /* 3858 * ndmp_restore_get_params_v3 3859 * 3860 * Get the parameters specified for recovery such as restore path, type 3861 * of restore (DAR, non-DAR) etc 3862 * 3863 * Parameters: 3864 * session (input) - pointer to the session 3865 * params (input) - pointer to the parameters structure 3866 * 3867 * Returns: 3868 * NDMP_NO_ERR: on success 3869 * != NDMP_NO_ERR: otherwise 3870 */ 3871 ndmp_error 3872 ndmp_restore_get_params_v3(ndmpd_session_t *session, 3873 ndmpd_module_params_t *params) 3874 { 3875 ndmp_error rv; 3876 ndmp_lbr_params_t *nlp; 3877 3878 if (!(nlp = ndmp_get_nlp(session))) { 3879 NDMP_LOG(LOG_DEBUG, "nlp is NULL"); 3880 rv = NDMP_ILLEGAL_ARGS_ERR; 3881 } else if (!(nlp->nlp_backup_path = get_backup_path_v3(params))) 3882 rv = NDMP_ILLEGAL_ARGS_ERR; 3883 else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) { 3884 NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles); 3885 rv = NDMP_ILLEGAL_ARGS_ERR; 3886 } else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) { 3887 rv = NDMP_ILLEGAL_ARGS_ERR; 3888 } else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) { 3889 NDMP_LOG(LOG_DEBUG, "fix_nlist_v3: %d", rv); 3890 } else { 3891 rv = NDMP_NO_ERR; 3892 get_direct_env_v3(params, nlp); 3893 if (NLP_ISSET(nlp, NLPF_DIRECT)) { 3894 if (NLP_ISSET(nlp, NLPF_RECURSIVE)) { 3895 /* Currently we dont support DAR on directory */ 3896 NDMP_LOG(LOG_DEBUG, 3897 "Can't have RECURSIVE and DIRECT together"); 3898 rv = NDMP_ILLEGAL_ARGS_ERR; 3899 return (rv); 3900 } 3901 3902 /* 3903 * DAR can be done if all the fh_info's are valid. 3904 */ 3905 if (allvalidfh(session, params)) { 3906 ndmp_sort_nlist_v3(session); 3907 } else { 3908 MOD_LOGV3(params, NDMP_LOG_WARNING, 3909 "Cannot do direct access recovery. " 3910 "Some 'fh_info'es are not valid.\n"); 3911 NLP_UNSET(nlp, NLPF_DIRECT); 3912 } 3913 } 3914 3915 log_rs_params_v3(session, params, nlp); 3916 } 3917 3918 return (rv); 3919 } 3920 3921 3922 /* 3923 * ndmpd_tar_restore_starter_v3 3924 * 3925 * The main restore starter function. It will start a DAR or 3926 * non-DAR recovery based on the parameters. (V3 and V4 only) 3927 * 3928 * Parameters: 3929 * params (input) - pointer to the parameters structure 3930 * 3931 * Returns: 3932 * NDMP_NO_ERR: on success 3933 * != NDMP_NO_ERR: otherwise 3934 */ 3935 int 3936 ndmpd_tar_restore_starter_v3(void *arg) 3937 { 3938 ndmpd_module_params_t *params = arg; 3939 int err; 3940 ndmpd_session_t *session; 3941 ndmp_lbr_params_t *nlp; 3942 3943 3944 session = (ndmpd_session_t *)(params->mp_daemon_cookie); 3945 *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session); 3946 ndmp_session_ref(session); 3947 3948 if (NLP_ISSET(nlp, NLPF_DIRECT)) 3949 err = ndmpd_rs_dar_tar_v3(session, params, nlp); 3950 else 3951 err = ndmpd_rs_sar_tar_v3(session, params, nlp); 3952 3953 MOD_DONE(params, err); 3954 3955 NS_DEC(nrs); 3956 /* nlp_params is allocated in start_recover() */ 3957 NDMP_FREE(nlp->nlp_params); 3958 ndmp_session_unref(session); 3959 return (err); 3960 3961 } 3962 3963 3964 /* 3965 * ndmp_tar_restore_abort_v3 3966 * 3967 * Restore abort function (V3 and V4 only) 3968 * 3969 * Parameters: 3970 * module_cookie (input) - pointer to nlp 3971 * 3972 * Returns: 3973 * 0 3974 */ 3975 int 3976 ndmpd_tar_restore_abort_v3(void *module_cookie) 3977 { 3978 ndmp_lbr_params_t *nlp; 3979 3980 nlp = (ndmp_lbr_params_t *)module_cookie; 3981 if (nlp != NULL && nlp->nlp_session != NULL) { 3982 if (nlp->nlp_session->ns_data.dd_mover.addr_type == 3983 NDMP_ADDR_TCP && 3984 nlp->nlp_session->ns_data.dd_sock != -1) { 3985 (void) close(nlp->nlp_session->ns_data.dd_sock); 3986 nlp->nlp_session->ns_data.dd_sock = -1; 3987 } 3988 nlp_event_nw(nlp->nlp_session); 3989 ndmp_stop_writer_thread(nlp->nlp_session); 3990 } 3991 3992 3993 return (0); 3994 3995 } 3996