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