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